1 ##################################################
2 # Samba4 NDR parser generator for IDL structures
3 # Copyright tridge@samba.org 2000-2003
4 # Copyright tpot@samba.org 2001
5 # Copyright jelmer@samba.org 2004-2005
6 # Portions based on idl2eth.c by Ronnie Sahlberg
7 # released under the GNU GPL
9 package Parse::Pidl::Ethereal::NDR::Parser;
12 use Parse::Pidl::Typelist;
13 use Parse::Pidl::Util qw(has_property ParseExpr);
15 use Parse::Pidl::Ethereal::Conformance qw(EmitProhibited FindDissectorParam);
17 my %ptrtype_define_mappings = (
18 "unique" => "NDR_POINTER_UNIQUE",
19 "ref" => "NDR_POINTER_REF",
20 "ptr" => "NDR_POINTER_PTR"
27 return "FT_UINT$1" if $t =~ /uint(8|16|32|64)/;
28 return "FT_INT$1" if $t =~ /int(8|16|32|64)/;
29 return "FT_UINT64", if $t eq "HYPER_T" or $t eq "NTTIME"
30 or $t eq "NTTIME_1sec" or $t eq "NTTIME_hyper" or $t eq "hyper";
37 # Determine the display base for an element
43 if (my $base = has_property($e, "display")) {
44 return "BASE_" . uc($base);
47 return "BASE_DEC", if $e->{TYPE} eq "ENUM";
48 return "BASE_DEC", if $e->{TYPE} =~ /u?int(8|16|32|64)/;
49 return "BASE_DEC", if $e->{TYPE} eq "NTTIME" or $e->{TYPE} eq "HYPER_T";
56 # Convert a IDL structure field name (e.g access_mask) to a prettier
57 # string like 'Access Mask'.
63 $field =~ s/_/ /g; # Replace underscores with spaces
64 $field =~ s/(\w+)/\u\L$1/g; # Capitalise each word
73 return "16", if has_property($e->{DATA}, "bitmap16bit");
74 return "8", if has_property($e->{DATA}, "bitmap8bit");
91 sub pidl_hdr($) { my $x = shift; $res{hdr} .= "$x\n"; }
92 sub pidl_def($) { my $x = shift; $res{def} .= "$x\n"; }
101 $tabs = substr($tabs, 0, -1);
104 #####################################################################
105 # parse the interface definitions
109 Typedef($_,$interface->{NAME}) foreach (@{$interface->{TYPEDEFS}});
110 Function($_,$interface->{NAME}) foreach (@{$interface->{FUNCTIONS}});
115 my ($e,$name,$ifname) = @_;
116 my $valsstring = "$ifname\_$name\_vals";
117 my $dissectorname = "$ifname\_dissect\_$name";
119 foreach (@{$e->{ELEMENTS}}) {
120 if (/([^=]*)=(.*)/) {
121 pidl_hdr "#define $1 $2";
125 pidl_hdr "extern const value_string $valsstring;";
126 pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
128 pidl_def "const value_string ".$valsstring."[] = {";
130 foreach (@{$e->{ELEMENTS}}) {
131 next unless (/([^=]*)=(.*)/);
132 pidl_code "{ $1, \"$2\" },";
135 pidl_def "{ 0, NULL }";
140 pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param _U_)";
143 pidl_code "offset=dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, NULL);";
144 pidl_code "return offset;";
147 register_type($name, $dissectorname, enum_ft($e), "BASE_DEC", "0", "VALS($valsstring)", enum_size($e));
152 my ($e,$name,$ifname) = @_;
153 my $dissectorname = "$ifname\_dissect\_$name";
155 register_ett("ett_$ifname\_$name");
157 pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
160 pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
163 pidl_code "proto_item *item=NULL;";
164 pidl_code "proto_tree *tree=NULL;";
167 if ($e->{ALIGN} == 8) {
168 pidl_code "guint8 flags;";
169 } elsif ($e->{ALIGN} == 4) {
170 pidl_code "guint32 flags;";
171 pidl_code "ALIGN_TO_4_BYTES;";
176 pidl_code "if(parent_tree) {";
178 pidl_code "item=proto_tree_add_item(parent_tree, hf_index, tvb, offset, $e->{ALIGN}, TRUE);";
179 pidl_code "tree=proto_item_add_subtree(item,ett_$ifname\_$name);";
183 pidl_code "offset=dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, NULL, drep, -1, &flags);";
185 foreach (@{$e->{ELEMENTS}}) {
186 next unless (/([^=]*)=(.*)/);
187 my ($en,$ev) = ($1,$2);
188 my $hf_bitname = "hf_$ifname\_$name\_$en";
189 my $filtername = "$ifname\.$name\.$en";
191 register_hf_field($hf_bitname, $en, $filtername, "FT_BOOLEAN", $e->{ALIGN} * 8, "TFS(&$en\_tfs)", $ev, "");
193 pidl_def "static const true_false_string $name\_tfs = {";
194 pidl_def " \"$name is SET\",";
195 pidl_def " \"$name is NOT SET\",";
198 pidl_code "proto_tree_add_boolean(tree, $hf_bitname, tvb, offset-$e->{ALIGN}, $e->{ALIGN}, flags);";
199 pidl_code "if (flags&$ev){";
200 pidl_code "\tproto_item_append_text(item,\"$en\");";
202 pidl_code "flags&=(~$ev);";
205 pidl_code "if(flags){";
206 pidl_code "proto_item_append_text(item, \"UNKNOWN-FLAGS\");";
209 pidl_code "return offset;";
211 register_new_type($name, $dissectorname, bitmap_ft($e), "BASE_HEX", "0", "NULL", $e->{ALIGN});
220 BASE_TYPE => "FIXME",
223 DISSECTOR => "FOOBNA"
229 my ($e,$pn,$ifname) = @_;
231 my $hf_index = "hf_$ifname\_$pn\_$e->{NAME}";
232 my $dissectorname = "$ifname\_dissect\_$ifname\_$pn\_$e->{NAME}";
234 return if (EmitProhibited($dissectorname));
236 my $type = FindType($e->{DATA_TYPE});
238 my $hf = register_hf_field($hf_index, $e->{NAME}, "$ifname.$pn.$e->{NAME}", $type->{FT_TYPE}, $type->{BASE_TYPE}, $type->{VALS}, $type->{MASK}, "");
240 pidl_code "static int";
241 pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)";
244 pidl_code "guint32 param=" . FindDissectorParam($dissectorname).";";
245 pidl_code "offset=$type->{DISSECTOR}(tvb, offset, pinfo, tree, drep, $hf, param);";
246 pidl_code "return offset;";
253 my ($fn,$ifname) = @_;
255 pidl_code "static int";
256 pidl_code "$ifname\_dissect\_$fn->{NAME}_response(tvbuff_t *tvb _U_, int offset _U_, packet_info *pinfo _U_, proto_tree *tree _U_, guint8 *drep _U_)";
259 foreach (@{$fn->{ELEMENTS}}) {
260 Element($_, $fn->{NAME}, $ifname) if (grep(/in/,@{$_->{DIRECTION}}));
262 pidl_code "return offset;";
266 pidl_code "static int";
267 pidl_code "$ifname\_dissect\_$fn->{NAME}_request(tvbuff_t *tvb _U_, int offset _U_, packet_info *pinfo _U_, proto_tree *tree _U_, guint8 *drep _U_)";
270 foreach (@{$fn->{ELEMENTS}}) {
271 Element($_, $fn->{NAME}, $ifname) if (grep(/out/,@{$_->{DIRECTION}}));
273 pidl_code "return offset;";
280 my ($e,$name,$ifname) = @_;
281 my $dissectorname = "$ifname\_dissect\_$name";
283 return if (EmitProhibited($dissectorname));
285 register_ett("ett_$ifname\_$name");
287 pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_);";
290 pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
293 pidl_code "proto_item *item = NULL;";
294 pidl_code "proto_tree *tree = NULL;";
295 pidl_code "int old_offset;";
298 pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
301 pidl_code "old_offset=offset;";
303 pidl_code "if(parent_tree){";
305 pidl_code "item=proto_tree_add_item(parent_tree, hf_index, tvb, offset, -1, TRUE);";
306 pidl_code "tree=proto_item_add_subtree(item, ett_$ifname\_$name);";
312 Element($_, $name, $ifname) foreach (@{$e->{ELEMENTS}});
315 pidl_code "proto_item_set_len(item, offset-old_offset);";
316 pidl_code "return offset;";
323 my ($e,$name,$ifname) = @_;
325 my $dissectorname = "$ifname\_dissect_union_$name";
327 register_ett("ett_$ifname\_$name");
329 pidl_code "static int";
330 pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
333 pidl_code "proto_item *item=NULL;";
334 pidl_code "proto_tree *tree=NULL;";
335 pidl_code "int old_offset;";
336 pidl_code "g$e->{SWITCH_TYPE} level;";
339 if ($e->{ALIGN} == 2) {
340 pidl_code "ALIGN_TO_2_BYTES;";
341 } elsif ($e->{ALIGN} == 4) {
342 pidl_code "ALIGN_TO_4_BYTES;";
348 pidl_code "old_offset=offset;";
349 pidl_code "if(parent_tree){";
351 pidl_code "item=proto_tree_add_text(parent_tree,tvb,offset,-1,\"$name\");";
352 pidl_code "tree=proto_item_add_subtree(item,ett_$ifname\_$name);";
357 pidl_code "offset = dissect_ndr_$e->{SWITCH_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, &level);";
359 pidl_code "switch(level) {";
360 foreach (@{$e->{ELEMENTS}}) {
361 pidl_code "$_->{CASE}:";
363 Element($_, $name, $ifname);
368 pidl_code "proto_item_set_len(item, offset-old_offset);";
369 pidl_code "return offset;";
377 my ($e,$ifname) = @_;
384 }->{$e->{DATA}->{TYPE}}->($e->{DATA}, $e->{NAME}, $ifname);
387 sub RegisterInterface($)
391 pidl_code "void proto_register_dcerpc_$x->{NAME}(void)";
395 $res{code}.=DumpHfList()."\n";
396 $res{code}.="\n".DumpEttList()."\n";
398 if (defined($x->{UUID})) {
399 # These can be changed to non-pidl_code names if the old dissectors
400 # in epan/dissctors are deleted.
402 my $name = "\"" . uc($x->{NAME}) . " (pidl)\"";
403 if (has_property($x, "helpstring")) {
404 $name = $x->{PROPERTIES}->{helpstring};
406 my $short_name = "idl_$x->{NAME}";
407 my $filter_name = "idl_$x->{NAME}";
409 pidl_code "proto_dcerpc_$x->{NAME} = proto_register_protocol($name, \"$short_name\", \"$filter_name\");";
411 pidl_code "proto_register_field_array(proto_dcerpc_$x->{NAME}, hf, array_length (hf));";
412 pidl_code "proto_register_subtree_array(ett, array_length(ett));";
414 pidl_code "proto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");";
415 pidl_code "proto_register_field_array(proto_dcerpc, hf, array_length(hf));";
416 pidl_code "proto_register_subtree_array(ett, array_length(ett));";
423 sub RegisterInterfaceHandoff($)
426 pidl_code "void proto_reg_handoff_dcerpc_$x->{NAME}(void)";
429 pidl_code "dcerpc_init_uuid(proto_dcerpc_$x->{NAME}, ett_dcerpc_$x->{NAME},";
430 pidl_code "\t&uuid_dcerpc_$x->{NAME}, ver_dcerpc_$x->{NAME},";
431 pidl_code "\t$x->{NAME}_dissectors, hf_$x->{NAME}_opnum);";
436 sub ProcessInterface($)
440 if (defined($x->{UUID})) {
441 my $if_uuid = $x->{UUID};
443 pidl_def "/* Version information */\n\n";
445 pidl_def "static e_uuid_t uuid_dcerpc_$x->{NAME} = {";
446 pidl_def "\t0x" . substr($if_uuid, 1, 8)
447 . ", 0x" . substr($if_uuid, 10, 4)
448 . ", 0x" . substr($if_uuid, 15, 4) . ",";
449 pidl_def "\t{ 0x" . substr($if_uuid, 20, 2)
450 . ", 0x" . substr($if_uuid, 22, 2)
451 . ", 0x" . substr($if_uuid, 25, 2)
452 . ", 0x" . substr($if_uuid, 27, 2)
453 . ", 0x" . substr($if_uuid, 29, 2)
454 . ", 0x" . substr($if_uuid, 31, 2)
455 . ", 0x" . substr($if_uuid, 33, 2)
456 . ", 0x" . substr($if_uuid, 35, 2) . " }";
459 pidl_def "static guint16 ver_dcerpc_$x->{NAME} = $x->{VERSION};";
465 $res{functiontable} = DumpFunctionTable($x);
467 RegisterInterface($x);
468 RegisterInterfaceHandoff($x);
471 #####################################################################
472 # Generate ethereal parser and header code
475 my($ndr,$module,$filename) = @_;
478 my $h_filename = $filename;
480 if ($h_filename =~ /(.*)\.c/) {
481 $h_filename = "$1.h";
484 %res = (code=>"",def=>"",hdr=>"");
486 pidl_hdr "/* header auto-generated by pidl */";
489 $res{headers} .= "#ifdef HAVE_CONFIG_H\n";
490 $res{headers} .= "#include \"config.h\"\n";
491 $res{headers} .= "#endif\n\n";
492 $res{headers} .= "#include <glib.h>\n";
493 $res{headers} .= "#include <string.h>\n";
494 $res{headers} .= "#include <epan/packet.h>\n\n";
496 $res{headers} .= "#include \"packet-dcerpc.h\"\n";
497 $res{headers} .= "#include \"packet-dcerpc-nt.h\"\n";
498 $res{headers} .= "#include \"packet-windows-common.h\"\n";
499 $res{headers} .= "#include \"$h_filename\"\n";
502 # Ethereal protocol registration
504 ProcessInterface($_) foreach (@$ndr);
506 $res{ett} = DumpEttDeclaration();
507 $res{hf} = DumpHfDeclaration();
509 my $parser = "/* parser auto-generated by pidl */";
510 $parser.= $res{headers};
516 my $define = "__PACKET_DCERPC_" . uc($_->{NAME}) . "_H";
517 my $header = "#ifndef $define\n#define $define\n\n".$res{hdr} . "\n#endif /* $define */\n";
519 return ($parser,$header);
522 ###############################################################################
524 ###############################################################################
537 my $res = "\tstatic gint *ett[] = {\n";
539 $res .= "\t\t&$_,\n";
545 sub DumpEttDeclaration()
547 my $res = "\n/* Ett declarations */\n";
549 $res .= "static gint $_ = -1;\n";
555 ###############################################################################
557 ###############################################################################
561 sub register_hf_field($$$$$$$$)
563 my ($index,$name,$filter_name,$ft_type,$base_type,$valsstring,$mask,$fixme) = @_;
568 FILTER => $filter_name,
570 BASE_TYPE => $base_type,
576 sub DumpHfDeclaration()
580 $res = "\n/* Header field declarations */\n";
584 $res .= "static gint $_ = -1;\n";
592 my $res = "\tstatic hf_register_info hf[] = {\n";
596 $res .= "\t{ &$_->{INDEX},
597 { \"$_->{NAME}\", \"$_->{FILTER}\", $_->{FT_TYPE}, $_->{BASE_TYPE}, $_->{VALS}, $_->{MASK}, FIXME, HFILL }},
601 return $res."\t};\n";
605 ###############################################################################
607 ###############################################################################
609 sub DumpFunctionTable($)
613 my $res = "static dcerpc_sub_dissector $if->{NAME}\_dissectors[] = {\n";
615 foreach (@{$if->{FUNCTIONS}}) {
616 $res.= "\t{ $_->{OPNUM}, \"$_->{NAME},\n";
617 $res.= "\t $if->{NAME}_dissect_$_->{NAME}_request, $if->{NAME}_dissect_$_->{NAME}_response},\n";
620 $res .= "\t{ 0, NULL, NULL, NULL },\n";