2 # Wireshark Dissector Generator for SkinnyProtocolOptimized.xml
4 # Author: Diederik de Groot <ddegroot@user.sf.net>
6 # Skinny Protocol Versions: 0 through 22
9 # xml2obj based on https://code.activestate.com/recipes/149368-xml2obj/
15 # cog.py + packet-skinny.c.in for inplace code generation
16 # See: https://nedbatchelder.com/code/cog/
19 # SPDX-License-Identifier: GPL-2.0-or-later
23 import xml
.sax
.handler
29 "callReference" : "si->callId",
30 "lineInstance": "si->lineId",
31 "passThroughPartyId" : "si->passThroughPartyId",
32 "callState" : "si->callState",
33 "callingParty" : "si->callingParty",
34 "calledParty" : "si->calledParty",
35 "mediaReceptionStatus" : "si->mediaReceptionStatus",
36 "mediaTransmissionStatus" : "si->mediaTransmissionStatus",
37 "multimediaReceptionStatus" : "si->multimediaReceptionStatus",
38 "multimediaTransmissionStatus" : "si->multimediaTransmissionStatus",
39 "multicastReceptionStatus" : "si->multicastReceptionStatus",
46 A function to converts XML data into native Python objects.
49 non_id_char
= re
.compile('[^_0-9a-zA-Z]')
51 def _name_mangle(name
):
52 return non_id_char
.sub('_',
55 class DataNode(object):
57 self
._attrs
= {} # XML attributes and child elements
58 self
.data
= None # child text data
60 self
.basemessage
= None
66 # treat single element as a list of 1
68 def __getitem__(self
, key
):
69 if isinstance(key
, str):
70 return self
._attrs
.get(key
,None)
74 def __contains__(self
, name
):
75 return name
in self
._attrs
78 return bool(self
._attrs
or self
.data
)
80 def __getattr__(self
, name
):
81 if name
.startswith('__'):
82 # need to do this for Python special methods???
83 raise AttributeError(name
)
84 return self
._attrs
.get(name
,None)
86 def _add_xml_attr(self
, name
, value
):
87 if name
in self
._attrs
:
88 # multiple attribute of the same name are represented by a list
89 children
= self
._attrs
[name
]
90 if not isinstance(children
, list):
92 self
._attrs
[name
] = children
93 children
.append(value
)
95 self
._attrs
[name
] = value
97 def _add_child(self
, name
, value
):
98 #print "adding : %s / %s to %s" %(name,value, self.__class__)
99 self
._children
.append(value
)
102 return '%s:%s' %(self
.__class
__,self
.name
)
105 return self
._attrs
.keys()
110 items
.append(('data', self
.data
))
111 return '{%s}' % ', '.join(['%s:%s' % (k
,repr(v
)) for k
,v
in items
])
113 def __setitem__(self
, key
, value
):
114 self
._attrs
[key
] = value
116 def getfieldnames(self
):
119 def get_req_resp_keys(self
, req_resp_keys
):
122 def get_req_resp_key(self
):
123 if self
.req_resp_key
== "1":
127 def declaration(self
):
129 if self
.name
not in fieldsArray
:
130 fieldsArray
[self
.name
] = '/* UNKNOWN { &hf_skinny_%s,\n {\n"%s", "skinny.%s", FT_UINT32, BASE_DEC, NULL, 0x0,\n "%s", HFILL }}, */\n' %(self
.name
, self
.name
, self
.name
, self
.comment
)
134 return self
.name
or ''
136 def incr_indent(self
):
141 for x
in range(0, indentation
):
144 def decr_indent(self
):
149 for x
in range(0, indentation
):
152 def indent_out(self
, string
):
153 return indent_str
+ string
156 class Message(DataNode
):
161 def gen_handler(self
):
162 if self
.fields
is None:
163 # skip whole message and return NULL as handler
165 return 'handle_%s' %self
.name
172 if (self
.fields
is not None):
173 ret
+= self
.indent_out("/*\n")
174 ret
+= self
.indent_out(" * Message: %s\n" %self
.name
)
175 ret
+= self
.indent_out(" * Opcode: %s\n" %self
.opcode
)
176 ret
+= self
.indent_out(" * Type: %s\n" %self
.type)
177 ret
+= self
.indent_out(" * Direction: %s\n" %self
.direction
)
178 ret
+= self
.indent_out(" * VarLength: %s\n" %self
.dynamic
)
179 ret
+= self
.indent_out(" * MsgType: %s\n" %self
.msgtype
)
181 ret
+= self
.indent_out(" * Comment: %s\n" %self
.comment
)
182 ret
+= self
.indent_out(" */\n")
183 ret
+= self
.indent_out("static void\n")
184 ret
+= self
.indent_out("handle_%s(ptvcursor_t *cursor, packet_info * pinfo _U_, skinny_conv_info_t * skinny_conv _U_)\n" %self
.name
)
185 ret
+= self
.indent_out("{\n")
188 for fields
in self
.fields
:
189 if fields
.size_lt
or fields
.size_gt
:
190 if self
.basemessage
.declared
is None or "hdr_data_length" not in self
.basemessage
.declared
:
191 ret
+= self
.indent_out("uint32_t hdr_data_length = tvb_get_letohl(ptvcursor_tvbuff(cursor), 0);\n")
192 self
.basemessage
.declared
.append("hdr_data_length")
194 if fields
.fixed
== "yes":
197 if not declarations
or fixed
== 1:
198 for fields
in self
.fields
[1:]:
199 if self
.basemessage
.declared
is None or "hdr_version" not in self
.basemessage
.declared
:
200 ret
+= self
.indent_out("uint32_t hdr_version = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n")
201 self
.basemessage
.declared
.append("hdr_version")
205 for fields
in self
.fields
:
206 fields
.get_req_resp_keys(req_resp_keys
)
207 ret
+= '%s' %fields
.declaration()
213 if self
.fields
is not None:
214 for fields
in self
.fields
:
215 ret
+= '%s' %fields
.dissect()
217 # setup request/response
218 if self
.msgtype
== "request":
219 if req_resp_keys
and req_resp_keys
[0] != '':
220 ret
+= self
.indent_out('skinny_reqrep_add_request(cursor, pinfo, skinny_conv, %s ^ %s);\n' %(self
.opcode
, req_resp_keys
[0]))
222 ret
+= self
.indent_out('skinny_reqrep_add_request(cursor, pinfo, skinny_conv, %s);\n' %(self
.opcode
))
224 if self
.msgtype
== "response":
225 if req_resp_keys
and req_resp_keys
[0] != '':
226 ret
+= self
.indent_out('skinny_reqrep_add_response(cursor, pinfo, skinny_conv, %s ^ %s);\n' %(self
.request
, req_resp_keys
[0]))
228 ret
+= self
.indent_out('skinny_reqrep_add_response(cursor, pinfo, skinny_conv, %s);\n' %(self
.request
))
235 class Fields(DataNode
):
239 def get_req_resp_keys(self
, req_resp
):
240 for field
in self
._children
:
241 key
= field
.get_req_resp_key()
242 if key
is not None and key
not in req_resp
:
245 def declaration(self
):
248 for field
in self
._children
:
249 ret
+= '%s' %(field
.declaration())
250 self
.intsize
+= field
.intsize
253 def dissect(self
, lookupguide
=""):
256 #ret += "/* [PARENT: %s, BASEMESSAGE: %s] */\n" %(self.parent.name,self.basemessage.name)
258 if ((self
.beginversion
or self
.endversion
) and (self
.beginversion
!= "0" or self
.endversion
!= "22")):
261 ret
+= self
.indent_out('if (')
262 if (self
.beginversion
and self
.beginversion
!= "0"):
263 if (not self
.endversion
or self
.endversion
== "22"):
264 ret
+= 'hdr_version >= V%s_MSG_TYPE) {\n' %self
.beginversion
266 ret
+= 'hdr_version >= V%s_MSG_TYPE && ' %self
.beginversion
267 if (self
.endversion
and self
.endversion
!= "22"):
268 ret
+= 'hdr_version <= V%s_MSG_TYPE) {\n' %self
.endversion
272 ret
+= self
.indent_out('if (hdr_data_length < %s) {\n' %self
.size_lt
)
276 ret
+= self
.indent_out('if (hdr_data_length > %s) {\n' %self
.size_gt
)
279 # generate dissection
280 for field
in self
._children
:
281 ret
+= '%s' %(field
.dissect())
285 ret
+= self
.indent_out('}\n')
289 ret
+= self
.indent_out('}\n')
293 ret
+= self
.indent_out('}\n')
297 class Integer(DataNode
):
299 DataNode
.__init
__(self
)
301 self
.endian
= "ENC_LITTLE_ENDIAN"
304 return '%s:%s' %(self
.__class
__,self
.name
)
306 def declaration(self
):
309 int_sizes
= {'uint32':4,'uint16':2,'uint8':1,'int32':4,'int16':2,'int8':1,'ipport':4}
310 if self
.endianness
== "big":
311 self
.endian
= "ENC_BIG_ENDIAN"
312 if self
.type in int_sizes
:
313 self
.intsize
= int_sizes
[self
.type]
315 print(("ERROR integer %s with type: %s, could not be found" %(self
.name
, self
.type)))
317 if self
.declare
== "yes" or self
.make_additional_info
== "yes":
318 if self
.basemessage
.declared
is None or self
.name
not in self
.basemessage
.declared
:
319 ret
+= self
.indent_out(f
'uint{self.intsize * 8}_t {self.name} = 0;\n')
320 self
.basemessage
.declared
.append(self
.name
)
323 if self
.name
not in fieldsArray
:
324 fieldsArray
[self
.name
] ='{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_UINT%d, BASE_DEC, NULL, 0x0,\n %s, HFILL }},\n' %(self
.name
, self
.comment
if (self
.comment
and self
.longcomment
) else self
.name
, self
.name
.replace("_","."), self
.intsize
* 8, '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
331 if self
.size_fieldname
:
332 if self
.basemessage
.dynamic
== "yes":
333 size
= self
.size_fieldname
340 if self
.size_fieldname
:
341 ret
+= self
.indent_out('if (%s <= %s) {%s\n' %(self
.size_fieldname
, size
, ' /* tvb integer size guard */' if debug
else ''))
343 ret
+= self
.indent_out('{\n')
345 variable
= 'counter_%d' %indentation
346 ret
+= self
.indent_out('uint32_t %s = 0;\n' %(variable))
347 if self
.size_fieldname
:
348 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [ref:%s = %%d, max:%s]", %s);\n' %(self
.name
, self
.size_fieldname
, size
, self
.size_fieldname
))
350 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [max:%s]");\n' %(self
.name
, size
))
351 ret
+= self
.indent_out('for (%s = 0; %s < %s; %s++) {\n' %(variable
, variable
, size
, variable
))
352 if self
.basemessage
.dynamic
== "no" and self
.size_fieldname
:
354 ret
+= self
.indent_out('if (%s < %s) {\n' %(variable
,self
.size_fieldname
))
357 if self
.declare
== "yes" or self
.make_additional_info
== "yes":
358 if self
.endianness
== "big":
359 if (self
.intsize
== 4):
360 ret
+= self
.indent_out('%s = tvb_get_ntohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self
.name
))
361 elif (self
.intsize
== 2):
362 ret
+= self
.indent_out('%s = tvb_get_ntohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self
.name
))
364 ret
+= self
.indent_out('%s = tvb_get_uint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self
.name
))
366 if (self
.intsize
== 4):
367 ret
+= self
.indent_out('%s = tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self
.name
))
368 elif (self
.intsize
== 2):
369 ret
+= self
.indent_out('%s = tvb_get_letohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self
.name
))
371 ret
+= self
.indent_out('%s = tvb_get_uint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self
.name
))
373 if self
.name
in si_fields
.keys():
374 if self
.endianness
== "big":
375 ret
+= self
.indent_out('%s = tvb_get_ntohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(si_fields
[self
.name
]))
377 ret
+= self
.indent_out('%s = tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(si_fields
[self
.name
]))
379 ret
+= self
.indent_out('ptvcursor_add(cursor, hf_skinny_%s, %d, %s);\n' %(self
.name
, self
.intsize
, self
.endian
))
382 if self
.basemessage
.dynamic
== "no" and self
.size_fieldname
:
384 ret
+= self
.indent_out('} else {\n')
385 ret
+= self
.indent_out(' ptvcursor_advance(cursor, %d);\n' %self
.intsize
)
386 ret
+= self
.indent_out('}\n')
388 ret
+= self
.indent_out('}\n')
390 ret
+= self
.indent_out('ptvcursor_pop_subtree(cursor); /* end for loop tree: %s */\n' %(self
.name
))
392 ret
+= self
.indent_out('ptvcursor_pop_subtree(cursor);\n')
394 if self
.size_fieldname
:
395 ret
+= self
.indent_out('} else {\n')
397 ret
+= self
.indent_out('ptvcursor_advance(cursor, (%s * %s));%s\n' %(size
, self
.intsize
, ' /* guard kicked in -> skip the rest */;' if debug
else ''))
399 ret
+= self
.indent_out('}\n')
401 if self
.make_additional_info
== "yes":
402 ret
+= self
.indent_out('srtp_add_address(pinfo, PT_UDP, &%s, %s, 0, "SKINNY", pinfo->num, false, NULL, NULL, NULL);\n' %(self
.use_param
, self
.name
))
403 ret
+= self
.indent_out('%s_str = address_to_display(NULL, &%s);\n' % (self
.use_param
, self
.use_param
))
404 ret
+= self
.indent_out('si->additionalInfo = ws_strdup_printf("%%s:%%d", %s_str, %s);\n' % (self
.use_param
, self
.name
))
405 ret
+= self
.indent_out('wmem_free(NULL, %s_str);\n' % (self
.use_param
))
409 class Enum(DataNode
):
411 DataNode
.__init
__(self
)
416 return '%s:%s' %(self
.__class
__,self
.name
)
418 def declaration(self
):
420 enum_sizes
= {'uint32':4,'uint16':2,'uint8':1}
421 if self
.type in enum_sizes
:
422 self
.intsize
= enum_sizes
[self
.type]
424 print(("ERROR enum %s with type: %s, could not be found" %(self
.name
, self
.type)))
426 if self
.declare
== "yes":
427 if self
.basemessage
.declared
is None or self
.name
not in self
.basemessage
.declared
:
428 ret
+= self
.indent_out('g%s %s = 0;\n' %(self
.type, self
.name
))
429 self
.basemessage
.declared
.append(self
.name
)
432 if self
.name
not in fieldsArray
:
433 fieldsArray
[self
.name
] ='{&hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_UINT%d, BASE_HEX | BASE_EXT_STRING, &%s_ext, 0x0,\n %s, HFILL }},\n' %(self
.name
, self
.comment
if (self
.comment
and self
.longcomment
) else self
.name
, self
.name
.replace("_","."), self
.intsize
* 8, self
.subtype
[0].upper() + self
.subtype
[1:], '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
438 endian
= "ENC_LITTLE_ENDIAN"
440 if self
.size_fieldname
:
441 if self
.basemessage
.dynamic
== "yes":
442 size
= self
.size_fieldname
448 if self
.make_additional_info
== "yes":
449 ret
+= self
.indent_out('si->additionalInfo = ws_strdup_printf("\\"%s\\"",\n')
451 ret
+= self
.indent_out('try_val_to_str_ext(\n')
453 ret
+= self
.indent_out('tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)),\n')
454 ret
+= self
.indent_out('&%s_ext\n' %(self
.subtype
[0].upper() + self
.subtype
[1:]))
456 ret
+= self
.indent_out(')\n')
458 ret
+= self
.indent_out(');\n')
460 if self
.make_additional_info_short
== "yes":
461 ret
+= self
.indent_out('si->additionalInfo = ws_strdup_printf("\\"%s\\"",\n')
463 ret
+= self
.indent_out('try_val_to_str_ext(\n')
465 ret
+= self
.indent_out('tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)),\n')
466 ret
+= self
.indent_out('&%s_short_ext\n' %(self
.subtype
[0].upper() + self
.subtype
[1:]))
468 ret
+= self
.indent_out(')\n')
470 ret
+= self
.indent_out(');\n')
473 if self
.size_fieldname
:
474 ret
+= self
.indent_out('if (%s <= %s) { /* tvb enum size guard */\n' %(self
.size_fieldname
, self
.maxsize
))
476 ret
+= self
.indent_out('{\n')
478 variable
= 'counter_%d' %indentation
479 ret
+= self
.indent_out('uint32_t %s = 0;\n' %(variable))
480 if self
.size_fieldname
:
481 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [ref: %s = %%d, max:%s]", %s);\n' %(self
.name
, self
.size_fieldname
, size
, self
.size_fieldname
))
483 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [max:%s]");\n' %(self
.name
, size
))
484 ret
+= self
.indent_out('for (%s = 0; %s < %s; %s++) {\n' %(variable
, variable
, size
, variable
))
485 if self
.basemessage
.dynamic
== "no" and self
.size_fieldname
:
487 ret
+= self
.indent_out('if (%s < %s) {\n' %(variable
,self
.size_fieldname
))
490 if self
.name
in si_fields
.keys():
491 ret
+= self
.indent_out('%s = tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(si_fields
[self
.name
]))
493 if self
.declare
== "yes":
494 if (self
.intsize
== 4):
495 ret
+= self
.indent_out('%s = tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self
.name
))
496 elif (self
.intsize
== 2):
497 ret
+= self
.indent_out('%s = tvb_get_letohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self
.name
))
499 ret
+= self
.indent_out('%s = tvb_get_uint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self
.name
))
501 ret
+= self
.indent_out('ptvcursor_add(cursor, hf_skinny_%s, %d, %s);\n' %(self
.name
, self
.intsize
, endian
))
504 if self
.basemessage
.dynamic
== "no" and self
.size_fieldname
:
506 ret
+= self
.indent_out('} else {\n')
507 ret
+= self
.indent_out(' ptvcursor_advance(cursor, 4);\n')
508 ret
+= self
.indent_out('}\n')
510 ret
+= self
.indent_out('}\n')
512 ret
+= self
.indent_out('ptvcursor_pop_subtree(cursor); /* end for loop tree: %s */\n' %(self
.name
))
514 ret
+= self
.indent_out('ptvcursor_pop_subtree(cursor);\n')
516 if self
.size_fieldname
:
517 ret
+= self
.indent_out('} else {\n')
519 ret
+= self
.indent_out('ptvcursor_advance(cursor, (%s * %s)); /* guard kicked in -> skip the rest */;\n' %(size
, self
.intsize
))
521 ret
+= self
.indent_out('}\n')
525 class String(DataNode
):
527 DataNode
.__init
__(self
)
530 return '%s:%s' %(self
.__class
__,self
.name
)
532 def get_req_resp_key(self
):
533 if self
.req_resp_key
== "1":
534 return 'wmem_str_hash(%s)' %self
.name
537 def declaration(self
):
541 if self
.size
=="VariableDirnumSize":
544 self
.intsize
= int(self
.size
)
545 elif self
.maxsize
and self
.basemessage
.dynamic
== "no":
546 self
.intsize
= int(self
.maxsize
)
548 if self
.declare
== "yes":
549 if self
.size
=="VariableDirnumSize":
550 if self
.basemessage
.declared
is None or "VariableDirnumSize" not in self
.basemessage
.declared
:
551 if self
.basemessage
.declared
is None or "hdr_version" not in self
.basemessage
.declared
:
552 #if (self.basemessage.fields is not None and len(self.basemessage.fields) == 1):
553 ret
+= self
.indent_out('uint32_t hdr_version = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n')
554 self
.basemessage
.declared
.append("hdr_version")
555 ret
+= self
.indent_out('uint32_t VariableDirnumSize = (hdr_version >= V18_MSG_TYPE) ? 25 : 24;\n')
556 self
.basemessage
.declared
.append("VariableDirnumSize")
558 # if self.basemessage.declared is None or self.name not in self.basemessage.declared:
559 # ret += self.indent_out('char *%s = NULL;\n' %self.name)
560 # self.basemessage.declared.append(self.name)
562 if self
.basemessage
.dynamic
== "yes" and not self
.subtype
== "DisplayLabel":
563 if self
.basemessage
.declared
is None or self
.name
+ '_len' not in self
.basemessage
.declared
:
564 ret
+= self
.indent_out('uint32_t %s_len = 0;\n' %self
.name
)
565 self
.basemessage
.declared
.append(self
.name
+ '_len')
568 if self
.name
not in fieldsArray
:
569 fieldsArray
[self
.name
] = '{&hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_STRING, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self
.name
, self
.comment
if (self
.comment
and self
.longcomment
) else self
.name
, self
.name
.replace("_","."), '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
575 if self
.declare
== "yes" and self
.size
!= "VariableDirnumSize":
576 ret
+= self
.indent_out('const char * %s = g_strdup(tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s));\n' %(self
.name
, self
.size
))
578 if self
.subtype
== "DisplayLabel":
579 if self
.basemessage
.dynamic
== "yes":
580 ret
+= self
.indent_out('dissect_skinny_displayLabel(cursor, pinfo, hf_skinny_%s, 0);\n' %(self
.name
))
581 elif self
.size_fieldname
:
582 ret
+= self
.indent_out('dissect_skinny_displayLabel(cursor, pinfo, hf_skinny_%s, %s);\n' %(self
.name
, self
.size_fieldname
))
584 ret
+= self
.indent_out('dissect_skinny_displayLabel(cursor, pinfo, hf_skinny_%s, %s);\n' %(self
.name
, self
.size
))
586 elif self
.basemessage
.dynamic
== "yes":
587 ret
+= self
.indent_out('%s_len = tvb_strnlen(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), -1)+1;\n' %self
.name
)
588 ret
+= self
.indent_out('if (%s_len > 1) {\n' %self
.name
)
589 if self
.name
in si_fields
.keys():
590 ret
+= self
.indent_out(' %s = g_strdup(tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s_len));\n' %(si_fields
[self
.name
], self
.name
))
591 ret
+= self
.indent_out(' ptvcursor_add(cursor, hf_skinny_%s, %s_len, ENC_ASCII);\n' %(self
.name
, self
.name
))
592 ret
+= self
.indent_out('} else {\n')
593 ret
+= self
.indent_out(' ptvcursor_advance(cursor, 1);\n')
594 ret
+= self
.indent_out('}\n')
595 elif self
.size_fieldname
:
596 if self
.name
in si_fields
.keys():
597 ret
+= self
.indent_out('%s = g_strdup(tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s));\n' %(si_fields
[self
.name
], self
.size_fieldname
))
598 ret
+= self
.indent_out('ptvcursor_add(cursor, hf_skinny_%s, %s, ENC_ASCII);\n' %(self
.name
, self
.size_fieldname
))
600 if self
.name
in si_fields
.keys():
601 ret
+= self
.indent_out('%s = g_strdup(tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s));\n' %(si_fields
[self
.name
], self
.size
))
602 if self
.make_additional_info
== "yes":
603 ret
+= self
.indent_out('uint32_t %s_len;\n' %(self
.name
))
604 if self
.size
=="VariableDirnumSize":
605 ret
+= self
.indent_out('%s_len = tvb_strnlen(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), VariableDirnumSize)+1;\n' %(self
.name
))
607 ret
+= self
.indent_out('%s_len = tvb_strnlen(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), 24)+1;\n' %(self
.name
))
608 ret
+= self
.indent_out('if (%s_len > 1) {\n' %(self
.name
))
610 ret
+= self
.indent_out('si->additionalInfo = ws_strdup_printf("\\"%%s\\"", tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s_len));\n' %(self
.name
))
612 ret
+= self
.indent_out('}\n')
614 ret
+= self
.indent_out('ptvcursor_add(cursor, hf_skinny_%s, %s, ENC_ASCII);\n' %(self
.name
, self
.size
))
618 class Ether(DataNode
):
620 DataNode
.__init
__(self
)
623 return '%s:%s' %(self
.__class
__,self
.name
)
625 def declaration(self
):
629 self
.intsize
= int(self
.size
)
630 elif self
.maxsize
and self
.basemessage
.dynamic
== "no":
631 self
.intsize
= int(self
.maxsize
)
633 if self
.declare
== "yes":
634 if self
.basemessage
.declared
is None or self
.name
not in self
.basemessage
.declared
:
635 ret
+= self
.indent_out('uint32_t %s = 0;\n' %self
.name
)
636 self
.basemessage
.declared
.append(self
.name
)
638 if self
.basemessage
.dynamic
== "yes":
639 if self
.basemessage
.declared
is None or self
.name
+ '_len' not in self
.basemessage
.declared
:
640 ret
+= self
.indent_out('uint32_t %s_len = 0;\n' %self
.name
)
641 self
.basemessage
.declared
.append(self
.name
+ '_len')
644 if self
.name
not in fieldsArray
:
645 fieldsArray
[self
.name
] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_ETHER, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self
.name
, self
.comment
if (self
.comment
and self
.longcomment
) else self
.name
, self
.name
.replace("_","."), '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
651 if self
.basemessage
.dynamic
== "yes":
652 ret
+= self
.indent_out('%s_len = tvb_strnlen(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), -1)+1;\n' %self
.name
)
653 ret
+= self
.indent_out('if (%s_len > 1) {\n' %self
.name
)
654 ret
+= self
.indent_out(' ptvcursor_add(cursor, hf_skinny_%s, 6, ENC_NA);\n' %(self
.name
))
655 ret
+= self
.indent_out(' ptvcursor_advance(cursor, %s_len - 6);\n' %(self
.name
))
656 ret
+= self
.indent_out('} else {\n')
657 ret
+= self
.indent_out(' ptvcursor_advance(cursor, 1);\n')
658 ret
+= self
.indent_out('}\n')
659 elif self
.size_fieldname
:
660 ret
+= self
.indent_out('ptvcursor_add(cursor, hf_skinny_%s, 6, ENC_NA);\n' %(self
.name
))
661 ret
+= self
.indent_out('ptvcursor_advance(cursor, %s - 6);\n' %(self
.size_fieldname
))
663 ret
+= self
.indent_out('ptvcursor_add(cursor, hf_skinny_%s, 6, ENC_NA);\n' %(self
.name
))
664 ret
+= self
.indent_out('ptvcursor_advance(cursor, %s - 6);\n' %(self
.size
))
667 class BitField(DataNode
):
669 DataNode
.__init
__(self
)
672 return '%s:%s' %(self
.__class
__,self
.name
)
674 def declaration(self
):
677 int_sizes
= {'uint32':4,'uint16':2,'uint8':1,'int32':4,'int16':2,'int8':1}
679 if self
.size
in int_sizes
:
680 self
.intsize
= int_sizes
[self
.size
]
682 for entries
in self
.entries
:
683 for entry
in entries
.entry
:
684 if entry
.name
not in fieldsArray
:
685 fieldsArray
[entry
.name
] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_BOOLEAN, %d, TFS(&tfs_yes_no), %s,\n %s, HFILL }},\n' %(entry
.name
, entry
.text
, entry
.name
.replace("_","."), self
.intsize
* 8, entry
.value
, '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
691 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s");\n' %(self
.name
))
692 for entries
in self
.entries
:
693 for entry
in entries
.entry
:
694 ret
+= self
.indent_out('ptvcursor_add_no_advance(cursor, hf_skinny_%s, %d, ENC_LITTLE_ENDIAN);\n' %(entry
.name
, self
.intsize
))
695 ret
+= self
.indent_out('ptvcursor_advance(cursor, %d);\n' %(self
.intsize
))
696 ret
+= self
.indent_out('ptvcursor_pop_subtree(cursor); /* end bitfield: %s */\n' %(self
.name
))
703 DataNode
.__init
__(self
)
705 if self
.type == "ipv6":
709 return '%s:%s' %(self
.__class
__,self
.name
)
711 def declaration(self
):
713 if self
.name
not in fieldsArray
:
714 if self
.type == "ipv4":
715 fieldsArray
[self
.name
] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_IPv4, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self
.name
, self
.comment
if (self
.comment
and self
.longcomment
) else self
.name
, self
.name
.replace("_","."), '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
717 fieldsArray
[self
.name
] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_IPv6, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self
.name
, self
.comment
if (self
.comment
and self
.longcomment
) else self
.name
, self
.name
.replace("_","."), '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
721 if self
.type == "ipv4":
722 return self
.indent_out('ptvcursor_add(cursor, hf_skinny_%s, 4, ENC_BIG_ENDIAN);\n' %self
.name
)
724 return self
.indent_out('ptvcursor_add(cursor, hf_skinny_%s, 16, ENC_NA);\n' %self
.name
)
726 class Ipv4or6(DataNode
):
728 DataNode
.__init
__(self
)
730 if self
.endianness
is None:
734 return '%s:%s' %(self
.__class
__,self
.name
)
736 def declaration(self
):
740 name
= self
.name
+ '_ipv4'
741 if name
not in fieldsArray
:
742 fieldsArray
[name
] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_IPv4, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(name
, self
.name
+ ' IPv4 Address', name
.replace("_","."), '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
743 name
= self
.name
+ '_ipv6'
744 if name
not in fieldsArray
:
745 fieldsArray
[name
] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_IPv6, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(name
, self
.name
+ ' IPv6 Address', name
.replace("_","."), '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
746 if self
.make_additional_info
== "yes":
747 if self
.basemessage
.declared
is None or self
.name
not in self
.basemessage
.declared
:
748 ret
+= self
.indent_out('address %s;\n' %(self
.name
))
749 ret
+= self
.indent_out('char *%s_str = NULL;\n' %(self
.name
))
750 self
.basemessage
.declared
.append(self
.name
)
756 if self
.make_additional_info
== "yes":
757 ret
+= self
.indent_out('read_skinny_ipv4or6(cursor, &%s);\n' %(self
.name
))
758 ret
+= self
.indent_out('dissect_skinny_ipv4or6(cursor, hf_skinny_%s_ipv4, hf_skinny_%s_ipv6);\n' %(self
.name
, self
.name
))
763 DataNode
.__init
__(self
)
767 return '%s:%s' %(self
.__class
__,self
.name
)
769 def declaration(self
):
773 self
.intsize
= int(self
.size
)
775 self
.intsize
= int(self
.maxsize
)
777 if self
.name
not in fieldsArray
:
778 fieldsArray
[self
.name
] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_STRING, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self
.name
, self
.comment
if (self
.comment
and self
.longcomment
) else self
.name
, self
.name
.replace("_","."), '"' + self
.longcomment
+ '"' if self
.longcomment
else '"' + self
.comment
+ '"' if self
.comment
else 'NULL')
783 if self
.size_fieldname
:
784 ret
+= self
.indent_out('dissect_skinny_xml(cursor, hf_skinny_%s, pinfo, %s, %d);\n' %(self
.name
, self
.size_fieldname
, self
.intsize
))
786 ret
+= self
.indent_out('dissect_skinny_xml(cursor, hf_skinny_%s, pinfo, 0, %d);\n' %(self
.name
, self
.intsize
))
789 class Code(DataNode
):
791 DataNode
.__init
__(self
)
794 return '%s:%s' %(self
.__class
__,self
.name
)
796 def declaration(self
):
801 if self
.type == "calling_and_called_party":
802 params
= self
.use_param
.split(',')
803 ret
+= self
.indent_out('if (si->%s && si->%s) {\n' %(params
[0], params
[1]))
805 ret
+= self
.indent_out('si->additionalInfo = ws_strdup_printf("\\"%%s -> %%s\\"", si->%s, si->%s);\n' %(params
[0], params
[1]))
807 ret
+= self
.indent_out('}\n')
810 class Struct(DataNode
):
812 return '// Struct : %s / %s / %s / %s\n' %(self
.name
, self
.size
, self
.field_sizename
, self
.maxsize
)
814 def declaration(self
):
817 if (self
.fields
is not None and len(self
.fields
)):
818 if (len(self
.fields
) > 1):
819 if self
.basemessage
.declared
is None or "hdr_version" not in self
.basemessage
.declared
:
820 ret
+= self
.indent_out("uint32_t hdr_version = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n")
821 self
.basemessage
.declared
.append("hdr_version")
822 for fields
in self
.fields
:
823 ret
+= '%s' %fields
.declaration()
824 #self.intsize += fields.intsize
825 self
.intsize
= fields
.intsize
830 variable
= 'counter_%d' %indentation
833 if self
.size_fieldname
:
834 #if self.basemessage.dynamic == "yes":
835 # size = self.size_fieldname
837 # size = self.maxsize
843 if self
.size_fieldname
:
844 ret
+= self
.indent_out('if (%s <= %s) {%s\n' %(self
.size_fieldname
, size
, ' /* tvb struct size guard */' if debug
else ''))
846 ret
+= self
.indent_out('{\n')
849 ret
+= self
.indent_out('/* start struct : %s / size: %d */\n' %(self
.name
, self
.intsize
))
850 ret
+= self
.indent_out('uint32_t %s = 0;\n' %(variable))
851 if self
.size_fieldname
:
852 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [ref:%s = %%d, max:%s]", %s);\n' %(self
.name
, self
.size_fieldname
, self
.maxsize
, self
.size_fieldname
))
854 ret
+= self
.indent_out('if (%s && tvb_get_letohl(ptvcursor_tvbuff(cursor), 0) + 8 >= ptvcursor_current_offset(cursor) + (%s * %s) && %s <= %s) {%s\n' %(self
.size_fieldname
, self
.size_fieldname
, self
.intsize
, self
.size_fieldname
, self
.maxsize
, '/* tvb counter size guard */' if debug
else ''))
856 ret
+= self
.indent_out('if (%s && tvb_get_letohl(ptvcursor_tvbuff(cursor), 0) + 8 >= ptvcursor_current_offset(cursor) + (%s * %s)) {%s\n' %(self
.size_fieldname
, self
.size_fieldname
, self
.intsize
, '/* tvb counter size guard */' if debug
else ''))
859 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [max:%s]");\n' %(self
.name
, size
))
861 ret
+= self
.indent_out('for (%s = 0; %s < %s; %s++) {\n' %(variable
, variable
, size
, variable
))
862 if self
.basemessage
.dynamic
== "no" and self
.size_fieldname
:
864 ret
+= self
.indent_out('if (%s < %s) {\n' %(variable
,self
.size_fieldname
))
868 ret
+= self
.indent_out('{ /* start struct : %s / size: %d */\n' %(self
.name
, self
.intsize
))
870 ret
+= self
.indent_out('{\n')
872 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s");\n' %(self
.name
))
875 if self
.size_fieldname
:
876 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [%%d / %%d]", %s + 1, %s);\n' %(self
.name
, variable
, self
.size_fieldname
))
878 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [%%d / %%d]", %s + 1, %s);\n' %(self
.name
, variable
, size
))
880 if (self
.fields
is not None and len(self
.fields
)):
881 for fields
in self
.fields
:
882 ret
+= '%s' %fields
.dissect()
884 if self
.basemessage
.dynamic
== "no" and self
.size_fieldname
:
886 ret
+= self
.indent_out('} else {\n')
887 ret
+= self
.indent_out(' ptvcursor_advance(cursor, %d);\n' %(self
.intsize
))
888 ret
+= self
.indent_out('}\n')
891 ret
+= self
.indent_out('ptvcursor_pop_subtree(cursor);\n')
894 ret
+= self
.indent_out('} /* end for loop tree: %s */\n' %self
.name
)
896 ret
+= self
.indent_out('}\n')
897 if self
.size_fieldname
:
899 ret
+= self
.indent_out('} /* end counter tvb size guard */\n' if debug
else '}\n')
901 ret
+= self
.indent_out('ptvcursor_pop_subtree(cursor);\n')
903 ret
+= self
.indent_out('/* end struct: %s */\n' %self
.name
)
905 if self
.size_fieldname
:
906 ret
+= self
.indent_out('} else {\n')
908 ret
+= self
.indent_out('ptvcursor_advance(cursor, (%s * %s));%s\n' %(self
.size_fieldname
, self
.intsize
, ' /* guard kicked in -> skip the rest */' if debug
else ''))
910 ret
+= self
.indent_out('} /* end struct size guard */\n' if debug
else '}\n')
914 class Union(DataNode
):
916 return '%s:%s' %(self
.__class
__,self
.name
)
918 def declaration(self
):
921 if (self
.fields
is not None and len(self
.fields
)):
922 if (len(self
.fields
) > 1):
923 if self
.basemessage
.declared
is None or "hdr_version" not in self
.basemessage
.declared
:
924 ret
+= self
.indent_out("uint32_t hdr_version = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n")
925 self
.basemessage
.declared
.append("hdr_version")
926 for fields
in self
.fields
:
927 ret
+= '%s' %fields
.declaration()
928 previous_lookup_eq
= fields
._children
[0].lookup_eq
929 previous_lookup_le
= fields
._children
[0].lookup_le
930 previous_lookup_ge
= fields
._children
[0].lookup_ge
931 self
.runningtotal
= 0
932 for field
in fields
._children
:
933 if previous_lookup_eq
!= field
.lookup_eq
or previous_lookup_le
!= field
.lookup_le
or previous_lookup_ge
== field
.lookup_ge
:
934 previous_lookup_eq
= field
.lookup_eq
935 previous_lookup_le
= field
.lookup_le
936 previous_lookup_ge
= field
.lookup_ge
937 self
.runningtotal
= 0
939 self
.runningtotal
+= field
.intsize
940 if self
.runningtotal
> self
.maxsize
:
941 self
.maxsize
= self
.runningtotal
943 self
.intsize
= self
.maxsize
949 ifblock
= self
.indent_out('if')
950 #ret += self.indent_out('/* Union : %s / maxsize: %s */\n' %(self.name, self.maxsize))
952 if (self
.fields
is not None and len(self
.fields
)):
953 for fields
in self
.fields
:
954 for field
in fields
._children
:
955 if self
.lookup_guide
and (field
.lookup_ge
or field
.lookup_le
or field
.lookup_eq
):
956 lookupguide
= self
.lookup_guide
959 if field
.lookup_ge
and field
.lookup_le
:
960 ret
+= '%s (%s >= %s && %s <= %s)' %(ifblock
, lookupguide
, field
.lookup_ge
.upper(), lookupguide
, field
.lookup_le
.upper())
961 subtree_text
= "%s <= %s <= %s" %(field
.lookup_ge
, lookupguide
, field
.lookup_le
)
962 elif field
.lookup_ge
:
963 ret
+= '%s (%s >= %s)' %(ifblock
, lookupguide
, field
.lookup_ge
.upper())
964 subtree_text
= "%s >= %s" %(lookupguide
, field
.lookup_ge
)
965 elif field
.lookup_le
:
966 ret
+= '%s (%s <= %s)' %(ifblock
, lookupguide
, field
.lookup_le
.upper())
967 subtree_text
= "%s <= %s" %(lookupguide
, field
.lookup_le
)
968 elif field
.lookup_eq
:
969 if field
.lookup_eq
== "*":
971 subtree_text
= "any %s" %(lookupguide)
972 elif field
.lookup_eq
== "skip":
975 ret
+= '%s (%s == %s)' %(ifblock
, lookupguide
, field
.lookup_eq
.upper())
976 subtree_text
= "%s is %s" %(lookupguide
, field
.lookup_eq
)
978 ret
+= self
.indent_out(' {\n')
981 ret
+= self
.indent_out('/* start union : %s / maxsize: %s */\n' %(self
.name
, self
.maxsize
))
985 ret
+= self
.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s");\n' %subtree
_text
)
986 ret
+= '%s' %field
.dissect()
987 ret
+= self
.indent_out('ptvcursor_pop_subtree(cursor);\n')
989 currsize
+= field
.intsize
992 if (self
.maxsize
- currsize
) > 0:
993 ret
+= self
.indent_out('ptvcursor_advance(cursor, %d);\n' %(self
.maxsize
- currsize
))
998 ret
+= self
.indent_out('}')
1001 ret
+= '/* ERROR %s, missing lookup_guide */' %field
.dissect()
1006 class TreeBuilder(xml
.sax
.handler
.ContentHandler
):
1009 self
.root
= DataNode()
1010 self
.previous
= self
.root
1011 self
.current
= self
.root
1012 self
.basemessage
= None
1013 self
.text_parts
= []
1014 def startElement(self
, name
, attrs
):
1015 objecttype
= {"message": Message(), "fields": Fields(), "enum" : Enum(), "bitfield" : BitField(), "struct": Struct(), "union": Union(), "integer": Integer(), "string": String(), "ether": Ether(), "ip": Ip(), "ipv4or6": Ipv4or6(), "xml": XML(), "code": Code()}
1016 self
.previous
= self
.current
1017 self
.stack
.append((self
.current
, self
.text_parts
))
1018 if name
in objecttype
.keys():
1019 self
.current
= objecttype
[name
]
1021 self
.current
= DataNode()
1022 if name
== "message":
1023 self
.basemessage
= self
.current
1024 self
.text_parts
= []
1026 self
.current
.parent
= self
.previous
1027 self
.current
.basemessage
= self
.basemessage
1028 # xml attributes --> python attributes
1029 for k
, v
in list(attrs
.items()):
1030 self
.current
._add
_xml
_attr
(_name_mangle(k
), v
)
1032 def endElement(self
, name
):
1033 text
= ''.join(self
.text_parts
).strip()
1035 self
.current
.data
= text
1036 if self
.current
._attrs
:
1039 # a text only node is simply represented by the string
1041 self
.current
, self
.text_parts
= self
.stack
.pop()
1042 self
.current
._add
_xml
_attr
(_name_mangle(name
), obj
)
1043 self
.current
._add
_child
(_name_mangle(name
), obj
)
1044 def characters(self
, content
):
1045 self
.text_parts
.append(content
)
1047 builder
= TreeBuilder()
1048 xml
.sax
.parse(src
, builder
)
1049 return list(builder
.root
._attrs
.values())[0]
1051 # skinny = xml2obj('SkinnyProtocolOptimized.xml')
1052 # for message in skinny.message:
1053 # print '%s' %message.dissect()
1055 #if __name__ == '__main__':
1057 # print(timeit.timeit("generateMessageDissectors()", setup="from __main__ import generateMessageDissectors"))
1060 #skinny = xml2obj('SkinnyProtocolOptimized.xml')
1061 #for message in skinny.message:
1065 #for key,value in fieldsArray.items():
1066 # print "%s : %s" %(key,value)
1067 #print '%r\n' %fieldsArray
1069 #skinny = xml2obj('SkinnyProtocolOptimized.xml')
1070 #for message in skinny.message:
1071 # print message.declaration()