1 /******************************************************************************************************/
4 * Copyright (c) 2003 by Matthijs Melchior <matthijs.melchior@xs4all.nl>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1999 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 /**************************************************************************
31 * This plugin will dissect BER encoded ASN.1 messages in UDP packets or in
32 * a TCP stream. It relies on wireshark to do defragmentation and re-assembly
33 * to construct complete messages.
35 * To produce packet display with good annotations it needs to know about
36 * the ASN.1 definition of the messages it reads. To this end, it can read
37 * the 'type-table' output file of the ASN.1 to C compiler 'snacc'. The
38 * version I have used came from: http://packages.debian.org/testing/devel/snacc.html
40 * The type-table files produced by snacc are themselves ASN.1 BER encoded
41 * data structures. Knowledge of the structure of that table, as specified
42 * in the tbl.asn1 file in the snacc distribution, is hand coded in some
43 * functions in this plugin.
45 * This also means that this dissector can show its own specification.
46 * On a unix machine, do the following to see this in action:
48 * - snacc -u /usr/include/snacc/asn1/asn-useful.asn1 -T tbl.tt /usr/include/snacc/asn1/tbl.asn1
49 * - od -Ax -tx1 tbl.tt | text2pcap -T 801,801 - tbl.tt.pcap
50 * - wireshark tbl.tt.pcap
51 * GUI: Edit->Preferences->Protocols->ASN1
52 * type table file: /tmp/tbl.tt
55 * you can now browse the tbl.tt definition.
70 #include <glib/gprintf.h>
72 #include <wsutil/report_err.h>
73 #include <wsutil/file_util.h>
75 #include <epan/packet.h>
76 #include <epan/exceptions.h>
77 #include <epan/addr_resolv.h>
78 #include <epan/prefs.h>
79 #include <epan/filesystem.h>
80 #include <epan/dissectors/packet-tcp.h>
81 #include <epan/oids.h>
82 #include <epan/emem.h>
83 #include <plugins/asn1/asn1.h>
85 #ifdef DISSECTOR_WITH_GUI
89 #include <epan/ipproto.h>
96 /* Define default ports */
98 #define TCP_PORT_ASN1 0
99 #define UDP_PORT_ASN1 0
100 #define SCTP_PORT_ASN1 0
102 void proto_reg_handoff_asn1(void);
104 /* Define the asn1 proto */
106 static int proto_asn1
= -1;
108 /* Define the tree for asn1*/
110 static int ett_asn1
= -1;
112 #define MAXPDU 64 /* max # PDU's in one packet */
113 static int ett_pdu
[MAXPDU
];
115 #define MAX_NEST 32 /* max nesting level for ASN.1 elements */
116 static int ett_seq
[MAX_NEST
];
119 * Global variables associated with the preferences for asn1
123 static guint global_tcp_port_asn1
= TCP_PORT_ASN1
;
124 static guint global_udp_port_asn1
= UDP_PORT_ASN1
;
125 static guint global_sctp_port_asn1
= SCTP_PORT_ASN1
;
127 static range_t
*global_tcp_ports_asn1
;
128 static range_t
*global_udp_ports_asn1
;
129 static range_t
*global_sctp_ports_asn1
;
130 #endif /* JUST_ONE_PORT */
132 static gboolean asn1_desegment
= TRUE
;
133 static const char *asn1_filename
= NULL
;
134 static char *old_default_asn1_filename
= NULL
;
135 #define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
137 #define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
138 static char *bad_separator_old_default_asn1_filename
= NULL
;
140 static char *current_asn1
= NULL
;
141 static const char *asn1_pduname
= NULL
;
142 static char *current_pduname
= NULL
;
143 static gboolean asn1_debug
= FALSE
;
144 static guint first_pdu_offset
= 0;
145 static gboolean asn1_message_win
= FALSE
;
146 static gboolean asn1_verbose
= FALSE
; /* change to TRUE for logging the startup phase */
147 static gboolean asn1_full
= FALSE
; /* show full names */
148 static guint type_recursion_level
= 1; /* eliminate 1 level of references */
149 static char *asn1_logfile
= NULL
;
151 #define ASN1LOGFILE "wireshark.log"
153 /* PDU counter, for correlation between GUI display and log file in debug mode */
154 static int pcount
= 0;
156 static tvbuff_t
*asn1_desc
; /* the PDU description */
157 static GNode
*asn1_nodes
= NULL
; /* GNode tree pointing to every asn1 data element */
158 static GNode
*data_nodes
= NULL
; /* GNode tree describing the syntax data */
159 static GNode
*PDUtree
= NULL
; /* GNode tree describing the expected PDU format */
161 static guint PDUerrcount
= 0; /* count of parse errors in one ASN.1 message */
163 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
166 static char pabbrev
[] = "asn1"; /* field prefix */
168 static char fieldname
[512]; /* for constructing full names */
169 static guint pabbrev_pdu_len
; /* length initial part of fieldname with 'abbrev.asn1pdu.' */
172 * Text strings describing the standard, universal, ASN.1 names.
175 #define ASN1_EOI 4 /* this is in the class number space... */
176 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
178 static const char tag_class
[] = "UACPX";
180 static const char *asn1_cls
[] = { "Universal", "Application", "Context", "Private" };
182 static const char *asn1_con
[] = { "Primitive", "Constructed" };
184 static const char *asn1_tag
[] = {
185 /* 0 */ "EOC", "Boolean", "Integer", "BitString",
186 /* 4 */ "OctetString", "Null", "ObjectIdentifier", "ObjectDescriptor",
187 /* 8 */ "External", "Real", "Enumerated", "tag11",
188 /* 12 */ "UTF8String", "tag13", "tag14", "tag15",
189 /* 16 */ "Sequence", "Set", "NumericString", "PrintableString",
190 /* 20 */ "TeletexString", "VideotexString", "IA5String", "UTCTime",
191 /* 24 */ "GeneralTime", "GraphicString", "ISO646String", "GeneralString",
192 /* 28 */ "UniversalString", "tag29", "BMPString", "Long tag prefix"
193 /* TT61 == TELETEX */
194 /* ISO646 == VISIBLE*/
197 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
198 static gboolean tbl_types_verified
= FALSE
;
200 typedef enum { /* copied from .../snacc/c-lib/boot/tbl.h */
209 TBL__SIMPLE
= 8, /* values smaller than this can have a value */
217 TBL_SEQUENCEOF_start
, /* to mark potential sequence-of repeat */
218 TBL_TYPEREF_nopop
, /* typeref has been handled immediately */
219 TBL_CHOICE_done
, /* choice is finished */
220 TBL_reserved
, /* this sequence has been visited */
221 TBL_CHOICE_immediate
, /* immediate choice, no next */
223 TBL_INVALID
/* incorrect value for this enum */
226 /* Universal tags mapped to snacc ASN.1 table types */
227 static int asn1_uni_type
[] = {
228 /* 0 */ TBL_INVALID
, TBL_BOOLEAN
, TBL_INTEGER
, TBL_BITSTRING
,
229 /* 4 */ TBL_OCTETSTRING
, TBL_NULL
, TBL_OID
, TBL_INVALID
,
230 /* 8 */ TBL_INVALID
, TBL_REAL
, TBL_ENUMERATED
, TBL_INVALID
,
231 /* 12 */ TBL_OCTETSTRING
, TBL_INVALID
, TBL_INVALID
, TBL_INVALID
,
232 /* 16 */ TBL_SEQUENCE
, TBL_SET
, TBL_OCTETSTRING
, TBL_OCTETSTRING
,
233 /* 20 */ TBL_OCTETSTRING
, TBL_OCTETSTRING
, TBL_OCTETSTRING
, TBL_OCTETSTRING
,
234 /* 24 */ TBL_OCTETSTRING
, TBL_OCTETSTRING
, TBL_OCTETSTRING
, TBL_OCTETSTRING
,
235 /* 28 */ TBL_OCTETSTRING
, TBL_INVALID
, TBL_OCTETSTRING
, TBL_INVALID
,
239 #define TBL_REPEAT 0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
240 #define TBL_REPEAT_choice 0x00020000 /* repeating a choice */
241 #define TBL_CHOICE_made 0x00040000 /* This was a choice entry */
242 #define TBL_SEQUENCE_done 0x00080000 /* children have been processed */
243 #define TBL_CHOICE_repeat 0x00100000 /* a repeating choice */
244 #define TBL_REFERENCE 0x00200000 /* This entry is result of a typeref */
245 #define TBL_REFERENCE_pop 0x00400000 /* reference handled, do pop i.s.o. next */
246 #define TBL_SEQUENCE_choice 0x00800000 /* this sequence is a first of a repeating choice */
247 #define TBL_CONSTRUCTED 0x01000000 /* unexpectedly constructed entry */
248 #define TBL_TYPEmask 0x0000FFFF /* Mask just the type */
250 /* XXX - Should we use val_to_str here? */
251 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
253 /* text tables for debugging and GUI */
254 static const char *tbl_types
[] = {
255 /* 0 */ "tbl-boolean",
256 /* 1 */ "tbl-integer",
257 /* 2 */ "tbl-bitstring",
258 /* 2 */ "tbl-octetstring",
262 /* 7 */ "tbl-enumerated",
263 /* 8 */ "tbl-sequence",
265 /* 10 */ "tbl-sequenceof",
266 /* 11 */ "tbl-setof",
267 /* 12 */ "tbl-choice",
268 /* 13 */ "tbl-typeref",
270 /* 14 */ "tbl-sequenceof-start",
271 /* 15 */ "tbl-typeref-nopop",
272 /* 16 */ "tbl-choice-done",
273 /* 17 */ "tbl-reserved",
274 /* 18 */ "tbl-choice-immediate",
276 /* 19 */ "tbl-invalid",
278 static const char *tbl_types_asn1
[] = {
282 /* 2 */ "OCTET STRING",
284 /* 5 */ "OBJECT IDENTIFIER",
286 /* 7 */ "ENUMERATED",
289 /* 10 */ "SEQUENCE OF",
294 /* 14 */ "start-SEQUENCE OF",
295 /* 15 */ "TYPEREF nopop",
296 /* 16 */ "CHOICE done",
298 /* 18 */ "CHOICE immediate",
300 /* 19 */ "INVALID entry",
302 /* conversion from snacc type to appropriate wireshark type */
303 static enum ftenum tbl_types_wireshark
[] = {
304 /* 0 */ FT_BOOLEAN
, /* TBL_BOOLEAN */
305 /* 1 */ FT_UINT32
, /* TBL_INTEGER */
306 /* 2 */ FT_UINT32
, /* TBL_BITSTRING */
307 /* 2 */ FT_STRINGZ
, /* TBL_OCTETSTRING */
308 /* 4 */ FT_NONE
, /* TBL_NULL */
309 /* 5 */ FT_BYTES
, /* TBL_OID */
310 /* 6 */ FT_DOUBLE
, /* TBL_REAL */
311 /* 7 */ FT_UINT32
, /* TBL_ENUMERATED */
312 /* 8 */ FT_NONE
, /* TBL_SEQUENCE */
313 /* 9 */ FT_NONE
, /* TBL_SET */
314 /* 10 */ FT_NONE
, /* TBL_SEQUENCEOF */
315 /* 11 */ FT_NONE
, /* TBL_SETOF */
316 /* 12 */ FT_NONE
, /* TBL_CHOICE */
317 /* 13 */ FT_NONE
, /* TBL_TYPEREF */
319 /* 14 */ FT_NONE
, /* TBL_SEQUENCEOF_start */
320 /* 15 */ FT_NONE
, /* TBL_TYPEREF_nopop */
321 /* 16 */ FT_NONE
, /* TBL_CHOICE_done */
322 /* 17 */ FT_NONE
, /* TBL_reserved */
323 /* 18 */ FT_NONE
, /* TBL_CHOICE_immediate */
325 /* 19 */ FT_NONE
, /* TBL_INVALID */
328 /* conversion from snacc type to appropriate wireshark display type */
329 static guint tbl_display_wireshark
[] = {
330 /* 0 */ BASE_DEC
, /* TBL_BOOLEAN */
331 /* 1 */ BASE_DEC_HEX
, /* TBL_INTEGER */
332 /* 2 */ BASE_HEX
, /* TBL_BITSTRING */
333 /* 2 */ BASE_NONE
, /* TBL_OCTETSTRING */
334 /* 4 */ BASE_NONE
, /* TBL_NULL */
335 /* 5 */ BASE_DEC
, /* TBL_OID */
336 /* 6 */ BASE_DEC
, /* TBL_REAL */
337 /* 7 */ BASE_DEC
, /* TBL_ENUMERATED */
338 /* 8 */ BASE_NONE
, /* TBL_SEQUENCE */
339 /* 9 */ BASE_NONE
, /* TBL_SET */
340 /* 10 */ BASE_NONE
, /* TBL_SEQUENCEOF */
341 /* 11 */ BASE_NONE
, /* TBL_SETOF */
342 /* 12 */ BASE_NONE
, /* TBL_CHOICE */
343 /* 13 */ BASE_NONE
, /* TBL_TYPEREF */
345 /* 14 */ BASE_NONE
, /* TBL_SEQUENCEOF_start */
346 /* 15 */ BASE_NONE
, /* TBL_TYPEREF_nopop */
347 /* 16 */ BASE_NONE
, /* TBL_CHOICE_done */
348 /* 17 */ BASE_NONE
, /* TBL_reserved */
349 /* 18 */ BASE_NONE
, /* TBL_CHOICE_immediate */
351 /* 19 */ BASE_NONE
, /* TBL_INVALID */
354 static const char *tbl_types_wireshark_txt
[] = {
355 /* 0 */ "FT_BOOLEAN", /* TBL_BOOLEAN */
356 /* 1 */ "FT_UINT32", /* TBL_INTEGER */
357 /* 2 */ "FT_UINT32", /* TBL_BITSTRING */
358 /* 2 */ "FT_STRINGZ", /* TBL_OCTETSTRING */
359 /* 4 */ "FT_NONE", /* TBL_NULL */
360 /* 5 */ "FT_BYTES", /* TBL_OID */
361 /* 6 */ "FT_DOUBLE", /* TBL_REAL */
362 /* 7 */ "FT_UINT32", /* TBL_ENUMERATED */
363 /* 8 */ "FT_NONE", /* TBL_SEQUENCE */
364 /* 9 */ "FT_NONE", /* TBL_SET */
365 /* 10 */ "FT_NONE", /* TBL_SEQUENCEOF */
366 /* 11 */ "FT_NONE", /* TBL_SETOF */
367 /* 12 */ "FT_NONE", /* TBL_CHOICE */
368 /* 13 */ "FT_NONE", /* TBL_TYPEREF */
370 /* 14 */ "FT_NONE", /* TBL_SEQUENCEOF_start */
371 /* 15 */ "FT_NONE", /* TBL_TYPEREF_nopop */
372 /* 16 */ "FT_NONE", /* TBL_CHOICE_done */
373 /* 17 */ "FT_NONE", /* TBL_reserved */
374 /* 18 */ "FT_NONE", /* TBL_CHOICE_immediate */
376 /* 19 */ "FT_NONE", /* TBL_INVALID */
379 typedef struct _PDUinfo PDUinfo
;
383 const char *asn1typename
;
384 const char *fullname
;
390 gint basetype
; /* parent type */
391 gint mytype
; /* original type number, typenum may have gone through a reference */
392 gint value_id
; /* wireshark field id for the value in this PDU */
393 gint type_id
; /* wireshark field id for the type of this PDU */
394 hf_register_info value_hf
; /* wireshark field info for this value */
398 /* bits in the flags collection */
399 #define PDU_OPTIONAL 1
400 #define PDU_IMPLICIT 2
401 #define PDU_NAMEDNUM 4
402 #define PDU_REFERENCE 8
403 #define PDU_TYPEDEF 0x10
404 #define PDU_ANONYMOUS 0x20
405 #define PDU_TYPETREE 0x40
407 #define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
409 static guint PDUinfo_initflags
= 0; /* default flags for newly allocated PDUinfo structs */
411 /* description of PDU properties as passed from the matching routine
412 * to the decoder and GUI.
414 typedef struct _PDUprops PDUprops
;
416 guint type
; /* value from enum TBLTypeId */
418 const char *asn1typename
;
419 const char *fullname
;
425 /* flags defined in PDUprops.flags */
426 #define OUT_FLAG_type 1
427 #define OUT_FLAG_data 2
428 #define OUT_FLAG_typename 4
429 #define OUT_FLAG_dontshow 8
430 #define OUT_FLAG_noname 0x10
431 #define OUT_FLAG_constructed 0x20
433 static PDUprops
*getPDUprops(PDUprops
*out
, guint offset
, guint cls
, guint tag
, guint cons
);
434 static const char *getPDUenum(PDUprops
*props
, guint offset
, guint cls
, guint tag
, guint value
);
436 static const char empty
[] = ""; /* address of the empt string, avoids many tests for NULL */
437 #define MAX_OTSLEN 256 /* max printed size for an octet string */
440 #undef NEST /* show nesting of asn.1 enties */
442 #ifdef NEST /* only for debugging */
443 /* show nesting, only for debugging... */
444 #define MAXTAGS MAX_NEST
450 static char *showtaglist(guint level
)
452 static char tagtxt
[BUFLM
];
458 for(i
=0; i
<= level
; i
++) {
459 switch(taglist
[i
].cls
) {
461 idx
+= g_snprintf(&tagtxt
[idx
], BUFLM
- idx
, "U");
464 idx
+= g_snprintf(&tagtxt
[idx
], BUFLM
- idx
, "A");
467 idx
+= g_snprintf(&tagtxt
[idx
], BUFLM
- idx
, "C");
470 idx
+= g_snprintf(&tagtxt
[idx
], BUFLM
- idx
, "P");
473 idx
+= g_snprintf(&tagtxt
[idx
], BUFLM
- idx
, "x");
476 idx
+= g_snprintf(&tagtxt
[idx
], BUFLM
- idx
, "%d.", taglist
[i
].tag
);
478 #else /* only context tags */
479 idx
+= g_snprintf(&tagtxt
[idx
], BUFLM
- idx
, "C");
480 for(i
=0; i
<= level
; i
++) {
481 if (taglist
[i
].cls
== BER_CLASS_CON
) {
482 idx
+= g_snprintf(&tagtxt
[idx
], BUFLM
- idx
, "%d.", taglist
[i
].tag
);
487 tagtxt
[idx
] = '\0'; /* remove trailing '.' */
492 get_context(guint level
)
497 for(i
=0; i
<=level
; i
++) {
498 if (taglist
[i
].cls
== BER_CLASS_CON
)
499 ctx
= (ctx
<< 8) | taglist
[i
].tag
;
503 #endif /* NEST, only for debugging */
506 /* Convert a bit string to an ascii representation for printing
507 * -- not thread safe ...
509 static const char *showbits(guchar
*val
, guint count
)
511 static char str
[BUFLM
];
516 return "*too many bits*";
519 for(i
=0; i
<count
; i
++) {
520 if (i
&& ((i
& 7) == 0)) *p
++ = ' ';
521 *p
++ = (val
[i
>>3] & (0x80 >> (i
& 7))) ? '1' : '0';
528 /* get bitnames string for bits set */
530 showbitnames(guchar
*val
, guint count
, PDUprops
*props
, guint offset
)
532 static char str
[BUFLL
];
536 if (props
->flags
& OUT_FLAG_noname
)
540 return "*too many bits, no names...*";
544 for(i
=0; i
<count
; i
++) {
545 if (val
[i
>>3] & (0x80 >> (i
& 7))) { /* bit i is set */
546 idx
+= g_snprintf(&str
[idx
], BUFLL
-idx
, "%s,", getPDUenum(props
, offset
, 0, 0, i
));
550 --idx
; /* remove terminating , */
558 /* Convert an oid to its conventional text representation
559 * -- not thread safe...
561 static char *showoid(subid_t
*oid
, guint len
)
563 static char str
[BUFLM
];
569 for(i
=0; i
<len
; i
++) {
571 idx
+= g_snprintf(&str
[idx
], BUFLM
- idx
, ".");
572 idx
+= g_snprintf(&str
[idx
], BUFLM
- idx
, "%lu", (unsigned long)oid
[i
]);
579 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
581 showoctets(guchar
*octets
, guint len
, guint hexlen
) /* if len <= hexlen, always show hex */
587 const char *endstr
= empty
;
590 str
= (char *)g_malloc(1);
593 for (i
=0; i
<len
; i
++) {
594 if (!isprint(octets
[i
])) /* maybe isblank() as well ... */
597 if (len
> MAX_OTSLEN
) { /* limit the maximum output.... */
599 endstr
= "...."; /* this is 5 bytes !! */
602 str
= (char *)g_malloc(len
*2 + 5);
604 for (i
=0; i
<len
; i
++) {
605 idx
+= g_snprintf(&str
[idx
], len
*2 - idx
, "%2.2X", octets
[i
]);
607 g_snprintf(&str
[idx
], len
*2 + 5 - idx
, "%s", endstr
);
609 if (len
<= hexlen
) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
610 str
= (char *)g_malloc(len
*3+2);
612 for (i
=0; i
<len
; i
++) {
613 idx
+= g_snprintf(&str
[idx
], len
*3 - idx
, "%2.2X", octets
[i
]);
615 g_snprintf(&str
[idx
], len
*3+2 - idx
, " %s", octets
);
617 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
618 str
= (char *)g_malloc(len
+5);
619 g_snprintf(str
, len
*3+5, " %s%s", octets
, endstr
);
626 /* allow NULL pointers in strcmp, handle them as empty strings */
628 g_strcmp(gconstpointer a
, gconstpointer b
)
630 if (a
== 0) a
= empty
;
631 if (b
== 0) b
= empty
;
632 return strcmp((const char *)a
, (const char *)b
);
635 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
636 /* WARNING WARNING WARNING WARNING WARNING WARNING */
638 /* Most of the following routine is guesswork in order to */
639 /* speed up resynchronisation if the dissector lost the */
640 /* encoding due to incomplete captures, or a capture that */
641 /* starts in the middle of a fragmented ip packet */
642 /* If this poses to many problems, these settings can be */
643 /* made part of the protocol settings in the user interface */
644 /*************************************************************/
646 /* check length for a reasonable value, return a corrected value */
648 checklength(int len
, int def
, int cls
, int tag
, char *lenstr
, int strmax
)
653 g_snprintf(lenstr
, strmax
, "indefinite");
657 if (len
< 0) /* negative ..... */
660 if (cls
!= BER_CLASS_UNI
) { /* don't know about the tags */
665 case BER_UNI_TAG_EOC
: /* End Of Contents */
666 case BER_UNI_TAG_NULL
: /* Null */
669 case BER_UNI_TAG_BOOLEAN
: /* Boolean */
672 case BER_UNI_TAG_INTEGER
: /* Integer */
673 case BER_UNI_TAG_ENUMERATED
: /* Enumerated */
677 case BER_UNI_TAG_BITSTRING
: /* Bit String */
681 case BER_UNI_TAG_OCTETSTRING
: /* Octet String */
682 case BER_UNI_TAG_NumericString
: /* Numerical String */
683 case BER_UNI_TAG_PrintableString
: /* Printable String */
684 case BER_UNI_TAG_TeletexString
: /* Teletext String */
685 case BER_UNI_TAG_VideotexString
: /* Video String */
686 case BER_UNI_TAG_IA5String
: /* IA5 String */
687 case BER_UNI_TAG_GraphicString
: /* Graphical String */
688 case BER_UNI_TAG_VisibleString
: /* Visible String */
689 case BER_UNI_TAG_GeneralString
: /* General String */
693 case BER_UNI_TAG_OID
: /* Object Identifier */
694 case BER_UNI_TAG_ObjectDescriptor
: /* Description */
695 case ASN1_EXT
: /* External */
699 case BER_UNI_TAG_REAL
: /* Real */
703 case BER_UNI_TAG_SEQUENCE
: /* Sequence */
704 case BER_UNI_TAG_SET
: /* Set */
708 case BER_UNI_TAG_UTCTime
: /* Universal Time */
709 case BER_UNI_TAG_GeneralizedTime
: /* General Time */
722 /* a change was needed.... */
723 g_snprintf(lenstr
, strmax
, "%d(changed from %d)", newlen
, len
);
725 g_snprintf(lenstr
, strmax
, "%d", len
);
730 static guint
decode_asn1_sequence(tvbuff_t
*tvb
, guint offset
, guint len
, proto_tree
*pt
, int level
);
731 static void PDUreset(int count
, int counr2
);
734 dissect_asn1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
) {
737 guint cls
, con
, tag
, len
, offset
, reassembled
;
743 const char *name
, *tname
;
744 volatile guint boffset
;
745 volatile int i
= 0; /* PDU counter */
746 proto_tree
* volatile ti
= 0, * volatile ti2
= 0, *asn1_tree
, *tree2
;
747 proto_item
*hidden_item
;
749 static guint lastseq
;
750 struct tcpinfo
*info
;
756 reassembled
= 1; /* UDP is not a stream, and thus always reassembled .... */
757 if (pinfo
->ipproto
== IP_PROTO_TCP
) { /* we have tcpinfo */
758 info
= (struct tcpinfo
*)data
;
759 delta
= info
->seq
- lastseq
;
760 reassembled
= info
->is_reassembled
;
764 g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
765 info
->seq
, delta
, reassembled
);
768 g_message("dissect_asn1: udp");
771 /* Set the protocol column */
772 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "ASN.1 %s", current_pduname
);
774 col_clear(pinfo
->cinfo
, COL_INFO
);
778 if ((first_pdu_offset
> 0) && !reassembled
) {
779 boffset
= first_pdu_offset
;
780 g_snprintf(offstr
, sizeof(offstr
), " at %d", boffset
);
783 /* open BER decoding */
784 asn1_open(&asn1
, tvb
, boffset
);
786 asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
788 asn1_close(&asn1
, &offset
);
790 PDUreset(pcount
, 0); /* arguments are just for debugging */
791 getPDUprops(&props
, boffset
, cls
, tag
, con
);
793 tname
= props
.asn1typename
;
795 len
= checklength(len
, def
, cls
, tag
, lenstr
, sizeof(lenstr
));
799 g_snprintf(tagstr
, sizeof(tagstr
), "%ctag%d", tag_class
[cls
], tag
);
801 g_snprintf(headstr
, sizeof(headstr
), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
808 ((cls
== BER_CLASS_UNI
) && (tag
< 32)) ? asn1_tag
[tag
] : tagstr
,
814 if (props
.flags
& OUT_FLAG_noname
) {
815 g_snprintf(tagstr
, sizeof(tagstr
), "%ctag%d", tag_class
[cls
], tag
);
816 name
= ((cls
== BER_CLASS_UNI
) && (tag
< 32)) ? asn1_tag
[tag
] : tagstr
;
818 g_snprintf(headstr
, sizeof(headstr
), "first pdu%s: (%s)%s ", offstr
, tname
, name
);
821 /* Set the info column */
822 col_add_str(pinfo
->cinfo
, COL_INFO
, headstr
);
825 * If we have a non-null tree (ie we are building the proto_tree
826 * instead of just filling out the columns ), then add a BER
830 /* ignore the tree here, must decode BER to know how to reassemble!! */
833 TRY
{ /* catch incomplete PDU's */
835 ti
= proto_tree_add_protocol_format(tree
, proto_asn1
, tvb
, boffset
,
836 def
? (int) (offset
- boffset
+ len
) : -1,
837 "ASN.1 %s", current_pduname
);
839 tree2
= proto_item_add_subtree(ti
, ett_asn1
);
841 switch (((PDUinfo
*)PDUtree
->data
)->type
) {
848 hidden_item
= proto_tree_add_item(tree2
, ((PDUinfo
*)PDUtree
->data
)->value_id
, tvb
, boffset
,
849 def
? (int) (offset
- boffset
+ len
) : -1, ENC_LITTLE_ENDIAN
);
852 case TBL_OCTETSTRING
:
853 hidden_item
= proto_tree_add_item(tree2
, ((PDUinfo
*)PDUtree
->data
)->value_id
, tvb
, boffset
,
854 def
? (int) (offset
- boffset
+ len
) : -1, ENC_ASCII
|ENC_NA
);
858 hidden_item
= proto_tree_add_item(tree2
, ((PDUinfo
*)PDUtree
->data
)->value_id
, tvb
, boffset
,
859 def
? (int) (offset
- boffset
+ len
) : -1, ENC_NA
);
862 PROTO_ITEM_SET_HIDDEN(hidden_item
);
864 offset
= boffset
; /* the first packet */
865 while((i
< MAXPDU
) && (tvb_length_remaining(tvb
, offset
) > 0)) {
868 /* open BER decoding */
869 asn1_open(&asn1
, tvb
, offset
);
870 asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
871 asn1_close(&asn1
, &offset
);
873 PDUreset(pcount
, i
+1);
874 getPDUprops(&props
, boffset
, cls
, tag
, con
);
876 tname
= props
.asn1typename
;
879 len
= tvb_length_remaining(tvb
, offset
);
881 len
= checklength(len
, def
, cls
, tag
, lenstr
, sizeof(lenstr
));
885 g_snprintf(tagstr
, sizeof(tagstr
), "%ctag%d", tag_class
[cls
], tag
);
887 g_snprintf(headstr
, sizeof(headstr
), "%s, %s, %s, len=%s, off=%d, remaining=%d",
890 ((cls
== BER_CLASS_UNI
) && (tag
< 32)) ? asn1_tag
[tag
] : tagstr
,
893 tvb_length_remaining(tvb
, offset
) );
895 if (props
.value_id
== -1)
896 ti2
= proto_tree_add_text(tree2
, tvb
, boffset
,
897 def
? (int) (offset
- boffset
+ len
) : -1,
898 "%s: (%s)%s %d-%d %s", current_pduname
,
899 tname
, name
, pcount
, i
+1, headstr
);
901 ti2
= proto_tree_add_none_format(tree2
, props
.value_id
, tvb
, boffset
,
902 def
? (int) (offset
- boffset
+ len
) : -1,
903 "%s: (%s)%s %d-%d %s ~", current_pduname
,
904 tname
, name
, pcount
, i
+1, headstr
);
906 if (props
.type_id
!= -1){
907 switch (proto_registrar_get_ftype(props
.type_id
)) {
923 hidden_item
= proto_tree_add_item(tree2
, props
.type_id
, tvb
, boffset
,
924 def
? (int) (offset
- boffset
+ len
) : -1, ENC_LITTLE_ENDIAN
);
929 hidden_item
= proto_tree_add_item(tree2
, props
.type_id
, tvb
, boffset
,
930 def
? (int) (offset
- boffset
+ len
) : -1, ENC_ASCII
|ENC_NA
);
934 hidden_item
= proto_tree_add_item(tree2
, props
.type_id
, tvb
, boffset
,
935 def
? (int) (offset
- boffset
+ len
) : -1, ENC_NA
);
938 PROTO_ITEM_SET_HIDDEN(hidden_item
);
942 if (props
.flags
& OUT_FLAG_noname
) {
943 g_snprintf(tagstr
, sizeof(tagstr
), "%ctag%d", tag_class
[cls
], tag
);
944 name
= ((cls
== BER_CLASS_UNI
) && (tag
< 32)) ? asn1_tag
[tag
] : tagstr
;
946 if (props
.value_id
== -1)
947 ti2
= proto_tree_add_text(tree2
, tvb
, boffset
,
948 def
? (int) (offset
- boffset
+ len
) : -1,
949 "%s: (%s)%s", current_pduname
, tname
, name
);
951 ti2
= proto_tree_add_none_format(tree2
, props
.value_id
, tvb
, boffset
,
952 def
? (int) (offset
- boffset
+ len
) : -1,
953 "%s: (%s)%s ~", current_pduname
, tname
, name
);
954 if (props
.type_id
!= -1){
955 switch (proto_registrar_get_ftype(props
.type_id
)) {
971 hidden_item
= proto_tree_add_item(tree2
, props
.type_id
, tvb
, boffset
,
972 def
? (int) (offset
- boffset
+ len
) : -1, ENC_LITTLE_ENDIAN
);
977 hidden_item
= proto_tree_add_item(tree2
, props
.type_id
, tvb
, boffset
,
978 def
? (int) (offset
- boffset
+ len
) : -1, ENC_ASCII
|ENC_NA
);
982 hidden_item
= proto_tree_add_item(tree2
, props
.type_id
, tvb
, boffset
,
983 def
? (int) (offset
- boffset
+ len
) : -1, ENC_NA
);
986 PROTO_ITEM_SET_HIDDEN(hidden_item
);
990 asn1_tree
= proto_item_add_subtree(ti2
, ett_pdu
[i
]);
993 taglist
[0].cls
= cls
;
994 taglist
[0].tag
= tag
;
997 if (!def
) len
++; /* make sure we get an exception if we run off the end! */
999 offset
= decode_asn1_sequence(tvb
, offset
, len
, asn1_tree
, 1);
1001 proto_item_set_len(ti2
, offset
- boffset
); /* mark length for hex display */
1003 i
++; /* one more full message handled */
1005 if (ti2
&& PDUerrcount
&& asn1_debug
) /* show error counts only when in debug mode.... */
1006 proto_item_append_text(ti2
," (%d error%s)", PDUerrcount
, (PDUerrcount
>1)?"s":empty
);
1008 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[%d msg%s]", i
, (i
>1)?"s":empty
);
1010 proto_item_append_text(ti
, ", %d msg%s", i
, (i
>1)?"s":empty
);
1012 CATCH(ReportedBoundsError
) {
1013 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[%d+1 msg%s]", i
, (i
>0)?"s":empty
);
1015 proto_item_append_text(ti
, ", %d+1 msg%s", i
, (i
>1)?"s":empty
);
1017 proto_item_append_text(ti2
, " (incomplete)");
1018 if (asn1_desegment
) {
1019 pinfo
->desegment_offset
= boffset
;
1020 pinfo
->desegment_len
= 1;
1022 g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
1023 boffset
, 1, pinfo
->can_desegment
);
1031 g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
1032 pinfo
->desegment_offset
, pinfo
->desegment_len
, pinfo
->can_desegment
);
1034 return tvb_length(tvb
);
1037 /* decode an ASN.1 sequence, until we have consumed the specified length */
1039 decode_asn1_sequence(tvbuff_t
*tvb
, guint offset
, guint tlen
, proto_tree
*pt
, int level
)
1042 guint ret
, cls
, con
, tag
, len
, boffset
, soffset
, eos
;
1045 const char *clsstr
, *constr
, *tagstr
;
1049 proto_tree
*ti
, *pt2
;
1050 proto_item
*hidden_item
;
1051 guchar
*octets
, *bits
, unused
;
1053 /* the debugging formats */
1054 static char textfmt_d
[] = "off=%d: [%s %s %s] (%s)%s: %d%s"; /* decimal */
1055 static char textfmt_e
[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s"; /* enum */
1056 static char textfmt_s
[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s"; /* octet string */
1057 static char textfmt_b
[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s"; /* bit field */
1058 static char textfmt_c
[] = "off=%d: [%s %s %s] (%s)%s%s%s"; /* constructed */
1059 static char matchind
[] = " ~"; /* indication of possible match */
1060 const char *name
, *ename
, *tname
;
1064 ti
= 0; /* suppress gcc warning */
1066 soffset
= offset
; /* where this sequence starts */
1067 eos
= offset
+ tlen
;
1068 while (offset
< eos
) { /* while this entity has not ended... */
1070 asn1_open(&asn1
, tvb
, offset
);
1071 ret
= asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
1072 asn1_close(&asn1
, &offset
); /* mark current position */
1073 if (ret
!= ASN1_ERR_NOERROR
) {
1074 proto_tree_add_text(pt
, tvb
, offset
, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret
) );
1078 getPDUprops(&props
, boffset
, cls
, tag
, con
);
1080 tname
= props
.asn1typename
;
1082 name
= &props
.fullname
[pabbrev_pdu_len
]; /* no abbrev.pduname */
1083 if (asn1_debug
) { /* show both names */
1084 g_snprintf(fieldname
, sizeof(fieldname
), "%s[%s]", props
.name
, props
.fullname
);
1088 clsstr
= asn1_cls
[cls
];
1089 constr
= asn1_con
[con
];
1090 if ((cls
== BER_CLASS_UNI
) && ( tag
< 32 )) {
1091 tagstr
= asn1_tag
[tag
];
1093 g_snprintf(tagbuf
, sizeof(tagbuf
), "%ctag%d", tag_class
[cls
], tag
);
1097 len
= checklength(len
, def
, cls
, tag
, lenbuf
, sizeof(lenbuf
));
1100 g_snprintf(nnbuf
, sizeof(nnbuf
), "NN%d", len
);
1102 g_snprintf(nnbuf
, sizeof(nnbuf
), "NN-");
1103 /* make sure we get an exception if we run off the end! */
1104 len
= tvb_length_remaining(tvb
, offset
) + 1;
1106 if ( ( ! asn1_debug
) && (props
.flags
& OUT_FLAG_noname
) ) {
1107 /* just give type name if we don't know any better */
1109 name
= nnbuf
; /* this is better than just empty.... */
1113 taglist
[level
].cls
= cls
;
1114 taglist
[level
].tag
= tag
;
1118 if (level
>= MAX_NEST
) { /* nesting too deep..., handle as general octet string */
1119 cls
= BER_CLASS_UNI
;
1120 tag
= BER_UNI_TAG_GeneralString
;
1121 oname
= (char *)g_malloc(strlen(name
) + 32);
1122 g_snprintf(oname
, (gulong
)(strlen(name
) + 32), "%s ** nesting cut off **", name
);
1126 case BER_CLASS_UNI
: /* fprintf(stderr, "Universal\n"); */
1128 case BER_UNI_TAG_INTEGER
:
1129 asn1_int32_value_decode(&asn1
, len
, &value
); /* read value */
1130 asn1_close(&asn1
, &offset
); /* mark where we are now */
1132 if ( (props
.value_id
== -1) ||
1133 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1134 /* unknown or unexpected: just text */
1135 proto_tree_add_text(pt
, tvb
, boffset
,
1136 offset
- boffset
, textfmt_d
, boffset
,
1137 clsstr
, constr
, tagstr
, tname
, name
, value
,
1140 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
, boffset
,
1141 offset
- boffset
, value
, textfmt_d
, boffset
,
1142 clsstr
, constr
, tagstr
, tname
, name
, value
,
1144 if (props
.type_id
!= -1) {
1145 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
, tvb
,
1146 boffset
, offset
- boffset
, value
);
1147 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1151 if ( (props
.value_id
== -1) ||
1152 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1153 /* unknown or unexpected, just text */
1154 proto_tree_add_text(pt
, tvb
, boffset
,
1156 "(%s)%s: %d", tname
, name
, value
);
1158 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
, boffset
,
1159 offset
- boffset
, value
,
1160 "(%s)%s: %d ~", tname
, name
, value
);
1161 if (props
.type_id
!= -1){
1162 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
, tvb
,
1163 boffset
, offset
- boffset
, value
);
1164 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1170 case BER_UNI_TAG_ENUMERATED
:
1171 asn1_int32_value_decode(&asn1
, len
, &value
); /* read value */
1172 asn1_close(&asn1
, &offset
); /* mark where we are now */
1173 ename
= getPDUenum(&props
, boffset
, cls
, tag
, value
);
1175 if ( (props
.value_id
== -1) ||
1176 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1177 /* unknown or unexpected, just text */
1178 proto_tree_add_text(pt
, tvb
, boffset
,
1180 textfmt_e
, boffset
, clsstr
, constr
, tagstr
,
1181 tname
, name
, value
, ename
, empty
);
1183 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
, boffset
,
1184 offset
- boffset
, value
,
1185 textfmt_e
, boffset
, clsstr
, constr
, tagstr
,
1186 tname
, name
, value
, ename
, matchind
);
1187 if (props
.type_id
!= -1){
1188 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
, tvb
,
1189 boffset
, offset
- boffset
, value
);
1190 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1194 if ( (props
.value_id
== -1) ||
1195 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1196 /* unknown or unexpected, just text */
1197 proto_tree_add_text(pt
, tvb
, boffset
,
1199 "(%s)%s: %d:%s", tname
, name
, value
, ename
);
1201 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
, boffset
,
1202 offset
- boffset
, value
,
1203 "(%s)%s: %d:%s ~", tname
, name
, value
, ename
);
1204 if (props
.type_id
!= -1){
1205 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
, tvb
,
1206 boffset
, offset
- boffset
, value
);
1207 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1213 case BER_UNI_TAG_BOOLEAN
:
1214 asn1_bool_decode(&asn1
, len
, (gboolean
*)&value
); /* read value */
1215 asn1_close(&asn1
, (gint
*)&offset
); /* mark where we are now */
1217 if ( (props
.value_id
== -1) ||
1218 (tbl_types_wireshark
[props
.type
] != FT_BOOLEAN
) )
1219 /* unknown or unexpected, just text */
1220 proto_tree_add_text(pt
, tvb
, boffset
,
1222 textfmt_s
, boffset
, clsstr
, constr
, tagstr
,
1223 tname
, name
, value
? "true" : "false", empty
);
1225 proto_tree_add_boolean_format(pt
, props
.value_id
, tvb
, boffset
,
1226 offset
- boffset
, value
!= 0,
1227 textfmt_s
, boffset
, clsstr
, constr
, tagstr
,
1228 tname
, name
, value
? "true" : "false", matchind
);
1229 if (props
.type_id
!= -1){
1230 hidden_item
= proto_tree_add_boolean(pt
, props
.type_id
, tvb
,
1231 boffset
, offset
- boffset
, value
!= 0);
1232 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1236 if ( (props
.value_id
== -1) ||
1237 (tbl_types_wireshark
[props
.type
] != FT_BOOLEAN
) )
1238 /* unknown or unexpected, just text */
1239 proto_tree_add_text(pt
, tvb
, boffset
,
1241 "(%s)%s: %s", tname
, name
,
1242 value
? "true" : "false");
1244 proto_tree_add_boolean_format(pt
, props
.value_id
, tvb
, boffset
,
1245 offset
- boffset
, value
!= 0,
1246 "(%s)%s: %s ~", tname
, name
,
1247 value
? "true" : "false");
1248 if (props
.type_id
!= -1){
1249 hidden_item
= proto_tree_add_boolean(pt
, props
.type_id
, tvb
,
1250 boffset
, offset
- boffset
, value
!= 0);
1251 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1257 case BER_UNI_TAG_OCTETSTRING
:
1258 case BER_UNI_TAG_NumericString
:
1259 case BER_UNI_TAG_PrintableString
:
1260 case BER_UNI_TAG_TeletexString
:
1261 case BER_UNI_TAG_IA5String
:
1262 case BER_UNI_TAG_GeneralString
:
1263 case BER_UNI_TAG_UTCTime
:
1264 case BER_UNI_TAG_GeneralizedTime
:
1265 /* read value, \0 terminated */
1266 asn1_string_value_decode(&asn1
, len
, &octets
);
1267 asn1_close(&asn1
, (gint
*)&offset
); /* mark where we are now */
1268 ename
= showoctets(octets
, len
, (tag
== BER_UNI_TAG_OCTETSTRING
) ? 4 : 0 );
1270 if ( (props
.value_id
== -1) ||
1271 (tbl_types_wireshark
[props
.type
] != FT_STRINGZ
) )
1272 /* unknown or unexpected, just text */
1273 proto_tree_add_text(pt
, tvb
, boffset
,
1275 textfmt_s
, boffset
, clsstr
, constr
, tagstr
,
1276 tname
, name
, ename
, empty
);
1278 proto_tree_add_string_format(pt
, props
.value_id
, tvb
, boffset
,
1279 offset
- boffset
, octets
, /* \0 termnated */
1280 textfmt_s
, boffset
, clsstr
, constr
, tagstr
,
1281 tname
, name
, ename
, matchind
);
1282 if (props
.type_id
!= -1){
1283 hidden_item
= proto_tree_add_string(pt
, props
.type_id
, tvb
,
1284 boffset
, offset
- boffset
, octets
);
1285 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1289 if ( (props
.value_id
== -1) ||
1290 (tbl_types_wireshark
[props
.type
] != FT_STRINGZ
) )
1291 /* unknown or unexpected, just text */
1292 proto_tree_add_text(pt
, tvb
, boffset
,
1294 "(%s)%s: %s", tname
, name
, ename
);
1296 proto_tree_add_string_format(pt
, props
.value_id
, tvb
, boffset
,
1297 offset
- boffset
, octets
, /* \0 terminated */
1298 "(%s)%s: %s ~", tname
, name
, ename
);
1299 if (props
.type_id
!= -1){
1300 hidden_item
= proto_tree_add_string(pt
, props
.type_id
, tvb
,
1301 boffset
, offset
- boffset
, octets
);
1302 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1307 g_free( (gpointer
) ename
);
1310 case BER_UNI_TAG_BITSTRING
:
1311 asn1_bits_decode(&asn1
, len
, &bits
, &con
, &unused
); /* read value */
1312 asn1_close(&asn1
, &offset
); /* mark where we are now */
1313 ename
= showbitnames(bits
, (con
*8)-unused
, &props
, offset
);
1315 if ( (props
.value_id
== -1) ||
1316 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1317 /* unknown or unexpected, just text */
1318 proto_tree_add_text(pt
, tvb
, boffset
,
1320 textfmt_b
, boffset
, clsstr
, constr
, tagstr
,
1322 showbits(bits
, (con
*8)-unused
), ename
, empty
);
1324 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
, boffset
,
1325 offset
- boffset
, *bits
, /* XXX length ? XXX */
1326 textfmt_b
, boffset
, clsstr
, constr
, tagstr
,
1328 showbits(bits
, (con
*8)-unused
),ename
, matchind
);
1329 if (props
.type_id
!= -1){
1330 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
, tvb
,
1331 boffset
, offset
- boffset
, *bits
);
1332 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1337 if ( (props
.value_id
== -1) ||
1338 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1339 /* unknown or unexpected, just text */
1340 proto_tree_add_text(pt
, tvb
, boffset
,
1342 "(%s)%s: %s:%s", tname
, name
,
1343 showbits(bits
, (con
*8)-unused
), ename
);
1345 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
, boffset
,
1346 offset
- boffset
, *bits
, /* XXX length ? XXX */
1347 "(%s)%s: %s:%s ~", tname
, name
,
1348 showbits(bits
, (con
*8)-unused
), ename
);
1349 if (props
.type_id
!= -1){
1350 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
, tvb
,
1351 boffset
, offset
- boffset
, *bits
);
1352 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1359 case BER_UNI_TAG_SET
:
1360 case BER_UNI_TAG_SEQUENCE
:
1361 /* show full sequence length */
1364 if ( (props
.flags
& OUT_FLAG_dontshow
) || asn1_full
)
1366 if ( (props
.flags
& OUT_FLAG_constructed
))
1367 ename
= ", unexpected constructed";
1369 if (props
.value_id
== -1)
1370 ti
= proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
,
1371 textfmt_c
, boffset
, clsstr
, constr
, tagstr
,
1372 tname
, name
, ename
, empty
);
1374 switch (props
.type
) {
1380 case TBL_ENUMERATED
:
1381 ti
= proto_tree_add_item(pt
, props
.value_id
, tvb
,
1382 boffset
, 1, ENC_LITTLE_ENDIAN
);
1385 case TBL_OCTETSTRING
:
1386 ti
= proto_tree_add_item(pt
, props
.value_id
, tvb
,
1387 boffset
, 1, ENC_ASCII
|ENC_NA
);
1391 ti
= proto_tree_add_item(pt
, props
.value_id
, tvb
,
1392 boffset
, 1, ENC_NA
);
1395 /* change te text to to what I really want */
1396 proto_item_set_text(ti
, textfmt_c
, boffset
, clsstr
, constr
,
1397 tagstr
, tname
, name
, ename
, matchind
);
1398 if (props
.type_id
!= -1){
1399 switch (proto_registrar_get_ftype(props
.type_id
)) {
1415 hidden_item
= proto_tree_add_item(pt
, props
.type_id
, tvb
,
1416 boffset
, 1, ENC_LITTLE_ENDIAN
);
1421 hidden_item
= proto_tree_add_item(pt
, props
.type_id
, tvb
,
1422 boffset
, 1, ENC_ASCII
|ENC_NA
);
1426 hidden_item
= proto_tree_add_item(pt
, props
.type_id
, tvb
,
1427 boffset
, 1, ENC_NA
);
1430 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1434 if (props
.value_id
== -1) {
1435 if ( (! asn1_full
) && ((props
.flags
& OUT_FLAG_dontshow
) == 0) )
1436 ti
= proto_tree_add_text(pt
, tvb
, boffset
,
1437 offset
- boffset
+ len
,
1438 "(%s)%s", tname
, name
);
1440 if ( (! asn1_full
) && ((props
.flags
& OUT_FLAG_dontshow
) == 0) )
1441 ti
= proto_tree_add_none_format(pt
, props
.value_id
, tvb
,
1442 boffset
, offset
- boffset
+ len
,
1443 "(%s)%s ~", tname
, name
);
1445 /* don't care about the text */
1446 switch (props
.type
) {
1452 case TBL_ENUMERATED
:
1453 ti
= hidden_item
= proto_tree_add_item(pt
, props
.value_id
, tvb
,
1454 boffset
, 1, ENC_LITTLE_ENDIAN
);
1457 case TBL_OCTETSTRING
:
1458 ti
= hidden_item
= proto_tree_add_item(pt
, props
.value_id
, tvb
,
1459 boffset
, 1, ENC_ASCII
|ENC_NA
);
1463 ti
= hidden_item
= proto_tree_add_item(pt
, props
.value_id
, tvb
,
1464 boffset
, 1, ENC_NA
);
1467 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1469 if (props
.type_id
!= -1){
1470 switch (proto_registrar_get_ftype(props
.type_id
)) {
1486 hidden_item
= proto_tree_add_item(pt
, props
.type_id
, tvb
,
1487 boffset
, 1, ENC_LITTLE_ENDIAN
);
1492 hidden_item
= proto_tree_add_item(pt
, props
.type_id
, tvb
,
1493 boffset
, 1, ENC_ASCII
|ENC_NA
);
1497 hidden_item
= proto_tree_add_item(pt
, props
.type_id
, tvb
,
1498 boffset
, 1, ENC_NA
);
1501 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1505 if (len
== 0) return offset
; /* don't recurse if offset isn't going to change */
1507 if ( ( ! asn1_full
) && (asn1_debug
|| ((props
.flags
& OUT_FLAG_dontshow
) == 0)))
1508 pt2
= proto_item_add_subtree(ti
, ett_seq
[level
]);
1512 offset
= decode_asn1_sequence(tvb
, offset
, len
, pt2
, level
+1); /* recurse */
1514 if ( ( ! asn1_full
) && (asn1_debug
|| ((props
.flags
& OUT_FLAG_dontshow
) == 0)))
1515 proto_item_set_len(ti
, offset
- boffset
);
1519 case BER_UNI_TAG_EOC
:
1520 if (asn1_debug
) { /* don't show if not debugging */
1521 proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
, textfmt_d
,
1522 boffset
, clsstr
, constr
, tagstr
, tname
, name
,
1523 offset
- soffset
, empty
);
1525 getPDUprops(&props
, soffset
, ASN1_EOI
, 1, 0); /* mark end of this sequence */
1528 case BER_UNI_TAG_OID
:
1529 asn1_oid_value_decode(&asn1
, len
, &oid
, &con
);
1530 asn1_close(&asn1
, (gint
*)&offset
); /* mark where we are now */
1531 ename
= showoid(oid
, con
);
1533 if ( (props
.value_id
== -1) ||
1534 (tbl_types_wireshark
[props
.type
] != FT_BYTES
) )
1535 /* unknown or unexpected, just text */
1536 proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
, textfmt_s
,
1537 boffset
, clsstr
, constr
, tagstr
, tname
, name
,
1540 proto_tree_add_bytes_format(pt
, props
.value_id
, tvb
, boffset
,
1541 offset
- boffset
, ename
,/* XXX length?*/
1542 "(%s)%s: %s ~", tname
, name
, ename
);
1543 if (props
.type_id
!= -1){
1544 hidden_item
= proto_tree_add_bytes(pt
, props
.type_id
, tvb
,
1545 boffset
, offset
- boffset
, ename
);
1546 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1550 if ( (props
.value_id
== -1) ||
1551 (tbl_types_wireshark
[props
.type
] != FT_BYTES
) )
1552 /* unknown or unexpected, just text */
1553 proto_tree_add_text(pt
, tvb
, boffset
,
1555 "(%s)%s: %s", tname
, name
, ename
);
1557 proto_tree_add_bytes_format(pt
, props
.value_id
, tvb
, boffset
,
1558 offset
- boffset
, ename
, /* XXX length ? */
1559 "(%s)%s: %s ~", tname
, name
, ename
);
1560 if (props
.type_id
!= -1){
1561 hidden_item
= proto_tree_add_bytes(pt
, props
.type_id
, tvb
,
1562 boffset
, offset
- boffset
, ename
);
1563 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1570 case BER_UNI_TAG_NULL
:
1572 proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
, textfmt_s
,
1573 boffset
, clsstr
, constr
, tagstr
, tname
, name
,
1576 proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
,
1577 "(%s)%s: [NULL]", tname
, name
);
1579 offset
+= len
; /* skip value ... */
1582 case BER_UNI_TAG_ObjectDescriptor
:
1584 case BER_UNI_TAG_REAL
:
1585 case BER_UNI_TAG_VideotexString
:
1586 case BER_UNI_TAG_GraphicString
:
1587 case BER_UNI_TAG_VisibleString
:
1591 ti
= proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
,
1592 textfmt_s
, boffset
, clsstr
, constr
, tagstr
,
1593 tname
, name
, lenbuf
, empty
);
1595 ti
= proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
,
1596 "(%s)%s: %s bytes", tname
, name
, lenbuf
);
1598 proto_item_append_text(ti
, " *"); /* indicate default is used */
1599 offset
+= len
; /* skip value ... */
1604 case BER_CLASS_CON
: /* fprintf(stderr, "Context\n"); */
1605 case BER_CLASS_APP
: /* fprintf(stderr, "Application\n"); */
1606 case BER_CLASS_PRI
: /* fprintf(stderr, "Private\n"); */
1609 if (props
.value_id
== -1) /* type unknown, handle as string */
1611 switch(props
.type
) {
1612 /* this is via the asn1 description, don't trust the length */
1616 asn1_int32_value_decode(&asn1
, len
, (gint32
*)&value
); /* read value */
1617 asn1_close(&asn1
, &offset
); /* mark where we are now */
1619 if ( (props
.value_id
== -1) ||
1620 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1621 /* unknown or unexpected, just text */
1622 proto_tree_add_text(pt
, tvb
,
1623 boffset
, offset
- boffset
,
1624 textfmt_d
, boffset
, clsstr
, constr
,
1625 tagstr
, tname
, name
, value
, empty
);
1627 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
,
1628 boffset
, offset
- boffset
, value
,
1629 textfmt_d
, boffset
, clsstr
, constr
,
1630 tagstr
, tname
, name
, value
, matchind
);
1631 if (props
.type_id
!= -1){
1632 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
,
1633 tvb
, boffset
, offset
- boffset
, value
);
1634 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1638 if ( (props
.value_id
== -1) ||
1639 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1640 /* unknown or unexpected, just text */
1641 proto_tree_add_text(pt
, tvb
,
1642 boffset
, offset
- boffset
,
1643 "(%s)%s: %d", tname
, name
, value
);
1645 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
,
1646 boffset
, offset
- boffset
, value
,
1647 "(%s)%s: %d ~", tname
, name
, value
);
1648 if (props
.type_id
!= -1){
1649 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
,
1650 tvb
, boffset
, offset
- boffset
, value
);
1651 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1657 case TBL_ENUMERATED
:
1660 asn1_int32_value_decode(&asn1
, len
, &value
); /* read value */
1661 asn1_close(&asn1
, &offset
); /* mark where we are now */
1662 ename
= getPDUenum(&props
, boffset
, cls
, tag
, value
);
1664 if ( (props
.value_id
== -1) ||
1665 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1666 /* unknown or unexpected, just text */
1667 proto_tree_add_text(pt
, tvb
,
1668 boffset
, offset
- boffset
,
1669 textfmt_e
, boffset
, clsstr
, constr
,
1670 tagstr
, tname
, name
, value
, ename
, empty
);
1672 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
,
1673 boffset
, offset
- boffset
, value
,
1674 textfmt_e
, boffset
, clsstr
, constr
,
1675 tagstr
, tname
, name
, value
, ename
, matchind
);
1676 if (props
.type_id
!= -1){
1677 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
,
1678 tvb
, boffset
, offset
- boffset
, value
);
1679 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1683 if ( (props
.value_id
== -1) ||
1684 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1685 /* unknown or unexpected, just text */
1686 proto_tree_add_text(pt
, tvb
,
1687 boffset
, offset
- boffset
,
1688 "(%s)%s: %d:%s", tname
, name
, value
, ename
);
1690 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
,
1691 boffset
, offset
- boffset
, value
,
1692 "(%s)%s: %d:%s ~", tname
, name
, value
, ename
);
1693 if (props
.type_id
!= -1){
1694 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
,
1695 tvb
, boffset
, offset
- boffset
, value
);
1696 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1702 if (len
> (1+4)) /* max 32 bits ...?.. */
1705 asn1_bits_decode(&asn1
, len
, &bits
, &con
, &unused
);
1706 asn1_close(&asn1
, (gint
*)&offset
); /* mark where we are now */
1707 ename
= showbitnames(bits
, (con
*8)-unused
, &props
, offset
);
1709 if ( (props
.value_id
== -1) ||
1710 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1711 /* unknown or unexpected, just text */
1712 proto_tree_add_text(pt
, tvb
,
1713 boffset
, offset
- boffset
,
1714 textfmt_b
, boffset
, clsstr
, constr
,
1715 tagstr
, tname
, name
,
1716 showbits(bits
, (con
*8)-unused
), ename
,
1719 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
,
1720 boffset
, offset
- boffset
, *bits
,
1721 textfmt_b
, boffset
, clsstr
, constr
,
1722 tagstr
, tname
, name
,
1723 showbits(bits
, (con
*8)-unused
), ename
,
1725 if (props
.type_id
!= -1){
1726 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
,
1727 tvb
, boffset
, offset
- boffset
, *bits
);
1728 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1732 if ( (props
.value_id
== -1) ||
1733 (tbl_types_wireshark
[props
.type
] != FT_UINT32
) )
1734 /* unknown or unexpected, just text */
1735 proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
,
1736 "(%s)%s: %s:%s", tname
, name
,
1737 showbits(bits
, (con
*8)-unused
), ename
);
1739 proto_tree_add_uint_format(pt
, props
.value_id
, tvb
,
1740 boffset
, offset
- boffset
, *bits
,
1741 "(%s)%s: %s:%s ~", tname
, name
,
1742 showbits(bits
, (con
*8)-unused
), ename
);
1743 if (props
.type_id
!= -1){
1744 hidden_item
= proto_tree_add_uint(pt
, props
.type_id
,
1745 tvb
, boffset
, offset
- boffset
, *bits
);
1746 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1755 asn1_bool_decode(&asn1
, len
, (gboolean
*)&value
); /* read value */
1756 asn1_close(&asn1
, (gint
*)&offset
); /* mark where we are now */
1758 if ( (props
.value_id
== -1) ||
1759 (tbl_types_wireshark
[props
.type
] != FT_BOOLEAN
) )
1760 /* unknown or unexpected, just text */
1761 proto_tree_add_text(pt
, tvb
,
1762 boffset
, offset
- boffset
,
1763 textfmt_s
, boffset
, clsstr
, constr
,
1764 tagstr
, tname
, name
,
1765 value
? "true" : "false", empty
);
1767 proto_tree_add_boolean_format(pt
, props
.value_id
, tvb
,
1768 boffset
, offset
- boffset
, value
!= 0,
1769 textfmt_s
, boffset
, clsstr
, constr
,
1770 tagstr
, tname
, name
,
1771 value
? "true" : "false", matchind
);
1772 if (props
.type_id
!= -1){
1773 hidden_item
= proto_tree_add_boolean(pt
, props
.type_id
,
1774 tvb
, boffset
, offset
- boffset
, value
!= 0);
1775 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1779 if ( (props
.value_id
== -1) ||
1780 (tbl_types_wireshark
[props
.type
] != FT_BOOLEAN
) )
1781 /* unknown or unexpected, just text */
1782 proto_tree_add_text(pt
, tvb
,
1783 boffset
, offset
- boffset
,
1784 "(%s)%s: %s", tname
, name
,
1785 value
? "true" : "false");
1787 proto_tree_add_boolean_format(pt
, props
.value_id
, tvb
,
1788 boffset
, offset
- boffset
, value
!= 0,
1789 "(%s)%s: %s ~", tname
, name
,
1790 value
? "true" : "false");
1791 if (props
.type_id
!= -1){
1792 hidden_item
= proto_tree_add_boolean(pt
, props
.type_id
,
1793 tvb
, boffset
, offset
- boffset
, value
!= 0);
1794 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1803 proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
,
1804 textfmt_s
, boffset
, clsstr
, constr
,
1805 tagstr
, tname
, name
, "[NULL]", empty
);
1807 proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
,
1808 "(%s)%s: [NULL]", tname
, name
);
1810 offset
+= len
; /* skip value ... */
1814 props
.value_id
= -1; /* unlikely this is correct, dont use it */
1816 case TBL_OCTETSTRING
:
1817 /* defined length, not constructed, must be a string.... */
1818 asn1_string_value_decode(&asn1
, len
, &octets
); /* read value */
1819 asn1_close(&asn1
, (gint
*)&offset
); /* mark where we are now */
1820 ename
= showoctets(octets
, len
, 2); /* convert octets to printable */
1822 if ( (props
.value_id
== -1) ||
1823 (tbl_types_wireshark
[props
.type
] != FT_STRINGZ
) )
1824 /* unknown or unexpected, just text */
1825 proto_tree_add_text(pt
, tvb
,
1826 boffset
, offset
- boffset
,
1827 textfmt_s
, boffset
, clsstr
, constr
,
1828 tagstr
, tname
, name
, ename
, empty
);
1830 proto_tree_add_string_format(pt
, props
.value_id
, tvb
,
1831 boffset
, offset
- boffset
, (gchar
*)octets
, /* XXX */
1832 textfmt_s
, boffset
, clsstr
, constr
,
1833 tagstr
, tname
, name
, ename
, matchind
);
1834 if (props
.type_id
!= -1){
1835 hidden_item
= proto_tree_add_string(pt
, props
.type_id
,
1836 tvb
, boffset
, offset
- boffset
, (gchar
*)octets
);
1837 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1841 if ( (props
.value_id
== -1) ||
1842 (tbl_types_wireshark
[props
.type
] != FT_STRINGZ
) )
1843 /* unknown or unexpected, just text */
1844 proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
,
1845 "(%s)%s: %s", tname
, name
, ename
);
1847 proto_tree_add_string_format(pt
, props
.value_id
, tvb
,
1848 boffset
, offset
- boffset
, (gchar
*)octets
, /* XXX */
1849 "(%s)%s: %s ~", tname
, name
, ename
);
1850 if (props
.type_id
!= -1){
1851 hidden_item
= proto_tree_add_string(pt
, props
.type_id
,
1852 tvb
, boffset
, offset
- boffset
, (gchar
*)octets
);
1853 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1858 g_free( (gpointer
) ename
);
1862 /* indefinite length or constructed.... must be a sequence .... */
1863 /* show full sequence length */
1866 if ( (props
.flags
& OUT_FLAG_dontshow
) || asn1_full
)
1868 if ( (props
.flags
& OUT_FLAG_constructed
))
1869 ename
= ", unexpected constructed";
1871 if (props
.value_id
== -1)
1872 ti
= proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
,
1873 textfmt_c
, boffset
, clsstr
, constr
,
1874 tagstr
, tname
, name
, ename
, empty
);
1876 switch (props
.type
) {
1882 case TBL_ENUMERATED
:
1883 ti
= proto_tree_add_item(pt
, props
.value_id
, tvb
,
1884 boffset
, 1, ENC_LITTLE_ENDIAN
);
1887 case TBL_OCTETSTRING
:
1888 ti
= proto_tree_add_item(pt
, props
.value_id
, tvb
,
1889 boffset
, 1, ENC_ASCII
|ENC_NA
);
1893 ti
= proto_tree_add_item(pt
, props
.value_id
, tvb
,
1894 boffset
, 1, ENC_NA
);
1897 /* change te text to to what I really want */
1899 proto_item_set_text(ti
, textfmt_c
, boffset
, clsstr
, constr
,
1900 tagstr
, tname
, name
, ename
, matchind
);
1901 if (props
.type_id
!= -1){
1902 switch (proto_registrar_get_ftype(props
.type_id
)) {
1918 hidden_item
= proto_tree_add_item(pt
, props
.type_id
, tvb
,
1919 boffset
, 1, ENC_LITTLE_ENDIAN
);
1924 hidden_item
= proto_tree_add_item(pt
, props
.type_id
, tvb
,
1925 boffset
, 1, ENC_ASCII
|ENC_NA
);
1929 hidden_item
= proto_tree_add_item(pt
, props
.type_id
, tvb
,
1930 boffset
, 1, ENC_NA
);
1933 PROTO_ITEM_SET_HIDDEN(hidden_item
);
1936 ti
= proto_tree_add_text(pt
, tvb
, boffset
,
1937 offset
- boffset
+ len
,
1938 textfmt_c
, boffset
, clsstr
, constr
,
1939 tagstr
, tname
, name
, ename
, empty
);
1943 if (props
.value_id
== -1) {
1944 if ( ( ! asn1_full
) && ((props
.flags
& OUT_FLAG_dontshow
) == 0))
1945 ti
= proto_tree_add_text(pt
, tvb
, boffset
,
1946 offset
- boffset
+ len
, "(%s)%s", tname
, name
);
1948 if ( ( ! asn1_full
) && ((props
.flags
& OUT_FLAG_dontshow
) == 0))
1949 ti
= proto_tree_add_none_format(pt
, props
.value_id
, tvb
,
1951 "(%s)%s ~", tname
, name
);
1953 /* don't care about the text */
1954 switch (props
.type
) {
1960 case TBL_ENUMERATED
:
1961 ti
= proto_tree_add_item(pt
, props
.value_id
,
1962 tvb
, boffset
, 1, ENC_LITTLE_ENDIAN
);
1965 case TBL_OCTETSTRING
:
1966 ti
= proto_tree_add_item(pt
, props
.value_id
,
1967 tvb
, boffset
, 1, ENC_ASCII
|ENC_NA
);
1971 ti
= proto_tree_add_item(pt
, props
.value_id
,
1972 tvb
, boffset
, 1, ENC_NA
);
1975 PROTO_ITEM_SET_HIDDEN(ti
);
1977 if (props
.type_id
!= -1){
1978 switch (proto_registrar_get_ftype(props
.type_id
)) {
1994 hidden_item
= proto_tree_add_item(pt
, props
.type_id
,
1995 tvb
, boffset
, 1, ENC_LITTLE_ENDIAN
);
2000 hidden_item
= proto_tree_add_item(pt
, props
.type_id
,
2001 tvb
, boffset
, 1, ENC_ASCII
|ENC_NA
);
2005 hidden_item
= proto_tree_add_item(pt
, props
.type_id
,
2006 tvb
, boffset
, 1, ENC_NA
);
2009 PROTO_ITEM_SET_HIDDEN(hidden_item
);
2014 if (len
== 0) return offset
; /* don't recurse if offset isn't going to change */
2016 if ( ( ! asn1_full
) && (asn1_debug
|| ((props
.flags
& OUT_FLAG_dontshow
) == 0)))
2017 pt2
= proto_item_add_subtree(ti
, ett_seq
[level
]);
2021 offset
= decode_asn1_sequence(tvb
, offset
, len
, pt2
, level
+1); /* recurse */
2023 if ( ( ! asn1_full
) && (asn1_debug
|| ((props
.flags
& OUT_FLAG_dontshow
) == 0)))
2024 proto_item_set_len(ti
, offset
- boffset
);
2028 default: /* fprintf(stderr, "Other\n"); */
2030 ti
= proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
,
2031 textfmt_s
, boffset
, clsstr
, constr
, tagstr
,
2032 tname
, name
, lenbuf
, empty
);
2034 ti
= proto_tree_add_text(pt
, tvb
, boffset
, offset
- boffset
+ len
,
2035 "(%s)%s: %s bytes %s data", tname
, name
,
2038 proto_item_append_text(ti
, " *"); /* indicate default is used */
2039 offset
+= len
; /* skip value ... */
2042 g_free(oname
); /* XXX, memory management ? */
2044 /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
2046 getPDUprops(&props
, soffset
, ASN1_EOI
, 0, 0); /* mark end of this sequence */
2053 /************************************************************************************************/
2054 /* search throug the ASN.1 description for appropriate names */
2055 /************************************************************************************************/
2057 guint lev_limit
= G_MAXINT
;
2059 int icount
= 0; /* item counter */
2062 parse_tt3(tvbuff_t
*tvb
, guint offset
, guint size
, guint level
, GNode
*ptr
)
2065 guint eos
, cls
, con
, tag
, len
, value
;
2067 guchar
*octets
, *bits
, unused
;
2069 GNode
*cur_node
= 0;
2071 eos
= offset
+ size
;
2073 if (level
> lev_limit
)
2076 while(offset
< eos
) {
2077 if (ptr
) /* build pointer tree to all asn1 entities */
2078 cur_node
= g_node_append_data(ptr
, GUINT_TO_POINTER(offset
));
2080 asn1_open(&asn1
, tvb
, offset
);
2081 asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
2082 asn1_close(&asn1
, (gint
*)&offset
); /* mark where we are */
2085 len
= tvb_length_remaining(tvb
, offset
);
2089 case BER_CLASS_UNI
: /* fprintf(stderr, "Universal\n"); */
2091 case BER_UNI_TAG_INTEGER
:
2092 case BER_UNI_TAG_ENUMERATED
:
2093 asn1_int32_value_decode(&asn1
, len
, (gint32
*)&value
); /* read value */
2094 asn1_close(&asn1
, (gint
*)&offset
); /* mark where we are */
2097 case BER_UNI_TAG_BOOLEAN
:
2098 asn1_bool_decode(&asn1
, len
, (gboolean
*)&value
); /* read value */
2099 asn1_close(&asn1
, &offset
); /* mark where we are */
2102 case BER_UNI_TAG_OCTETSTRING
:
2103 case BER_UNI_TAG_NumericString
:
2104 case BER_UNI_TAG_PrintableString
:
2105 case BER_UNI_TAG_TeletexString
:
2106 case BER_UNI_TAG_IA5String
:
2107 case BER_UNI_TAG_GeneralString
:
2108 case BER_UNI_TAG_UTCTime
:
2109 case BER_UNI_TAG_GeneralizedTime
:
2110 asn1_string_value_decode(&asn1
, len
, &octets
); /* read value */
2111 asn1_close(&asn1
, &offset
); /* mark where we are */
2115 case BER_UNI_TAG_BITSTRING
:
2116 asn1_bits_decode(&asn1
, len
, &bits
, &con
, &unused
);
2117 asn1_close(&asn1
, &offset
); /* mark where we are */
2121 case BER_UNI_TAG_SET
:
2122 case BER_UNI_TAG_SEQUENCE
:
2123 if (len
== 0) /* don't recurse if offset isn't going to change */
2126 offset
= parse_tt3(tvb
, offset
, len
, level
+1, cur_node
); /* recurse */
2129 case BER_UNI_TAG_EOC
:
2132 case BER_UNI_TAG_OID
:
2133 asn1_oid_value_decode(&asn1
, len
, &oid
, &con
);
2134 asn1_close(&asn1
, &offset
); /* mark where we are */
2138 case BER_UNI_TAG_NULL
:
2142 case BER_UNI_TAG_ObjectDescriptor
:
2144 case BER_UNI_TAG_REAL
:
2145 case BER_UNI_TAG_VideotexString
:
2146 case BER_UNI_TAG_GraphicString
:
2147 case BER_UNI_TAG_VisibleString
:
2150 if (asn1_verbose
) g_message("%d skip1 %d", offset
, len
);
2151 offset
+= len
; /* skip value ... */
2156 case BER_CLASS_CON
: /* fprintf(stderr, "Context\n"); */
2158 /* defined length, not constructed, must be a string.... */
2159 asn1_string_value_decode(&asn1
, len
, &octets
); /* read value */
2160 asn1_close(&asn1
, &offset
); /* mark where we are */
2163 /* indefinite length or constructed.... must be a sequence .... */
2164 if (len
== 0) /* don't recurse if offset isn't going to change */
2167 offset
= parse_tt3(tvb
, offset
, len
, level
+1, cur_node
); /* recurse */
2171 default: /* fprintf(stderr, "Other\n"); */
2172 if (asn1_verbose
) g_message("%d skip2 %d", offset
, len
);
2173 offset
+= len
; /* skip value ... */
2180 static void showGNodes(GNode
*p
, int n
);
2184 myLeaf(GNode
*node
, gpointer data
)
2187 guint ret
, cls
, con
, tag
, def
, len
;
2188 char *clsstr
, *constr
, *tagstr
;
2192 (void) data
; /* make a reference */
2193 asn1_open(&asn1
, asn1_desc
, (int)node
->data
);
2195 ret
= asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
2197 clsstr
= asn1_cls
[cls
];
2198 constr
= asn1_con
[con
];
2199 if ((cls
== BER_CLASS_UNI
) && ( tag
< 32 )) {
2200 tagstr
= asn1_tag
[tag
];
2202 g_snprintf(tagbuf
, sizeof(tagbuf
), "tag%d", tag
);
2206 g_snprintf(lenbuf
, sizeof(lenbuf
), "%d", len
);
2208 g_snprintf(lenbuf
, sizeof(lenbuf
), "indefinite");
2212 g_message("off=%d: [%s %s %s] len=%s", (int)node
->data
, clsstr
, constr
, tagstr
, lenbuf
);
2220 if (asn1_verbose
) g_message("build GNode tree:");
2221 showGNodes(g_node_first_child(asn1_nodes
), 0);
2222 if (asn1_verbose
) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
2223 g_node_n_nodes(asn1_nodes
, G_TRAVERSE_ALL
),
2224 g_node_max_height (asn1_nodes
),
2225 g_node_n_nodes(asn1_nodes
, G_TRAVERSE_LEAFS
),
2226 g_node_n_nodes(asn1_nodes
, G_TRAVERSE_NON_LEAFS
) );
2228 g_node_traverse(g_node_first_child(asn1_nodes
), G_PRE_ORDER
, G_TRAVERSE_LEAFS
, -1, myLeaf
, 0);
2234 tt_build_tree(void) /* build a GNode tree with all offset's to ASN.1 entities */
2237 g_node_destroy(asn1_nodes
);
2238 asn1_nodes
= g_node_new(0);
2240 parse_tt3(asn1_desc
, 0, tvb_length(asn1_desc
), 0, asn1_nodes
);
2244 /*****************************************************************************************************/
2246 static guint anonCount
; /* for naming anonymous types */
2248 typedef struct _TBLModule TBLModule
;
2249 typedef struct _TBLTypeDef TBLTypeDef
;
2250 typedef struct _TBLTag TBLTag
;
2251 typedef struct _TBLType TBLType
;
2252 typedef struct _TBLTypeRef TBLTypeRef
;
2253 typedef struct _TBLNamedNumber TBLNamedNumber
;
2254 typedef struct _TBLRange TBLRange
;
2262 TBLTYPE_NamedNumber
,
2265 typedef enum _tbl_t tbl_t
;
2266 /* text for 'tbl_t' type for debugging */
2267 static const char *data_types
[] = {
2277 enum _TBLTypeContent_t
{
2279 TBLTYPETYPE_Primitive
,
2280 TBLTYPETYPE_Elements
,
2283 typedef enum _TBLTypeContent_t TBLTypeContent_t
;
2285 struct _TBLNamedNumber
{
2297 struct _TBLTypeRef
{
2313 TBLTypeContent_t content
;
2316 gboolean constraint
;
2319 struct _TBLTypeDef
{
2334 guint totalNumModules
;
2335 guint totalNumTypeDefs
;
2336 guint totalNumTypes
;
2338 guint totalNumStrings
;
2339 guint totalLenStrings
;
2342 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2345 get_asn1_int(guint want_tag
, guint offset
)
2348 guint ret
, cls
, con
, tag
, len
;
2352 /* g_message("%d get_asn1_int", offset); */
2354 asn1_open(&asn1
, asn1_desc
, offset
);
2356 ret
= asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
2357 if (ret
== ASN1_ERR_NOERROR
) {
2358 /* do not check class, both Unversal and Context are OK */
2359 if (con
== ASN1_PRI
&& tag
== want_tag
) {
2361 asn1_uint32_value_decode(&asn1
, len
, &value
);
2364 ret
= ASN1_ERR_LENGTH_NOT_DEFINITE
;
2366 ret
= ASN1_ERR_WRONG_TYPE
;
2368 g_warning("ASN.1 int mismatch at offset %d, %s", offset
, asn1_err_to_str(ret
));
2373 static subid_t
* /* with prepended length ..... */
2374 get_asn1_oid(guint want_tag
, guint offset
)
2377 guint ret
, cls
, con
, tag
, len
;
2381 /* g_message("%d get_asn1_oid", offset); */
2383 asn1_open(&asn1
, asn1_desc
, offset
);
2385 ret
= asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
2386 if (ret
== ASN1_ERR_NOERROR
) {
2387 /* do not check class, both Unversal and Context are OK */
2388 if ((con
== ASN1_PRI
) && (tag
== want_tag
)) {
2390 asn1_oid_value_decode(&asn1
, len
, &oid
, &con
);
2391 oid
= (subid_t
*)g_realloc(oid
, con
+ sizeof(guint
)); /* prepend the length */
2392 memmove(&oid
[1], oid
, con
*sizeof(guint
));
2396 ret
= ASN1_ERR_LENGTH_NOT_DEFINITE
;
2398 ret
= ASN1_ERR_WRONG_TYPE
;
2400 g_warning("ASN.1 oid mismatch at offset %d, %s", offset
, asn1_err_to_str(ret
));
2405 static guchar
* /* 0 terminated string */
2406 get_asn1_string(guint want_tag
, guint offset
)
2409 guint ret
, cls
, con
, tag
, len
;
2413 /* g_message("%d get_asn1_string", offset); */
2415 asn1_open(&asn1
, asn1_desc
, offset
);
2417 ret
= asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
2418 if (ret
== ASN1_ERR_NOERROR
) {
2419 /* do not check class, both Unversal and Context are OK */
2420 if ((con
== ASN1_PRI
) && (tag
== want_tag
)) {
2422 asn1_string_value_decode(&asn1
, len
, &octets
);
2423 octets
= (guchar
*)g_realloc(octets
, len
+1); /* need space for sentinel */
2427 ret
= ASN1_ERR_LENGTH_NOT_DEFINITE
;
2429 ret
= ASN1_ERR_WRONG_TYPE
;
2431 g_warning("ASN.1 string mismatch at offset %d, %s", offset
, asn1_err_to_str(ret
));
2437 get_asn1_uint(guint offset
)
2440 guint ret
, len
, value
;
2442 /* g_message( "%d get_asn1_uint", offset); */
2444 asn1_open(&asn1
, asn1_desc
, offset
);
2446 ret
= asn1_uint32_decode(&asn1
, &value
, &len
);
2448 if (ret
!= ASN1_ERR_NOERROR
) {
2449 g_warning("ASN.1 uint mismatch at offset %d, %s", offset
, asn1_err_to_str(ret
));
2456 check_tag(guint want_tag
, guint offset
)
2459 guint ret
, cls
, con
, tag
, len
;
2462 asn1_open(&asn1
, asn1_desc
, offset
);
2464 ret
= asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
2465 if (ret
== ASN1_ERR_NOERROR
) {
2466 ret
= (tag
== want_tag
) ? TRUE
: FALSE
;
2467 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2470 g_warning("ASN.1 check_tag at offset %d, %s", offset
, asn1_err_to_str(ret
));
2477 constructed(guint offset
)
2480 guint ret
, cls
, con
, tag
, def
, len
;
2482 /* g_message("%d constructed?", offset); */
2484 asn1_open(&asn1
, asn1_desc
, offset
);
2486 ret
= asn1_header_decode(&asn1
, &cls
, &con
, &tag
, &def
, &len
);
2487 if (ret
== ASN1_ERR_NOERROR
) {
2493 /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2500 define_constraint(GNode
*p
, GNode
*q
)
2502 TBLRange
*range
= (TBLRange
*)g_malloc(sizeof(TBLRange
));
2503 g_node_append_data(q
, range
);
2505 range
->type
= TBLTYPE_Range
;
2507 /* g_message("define_constraint %p, %p", p, q); */
2509 p
= g_node_first_child(p
);
2515 range
->from
= get_asn1_int(0, GPOINTER_TO_UINT(p
->data
));
2516 p
= g_node_next_sibling(p
);
2522 range
->to
= get_asn1_int(1, GPOINTER_TO_UINT(p
->data
));
2527 define_namednumber(GNode
*p
, GNode
*q
)
2529 TBLNamedNumber
*num
= (TBLNamedNumber
*)g_malloc(sizeof(TBLNamedNumber
));
2530 g_node_append_data(q
, num
);
2532 num
->type
= TBLTYPE_NamedNumber
;
2534 /* g_message("define_namednumber %p, %p", p, q); */
2536 p
= g_node_first_child(p
);
2542 num
->name
= get_asn1_string(0, GPOINTER_TO_UINT(p
->data
));
2543 p
= g_node_next_sibling(p
);
2549 num
->value
= get_asn1_int(1, GPOINTER_TO_UINT(p
->data
));
2553 define_typeref(GNode
*p
, GNode
*q
)
2555 TBLTypeRef
*ref
= (TBLTypeRef
*)g_malloc(sizeof(TBLTypeRef
));
2556 g_node_append_data(q
, ref
);
2558 ref
->type
= TBLTYPE_TypeRef
;
2560 /* g_message("define_typeref %p, %p", p, q); */
2562 p
= g_node_first_child(p
);
2568 ref
->typeDefId
= get_asn1_uint(GPOINTER_TO_UINT(p
->data
));
2569 p
= g_node_next_sibling(p
);
2575 ref
->implicit
= get_asn1_int(BER_UNI_TAG_BOOLEAN
, GPOINTER_TO_UINT(p
->data
));
2579 define_tag(GNode
*p
, GNode
*q
)
2581 TBLTag
*type
= (TBLTag
*)g_malloc(sizeof(TBLTag
));
2582 g_node_append_data(q
, type
);
2584 type
->type
= TBLTYPE_Tag
;
2586 /* g_message("define_tag %p, %p", p, q); */
2588 p
= g_node_first_child(p
);
2594 type
->tclass
= get_asn1_int(BER_UNI_TAG_ENUMERATED
, GPOINTER_TO_UINT(p
->data
));
2595 p
= g_node_next_sibling(p
);
2601 type
->code
= get_asn1_int(BER_UNI_TAG_INTEGER
, GPOINTER_TO_UINT(p
->data
));
2606 define_type(GNode
*p
, GNode
*q
)
2609 TBLType
*type
= (TBLType
*)g_malloc(sizeof(TBLType
));
2611 GNode
*t
= g_node_append_data(q
, type
);
2613 type
->type
= TBLTYPE_Type
;
2615 /* g_message("define_type %p, %p", p, q); */
2617 type
->typeId
= get_asn1_int(0, GPOINTER_TO_UINT(p
->data
));
2618 p
= g_node_next_sibling(p
);
2620 type
->optional
= get_asn1_int(1, GPOINTER_TO_UINT(p
->data
));
2621 p
= g_node_next_sibling(p
);
2623 if (check_tag(2, GPOINTER_TO_UINT(p
->data
))) { /* optional, need empty node if not there ?*/
2624 r
= g_node_first_child(p
);
2627 r
= g_node_next_sibling(r
);
2629 p
= g_node_next_sibling(p
);
2632 if (!check_tag(3, GPOINTER_TO_UINT(p
->data
))) {
2633 g_warning("expect tag 3, ERROR");
2635 r
= g_node_first_child(p
);
2637 type
->content
= TBLTYPETYPE_None
;
2638 if (check_tag(0, GPOINTER_TO_UINT(r
->data
))) type
->content
= TBLTYPETYPE_Primitive
;
2639 if (check_tag(1, GPOINTER_TO_UINT(r
->data
))) type
->content
= TBLTYPETYPE_Elements
;
2640 if (check_tag(2, GPOINTER_TO_UINT(r
->data
))) type
->content
= TBLTYPETYPE_TypeRef
;
2641 switch(type
->content
) {
2642 case TBLTYPETYPE_Primitive
:
2644 case TBLTYPETYPE_Elements
:
2645 r
= g_node_first_child(r
);
2647 define_type(g_node_first_child(r
), t
);
2648 r
= g_node_next_sibling(r
);
2651 case TBLTYPETYPE_TypeRef
:
2652 define_typeref(r
, t
);
2654 case TBLTYPETYPE_None
:
2655 g_warning("expected a contents choice, error");
2658 p
= g_node_next_sibling(p
);
2660 type
->fieldName
= 0;
2661 type
->anonymous
= FALSE
;
2662 if (p
&& check_tag(4, GPOINTER_TO_UINT(p
->data
))) {
2663 type
->fieldName
= get_asn1_string(4, GPOINTER_TO_UINT(p
->data
));
2664 p
= g_node_next_sibling(p
);
2666 type
->anonymous
= TRUE
;
2669 type
->constraint
= FALSE
;
2670 if (p
&& check_tag(5, GPOINTER_TO_UINT(p
->data
))) {
2671 type
->constraint
= TRUE
;
2672 define_constraint(p
, t
);
2673 p
= g_node_next_sibling(p
);
2676 if (p
&& check_tag(6, GPOINTER_TO_UINT(p
->data
))) {
2677 r
= g_node_first_child(p
);
2679 define_namednumber(r
, t
);
2680 r
= g_node_next_sibling(r
);
2686 define_typedef(GNode
*p
, GNode
*q
)
2688 TBLTypeDef
*type_def
= (TBLTypeDef
*)g_malloc(sizeof(TBLTypeDef
));
2690 GNode
*t
= g_node_append_data(q
, type_def
);
2692 /* g_message("define_typedef %p, %p", p, q); */
2694 type_def
->type
= TBLTYPE_TypeDef
;
2696 p
= g_node_first_child(p
);
2702 type_def
->typeDefId
= get_asn1_uint(GPOINTER_TO_UINT(p
->data
));
2703 p
= g_node_next_sibling(p
);
2709 type_def
->typeName
= get_asn1_string(BER_UNI_TAG_PrintableString
, GPOINTER_TO_UINT(p
->data
));
2710 p
= g_node_next_sibling(p
);
2716 define_type(g_node_first_child(p
), t
);
2717 p
= g_node_next_sibling(p
);
2719 type_def
->isPdu
= (p
!= 0); /* true if it exists, value ignored */
2723 define_module(GNode
*p
, GNode
*q
)
2725 TBLModule
*module
= (TBLModule
*)g_malloc(sizeof(TBLModule
));
2727 GNode
*m
= g_node_append_data(q
, module
);
2729 /* g_message("define_module %p %p", p, q); */
2731 module
->type
= TBLTYPE_Module
;
2733 p
= g_node_first_child(p
);
2739 module
->name
= get_asn1_string(0, GPOINTER_TO_UINT(p
->data
));
2740 p
= g_node_next_sibling(p
);
2743 if (check_tag(1, GPOINTER_TO_UINT(p
->data
))) { /* optional */
2744 module
->id
= get_asn1_oid(1, GPOINTER_TO_UINT(p
->data
));
2745 p
= g_node_next_sibling(p
);
2748 module
->isUseful
= get_asn1_int(2, GPOINTER_TO_UINT(p
->data
));
2749 p
= g_node_next_sibling(p
);
2751 p
= g_node_first_child(p
);
2753 define_typedef(p
, m
);
2754 p
= g_node_next_sibling(p
);
2758 typedef struct _SearchDef SearchDef
;
2765 is_typedef(GNode
*node
, gpointer data
)
2767 TBLTypeDef
*d
= (TBLTypeDef
*)node
->data
;
2768 SearchDef
*s
= (SearchDef
*)data
;
2770 if (d
== 0) return FALSE
;
2771 if (d
->type
!= TBLTYPE_TypeDef
) return FALSE
;
2772 if (strcmp(s
->key
, d
->typeName
) == 0) {
2779 typedef struct _TypeRef TypeRef
;
2785 GNode
*pdu
; /* location in PDU descriptor tree */
2786 guint level
; /* recursion counter */
2788 GPtrArray
*refs
; /* pointers to PDUinfo structures teferencing this entry */
2791 typedef struct _NameDefs NameDefs
;
2797 #define ALLOC_INCR 4
2798 #define CLASSREF (BER_CLASS_PRI+1)
2801 is_named(GNode
*node
, gpointer data
)
2803 TBLNamedNumber
*num
= (TBLNamedNumber
*)node
->data
;
2804 NameDefs
*n
= (NameDefs
*)data
;
2807 if (num
== 0) return FALSE
;
2808 if (num
->type
!= TBLTYPE_NamedNumber
) return FALSE
;
2810 if (num
->value
>= n
->max
) { /* need larger array */
2812 n
->max
= num
->value
+ ALLOC_INCR
;
2813 n
->info
= (TypeRef
*)g_realloc(n
->info
, n
->max
* sizeof(TypeRef
));
2814 memset(&n
->info
[oldmax
], 0, (n
->max
- oldmax
) * sizeof(TypeRef
));
2816 if (num
->value
> n
->used
) /* track max used value, there may be holes... */
2817 n
->used
= num
->value
;
2819 n
->info
[num
->value
].name
= num
->name
;
2825 index_typedef(GNode
*node
, gpointer data
)
2827 TBLTypeDef
*d
= (TBLTypeDef
*)node
->data
;
2828 NameDefs
*n
= (NameDefs
*)data
;
2833 if (d
== 0) return FALSE
;
2834 if (d
->type
!= TBLTYPE_TypeDef
) return FALSE
;
2836 if (d
->typeDefId
>= n
->max
) { /* need larger array */
2838 n
->max
= d
->typeDefId
+ ALLOC_INCR
;
2839 n
->info
= (TypeRef
*)g_realloc(n
->info
, n
->max
* sizeof(TypeRef
));
2840 memset(&n
->info
[oldmax
], 0, (n
->max
- oldmax
) * sizeof(TypeRef
));
2842 if (d
->typeDefId
> n
->used
) /* track max used value, there may be holes... */
2843 n
->used
= d
->typeDefId
;
2845 t
= &(n
->info
[d
->typeDefId
]);
2846 t
->name
= d
->typeName
;
2848 t
->refs
= g_ptr_array_new(); /* collect references here */
2849 node
= g_node_first_child(node
); /* the real type */
2850 tag
= (TBLTag
*)node
->data
;
2851 if ((tag
->type
== TBLTYPE_Type
) && (((TBLType
*)(void *)tag
)->typeId
== TBL_CHOICE
)) {
2852 /* no reasonable default... ! */
2853 t
->defclass
= 3; /* Private .... */
2854 t
->deftag
= 9999; /* a random value */
2856 node
= g_node_first_child(node
); /* the default tag */
2857 tag
= (TBLTag
*)node
->data
;
2860 t
->defclass
= tag
->tclass
;
2861 t
->deftag
= tag
->code
;
2863 case TBLTYPE_TypeRef
: /* take values from another one, may not be defined yet... */
2864 t
->defclass
= CLASSREF
; /* invalid class.. */
2865 t
->deftag
= ((TBLTypeRef
*)tag
)->typeDefId
;
2868 g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2869 data_types
[tag
->type
]);
2870 t
->defclass
= 3; /* Private .... */
2871 t
->deftag
= 9998; /* another random value */
2879 static TypeRef
*typeDef_names
= 0;
2880 static guint numTypedefs
= 0;
2883 free_node_data(GNode
*node
, gpointer data _U_
)
2890 get_values(void) /* collect values from ASN.1 tree */
2891 /* coded according to the tbl.asn1 description of snacc output */
2892 { /* This routine does not leave references to the tvbuff or */
2893 /* to the asn1_nodes, both can be freed by the caller of this.*/
2899 const char *t
, *s
, *E
;
2900 static char missing
[] = " **missing** ";
2902 if (asn1_verbose
) g_message("interpreting tree");
2903 typeDef_names
= 0; /* just forget allocated any data .... */
2906 g_node_traverse(data_nodes
, G_POST_ORDER
, G_TRAVERSE_ALL
, -1,
2907 free_node_data
, NULL
);
2908 g_node_destroy(data_nodes
);
2911 data_nodes
= g_node_new(0);
2913 p
= g_node_first_child(asn1_nodes
); /* top of the data tree */
2915 p
= g_node_first_child(p
);
2917 TT
.totalNumModules
= get_asn1_uint(GPOINTER_TO_UINT(p
->data
));
2918 p
= g_node_next_sibling(p
);
2920 TT
.totalNumTypeDefs
= get_asn1_uint(GPOINTER_TO_UINT(p
->data
));
2921 p
= g_node_next_sibling(p
);
2923 TT
.totalNumTypes
= get_asn1_uint(GPOINTER_TO_UINT(p
->data
));
2924 p
= g_node_next_sibling(p
);
2926 TT
.totalNumTags
= get_asn1_uint(GPOINTER_TO_UINT(p
->data
));
2927 p
= g_node_next_sibling(p
);
2929 TT
.totalNumStrings
= get_asn1_uint(GPOINTER_TO_UINT(p
->data
));
2930 p
= g_node_next_sibling(p
);
2932 TT
.totalLenStrings
= get_asn1_uint(GPOINTER_TO_UINT(p
->data
));
2933 p
= g_node_next_sibling(p
);
2935 p
= g_node_first_child(p
);
2937 define_module(p
, data_nodes
);
2938 p
= g_node_next_sibling(p
);
2941 /* g_message("finished with tree"); */
2943 if (!tbl_types_verified
) { /* verify snacc TBLTypeId contents */
2944 sd
.key
= "TBLTypeId";
2946 g_node_traverse(data_nodes
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, is_typedef
, (gpointer
)&sd
);
2947 if (asn1_verbose
) g_message("%s %sfound, %p", sd
.key
, sd
.here
?empty
:"not ", (void *)sd
.here
);
2951 nd
.info
= (TypeRef
*)g_malloc0(nd
.max
* sizeof(TypeRef
));
2952 g_node_traverse(sd
.here
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, is_named
,
2954 if (asn1_verbose
) g_message("tbltypenames: max=%d, info=%p", nd
.max
, (void *)nd
.info
);
2956 for (i
=0; i
<=nd
.used
; i
++) { /* we have entries in addition to snacc's */
2959 s
= nd
.info
[i
].name
;
2960 if (s
== 0) s
= missing
;
2961 if (g_strcmp(t
, s
) == 0) { /* OK ! */
2965 E
= ", X with errors X";
2967 if (asn1_verbose
) g_message(" %c %2d %s %s", X
, i
, s
, t
);
2969 if (asn1_verbose
) g_message("OK, TBLTypeId's index verified%s", E
);
2971 tbl_types_verified
= TRUE
;
2973 /* build table with typedef names */
2976 nd
.info
= (TypeRef
*)g_malloc0(nd
.max
* sizeof(TypeRef
));
2977 g_node_traverse(data_nodes
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, index_typedef
, (gpointer
)&nd
);
2978 if (asn1_verbose
) g_message("tbltypedefs: max=%d, info=%p", nd
.max
, (void *)nd
.info
);
2980 for (i
=0; i
<=nd
.used
; i
++) { /* show what we have in the index now */
2981 TypeRef
*ref
= &(nd
.info
[i
]);
2984 t
= ref
->name
= missing
;
2985 if (asn1_verbose
) g_message(" %3d %s", i
, t
);
2987 if (asn1_verbose
) g_message(" %3d %s, %c%d", i
, t
,
2988 tag_class
[ref
->defclass
], ref
->deftag
);
2990 if (ref
->pdu
) { /* should be 0 */
2991 if (asn1_verbose
) g_message("* %3d %s pdu=%p", i
, t
, (void *)ref
->pdu
);
2994 typeDef_names
= nd
.info
;
2996 if (asn1_verbose
) g_message("OK, %d TBLTypeDef's index set up", numTypedefs
);
3001 showGNode(GNode
*p
, int n
)
3004 const char *fn
, *s
= empty
;
3006 n
*=2; /* 2 spaces per level */
3007 if (p
->data
) { /* show value ... */
3008 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
3009 switch (((TBLTag
*)p
->data
)->type
) {
3010 case TBLTYPE_Module
: {
3011 TBLModule
*m
= (TBLModule
*)p
->data
;
3013 g_message("%*smodule %s%s", n
, empty
, m
->name
,
3014 m
->isUseful
? ", useful" : empty
);
3017 case TBLTYPE_TypeDef
: {
3018 TBLTypeDef
*t
= (TBLTypeDef
*)p
->data
;
3020 g_message("%*stypedef %d %s%s", n
, empty
, t
->typeDefId
, t
->typeName
,
3021 t
->isPdu
? ", isPDU" : empty
);
3024 case TBLTYPE_Type
: {
3025 TBLType
*t
= (TBLType
*)p
->data
;
3028 /* typeId is a value from enum TBLTypeId */
3029 fn
= TBLTYPE(t
->typeId
);
3030 if (asn1_verbose
) g_message("%*stype %d[%s]%s [%s]", n
, empty
, t
->typeId
, fn
,
3031 t
->optional
? " opt" : empty
, s
);
3035 TBLTag
*t
= (TBLTag
*)p
->data
;
3036 if ((t
->tclass
== BER_CLASS_UNI
) && (t
->code
< 32))
3037 s
= asn1_tag
[t
->code
];
3038 if (asn1_verbose
) g_message("%*stag %c%d[%s]", n
, empty
,
3039 tag_class
[t
->tclass
], t
->code
, s
);
3042 case TBLTYPE_NamedNumber
: {
3043 TBLNamedNumber
*nn
= (TBLNamedNumber
*)p
->data
;
3044 if (asn1_verbose
) g_message("%*snamednumber %2d %s", n
, empty
,
3045 nn
->value
, nn
->name
);
3048 case TBLTYPE_Range
: {
3049 TBLRange
*r
= (TBLRange
*)p
->data
;
3050 if (asn1_verbose
) g_message("%*srange %d .. %d", n
, empty
,
3054 case TBLTYPE_TypeRef
: {
3055 TBLTypeRef
*r
= (TBLTypeRef
*)p
->data
;
3057 s
= typeDef_names
[r
->typeDefId
].name
;
3058 if (asn1_verbose
) g_message("%*styperef %d[%s]%s", n
, empty
,
3059 r
->typeDefId
, s
, r
->implicit
? ", implicit" : empty
);
3063 TBLTag
*x
= (TBLTag
*)p
->data
;
3064 if (asn1_verbose
) g_message("%*s--default-- type=%d", n
, empty
, x
->type
);
3068 } else { /* just show tree */
3070 g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
3071 n
, empty
, (void *)p
, (void *)p
->data
, (void *)p
->next
, (void *)p
->prev
, (void *)p
->parent
, (void *)p
->children
);
3076 showGNodes(GNode
*p
, int n
)
3080 showGNodes(p
->children
, n
+1);
3081 showGNodes(p
->next
, n
);
3085 static void showGenv(GNode
*p
, int n
, int m
)
3091 if (asn1_verbose
) g_message("%*s.....", n
*2, empty
);
3095 for(i
=0; p
&& (i
< 3); p
= p
->next
, i
++) {
3097 showGenv(p
->children
, n
+1, m
);
3099 if (p
&& asn1_verbose
) g_message("%*s.....", n
*2, empty
);
3105 debug_dump_TT(void) /* dump contents of TT struct, for debugging */
3108 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
3110 TT
.totalNumTypeDefs
,
3114 TT
.totalLenStrings
);
3118 my_log_handler(const gchar
*log_domain
, GLogLevelFlags log_level
,
3119 const gchar
*message
, gpointer user_data
)
3121 static FILE* logf
= 0;
3122 static char eol
[] = "\r\n";
3124 (void) log_domain
; (void) log_level
; (void) user_data
; /* make references */
3126 if (logf
== NULL
&& asn1_logfile
) {
3127 logf
= ws_fopen(asn1_logfile
, "w");
3130 fputs(message
, logf
);
3132 fflush(logf
); /* debugging ... */
3137 read_asn1_type_table(const char *filename
)
3143 struct stat file_stat
;
3144 static guint mylogh
= 0;
3146 if ((filename
== 0) || (strlen(filename
) == 0))
3147 return; /* no filename provided */
3149 f
= ws_fopen(filename
, "rb");
3152 * Ignore "file not found" errors if it's the old default
3153 * ASN.1 file name, as we never shipped such a file.
3154 * Also, on Win32, ignore the earlier default, which
3155 * had a "/" rather than a "\" as the last pathname
3159 if (strcmp(filename
, bad_separator_old_default_asn1_filename
) != 0)
3161 if ((strcmp(filename
, old_default_asn1_filename
) != 0) || errno
!= ENOENT
)
3162 report_open_failure(filename
, errno
, FALSE
);
3165 ret
= fstat(fileno(f
), &file_stat
);
3167 size
= (int)file_stat
.st_size
;
3169 if (asn1_verbose
) g_message("file %s is empty or size is unknown, ignored", filename
);
3173 if (asn1_verbose
) g_message("reading %d bytes from %s", size
, filename
);
3175 data
= (guchar
*)g_malloc(size
);
3176 if (fread(data
, size
, 1, f
) < 1) {
3177 g_warning("error reading %s, %s", filename
, g_strerror(errno
));
3182 /* ***** from the time when logging was just in a console... *****
3183 * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
3184 * " Sleep 5 sec...");
3189 g_message("logging to file %s", asn1_logfile
);
3192 mylogh
= g_log_set_handler (NULL
, (GLogLevelFlags
)(G_LOG_LEVEL_MASK
| G_LOG_FLAG_FATAL
3193 | G_LOG_FLAG_RECURSION
), my_log_handler
, NULL
);
3197 asn1_desc
= tvb_new_real_data(data
, size
, size
);
3200 if (asn1_verbose
) g_message("read %d items from %s", icount
, filename
);
3208 g_node_destroy(asn1_nodes
);
3211 tvb_free(asn1_desc
);
3217 showGNodes(data_nodes
, 0);
3223 /* XXX - Shoudn't we make sure we're not dereferencing a NULL pointer here? */
3224 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
3225 g_warning("**** unexpected type %s, want %s, at line %d", \
3226 data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
3230 save_reference(PDUinfo
*p
)
3237 g_ptr_array_add(typeDef_names
[i
].refs
, (gpointer
)p
);
3241 tbl_type(gint n
, GNode
*pdu
, GNode
*list
, guint fullindex
);
3245 /* evaluate typeref, pointer to current pdu node and typedef */
3247 tbl_typeref(gint n
, GNode
*pdu
, GNode
*tree
, guint fullindex
)
3250 PDUinfo
*p
= (PDUinfo
*)pdu
->data
, *p1
;
3256 if (n
> 40) { /* don't believe this....! ...... stop recursion ...... */
3257 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
3261 CHECKTYPE(tree
, TBLTYPE_TypeDef
);
3263 if (asn1_verbose
) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n
*2, empty
,
3264 p
->name
, TBLTYPE(p
->type
), tag_class
[p
->tclass
], p
->tag
);
3266 p
->typenum
= ((TBLTypeDef
*)tree
->data
)->typeDefId
; /* name of current type */
3267 p
->flags
|= PDU_TYPEDEF
;
3269 tree
= g_node_first_child(tree
); /* move to its underlying type */
3270 CHECKTYPE(tree
, TBLTYPE_Type
);
3271 p
->type
= ((TBLType
*)tree
->data
)->typeId
;
3273 q
= g_node_first_child(tree
); /* the tag of this type entry ... is optional... */
3274 if (((TBLTag
*)q
->data
)->type
== TBLTYPE_Tag
) {
3275 if ((p
->flags
& PDU_IMPLICIT
) == 0) { /* not implicit, use this tag */
3279 /* XXX -- hack -- hack -- hack -- hack -- hack --
3280 * only change tag when class+tag == EOC,
3281 * or class is a reference,
3282 * or new class is not universal.
3284 if ( ((xcls
|xtag
) == 0) || (xcls
== CLASSREF
) ||
3285 (((TBLTag
*)q
->data
)->tclass
!= BER_CLASS_UNI
) ) {
3286 p
->tclass
= ((TBLTag
*)q
->data
)->tclass
;
3287 p
->tag
= ((TBLTag
*)q
->data
)->code
;
3289 g_message("%*s*change typeref tag from %c%d to %c%d",
3293 tag_class
[p
->tclass
],
3297 g_message("%*sNOT changing tag from %c%d to %c%d",
3301 tag_class
[((TBLTag
*)q
->data
)->tclass
],
3302 ((TBLTag
*)q
->data
)->code
);
3309 if (p
->tclass
==CLASSREF
)
3310 g_snprintf(ss
, 128, ", CLASSREF %d", p
->tag
);
3311 if (asn1_verbose
) g_message("%*sno typeref tag%s", n
*2, empty
, ss
);
3313 if (p
->tclass
==CLASSREF
) {
3316 /* CLASSREF....., get it defined using type of the reference */
3318 /* p->basetype may be -1 .... ? XXX */
3321 tr
= &typeDef_names
[i
];
3323 g_message("%*s*refer2 to type#%d %s, %p", n
*2, empty
,
3324 p
->tag
, tr
->name
, (void *)tr
->pdu
);
3326 tbl_typeref(n
+1, pdu
, tr
->type
, fullindex
);
3333 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n
*2, empty
, p
->typenum
,
3334 p
->name
, p
->asn1typename
, (void *)p
, TBLTYPE(p
->type
), tag_class
[p
->tclass
], p
->tag
);
3338 case TBL_ENUMERATED
:
3339 /* names do not have a fullname */
3340 if (asn1_verbose
) g_message("%*s*collection T %s", n
*2, empty
, p
->name
);
3341 /* read the enumeration [save min-max somewhere ?] */
3342 p
->value_hf
.hfinfo
.type
= tbl_types_wireshark
[p
->type
]; /* XXX change field type... */
3343 p
->value_hf
.hfinfo
.display
= tbl_display_wireshark
[p
->type
];
3345 proto_register_field_array(proto_asn1
, &(p
->value_hf
) , 1);
3350 g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3351 p
->mytype
, p
->typenum
, p
->basetype
, p
->flags
, p
->asn1typename
,
3352 p
->name
, p
->fullname
,
3353 tbl_types_wireshark_txt
[p
->type
], p
->value_id
);
3356 while((q
= g_node_next_sibling(q
))) {
3357 CHECKTYPE(q
, TBLTYPE_NamedNumber
);
3358 p
= (PDUinfo
*)g_malloc0(sizeof(PDUinfo
));
3360 p
->type
= TBL_ENUMERATED
;
3361 p
->name
= (((TBLNamedNumber
*)q
->data
)->name
);
3362 p
->tag
= (((TBLNamedNumber
*)q
->data
)->value
);
3363 p
->flags
= PDU_NAMEDNUM
;
3364 if (asn1_verbose
) g_message("%*s %3d %s", n
*2, empty
, p
->tag
, p
->name
);
3365 g_node_append_data(pdu
, p
);
3368 /* list all enum values in the field structure for matching */
3369 p1
->value_hf
.hfinfo
.strings
= v
= (value_string
*)g_malloc0((nvals
+1) * sizeof(value_string
));
3370 q
= g_node_first_child(pdu
);
3373 p
= (PDUinfo
*)q
->data
;
3374 v
[nvals
].value
= p
->tag
;
3375 v
[nvals
].strptr
= p
->name
;
3376 /* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
3378 q
= g_node_next_sibling(q
);
3380 /* last entry is already initialized to { 0, NULL } */
3385 if (p
->value_id
== -1) { /* not yet registered ..... */
3386 p
->value_hf
.hfinfo
.type
= tbl_types_wireshark
[p
->type
];
3387 p
->value_hf
.hfinfo
.display
= tbl_display_wireshark
[p
->type
];
3388 proto_register_field_array(proto_asn1
, &(p
->value_hf
) , 1);
3393 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3394 p
->mytype
, p
->typenum
, p
->basetype
, p
->flags
, p
->asn1typename
,
3395 p
->name
, p
->fullname
,
3396 tbl_types_wireshark_txt
[p
->type
], p
->value_id
);
3398 tbl_type(n
, pdu
, q
, fullindex
);
3402 if (p
->value_id
== -1) { /* not yet registered ..... */
3403 p
->value_hf
.hfinfo
.type
= tbl_types_wireshark
[p
->type
];
3404 p
->value_hf
.hfinfo
.display
= tbl_display_wireshark
[p
->type
];
3405 proto_register_field_array(proto_asn1
, &(p
->value_hf
) , 1);
3410 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3411 p
->mytype
, p
->typenum
, p
->basetype
, p
->flags
, p
->asn1typename
,
3412 p
->name
, p
->fullname
,
3413 tbl_types_wireshark_txt
[p
->type
], p
->value_id
);
3415 tbl_type(n
, pdu
, g_node_next_sibling(q
), fullindex
);
3420 tbl_type(gint n
, GNode
*pdu
, GNode
*list
, guint fullindex
) /* indent, pdu, source type node list */
3428 if (n
> 40) { /* don't believe this....! ...... stop recursion ...... */
3429 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3433 /* showGenv(list, n, n+1); */
3436 pdu1
= pdu
; /* save start location for append */
3437 while (list
) { /* handle all entries */
3439 g_message("%*s+handle a %s, list=%p", n
*2, empty
,
3440 data_types
[((TBLTag
*)list
->data
)->type
], (void *)list
);
3442 if (((TBLTag
*)list
->data
)->type
== TBLTYPE_Range
) { /* ignore this ..... */
3443 list
= g_node_next_sibling(list
);
3444 if (asn1_verbose
) g_message("%*s*skip range", n
*2, empty
);
3449 /******* change to positive comparation, but leave comment for reference
3450 * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3451 * CHECKTYPE(list, TBLTYPE_Type);
3454 if (((TBLTag
*)list
->data
)->type
== TBLTYPE_Type
) {
3455 CHECKTYPE(list
, TBLTYPE_Type
);
3457 p
= (PDUinfo
*)g_malloc0(sizeof(PDUinfo
));
3458 pdu
= g_node_append_data(pdu1
, p
);
3460 p
->type
= ((TBLType
*)list
->data
)->typeId
;
3461 p
->asn1typename
= tbl_types_asn1
[p
->type
]; /* the default type */
3464 p
->basetype
= ((PDUinfo
*)pdu1
->data
)->typenum
;
3465 p
->flags
= PDUinfo_initflags
;
3466 p
->flags
|= (((TBLType
*)list
->data
)->anonymous
? PDU_ANONYMOUS
: 0);
3467 p
->flags
|= (((TBLType
*)list
->data
)->optional
? PDU_OPTIONAL
: 0);
3469 if (((TBLType
*)list
->data
)->fieldName
== 0) { /* no name assigned */
3470 /* assign an anonymous name [XXX refer to parent asn1typename...] */
3471 ((TBLType
*)list
->data
)->fieldName
=
3472 g_strdup_printf("anon%d", anonCount
++);
3474 p
->name
= ((TBLType
*)list
->data
)->fieldName
;
3477 ni
+= g_snprintf(&fieldname
[ni
], sizeof(fieldname
) - ni
, ".%s", p
->name
);
3478 p
->fullname
= g_strdup(fieldname
);
3480 /* initialize field info */
3483 p
->value_hf
.p_id
= &(p
->value_id
);
3484 p
->value_hf
.hfinfo
.name
= p
->fullname
;
3485 p
->value_hf
.hfinfo
.abbrev
= p
->fullname
;
3486 p
->value_hf
.hfinfo
.type
= tbl_types_wireshark
[p
->type
];
3487 p
->value_hf
.hfinfo
.display
= tbl_display_wireshark
[p
->type
];
3488 p
->value_hf
.hfinfo
.blurb
= p
->fullname
;
3489 /* all the other fields are already 0 ! */
3491 if (p
->type
< TBL__SIMPLE
) {
3492 /* only register fields with a value here, postpone others */
3493 proto_register_field_array(proto_asn1
, &(p
->value_hf
) , 1);
3498 g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3499 p
->mytype
, p
->typenum
, p
->basetype
, p
->flags
,
3500 p
->asn1typename
, p
->name
, p
->fullname
,
3501 tbl_types_wireshark_txt
[p
->type
], p
->value_id
);
3504 q
= g_node_first_child(list
);
3506 p
= (PDUinfo
*)pdu
->data
;
3511 if (asn1_verbose
) g_message("%*s*switch %s %s", n
*2, empty
, p
->name
, TBLTYPE(p
->type
));
3516 case TBL_OCTETSTRING
:
3520 CHECKTYPE(q
, TBLTYPE_Tag
);
3521 p
->tclass
= ((TBLTag
*)q
->data
)->tclass
;
3522 p
->tag
= ((TBLTag
*)q
->data
)->code
;
3526 case TBL_ENUMERATED
:
3527 CHECKTYPE(q
, TBLTYPE_Tag
);
3528 p
->tclass
= ((TBLTag
*)q
->data
)->tclass
;
3529 p
->tag
= ((TBLTag
*)q
->data
)->code
;
3530 if (asn1_verbose
) g_message("%*s*collection %s", n
*2, empty
, p
->name
);
3531 /* read the enumeration [save min-max somewhere ?] */
3534 while((q
= g_node_next_sibling(q
))) {
3535 CHECKTYPE(q
, TBLTYPE_NamedNumber
);
3536 p
= (PDUinfo
*)g_malloc0(sizeof(PDUinfo
));
3538 p
->type
= TBL_ENUMERATED
;
3539 p
->name
= (gchar
*)(((TBLNamedNumber
*)q
->data
)->name
);
3540 p
->tag
= (((TBLNamedNumber
*)q
->data
)->value
);
3541 p
->flags
= PDU_NAMEDNUM
;
3542 if (asn1_verbose
) g_message("%*s %3d %s", n
*2, empty
, p
->tag
, p
->name
);
3543 g_node_append_data(pdu
, p
);
3546 /* list all enum values in the field structure for matching */
3547 p1
->value_hf
.hfinfo
.strings
= v
= (value_string
*)g_malloc0((nvals
+1) * sizeof(value_string
));
3548 q
= g_node_first_child(pdu
);
3551 p
= (PDUinfo
*)q
->data
;
3552 v
[nvals
].value
= p
->tag
;
3553 v
[nvals
].strptr
= p
->name
;
3554 /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3556 q
= g_node_next_sibling(q
);
3558 /* last entry is already initialized to { 0, NULL } */
3564 case TBL_SEQUENCEOF
:
3567 CHECKTYPE(q
, TBLTYPE_Tag
);
3568 q
= g_node_first_child(list
);
3569 tbl_type(n
+1, pdu
, q
, ni
);
3572 case TBL_TYPEREF
: { /* may have a tag ... */
3578 if ( ((TBLTag
*)q
->data
)->type
== TBLTYPE_Tag
) {
3579 if ((p
->flags
& PDU_IMPLICIT
) == 0) { /* not implicit, use this tag */
3580 p
->tclass
= ((TBLTag
*)q
->data
)->tclass
;
3581 p
->tag
= ((TBLTag
*)q
->data
)->code
;
3583 g_message("%*s*insert type tag %c%d", n
*2, empty
,
3584 tag_class
[p
->tclass
], p
->tag
);
3586 q
= g_node_next_sibling(q
);
3587 } else { /* use default tag for this type */
3588 tr
= &typeDef_names
[((TBLTypeRef
*)q
->data
)->typeDefId
];
3589 if ((((p
->flags
& PDU_IMPLICIT
) == 0) && (tr
->defclass
!= BER_CLASS_UNI
)) ||
3590 ((p
->tclass
| p
->tag
) == 0 )) {
3591 /* not implicit, use this tag */
3592 p
->tclass
= tr
->defclass
;
3593 p
->tag
= tr
->deftag
;
3594 if (asn1_verbose
) g_message("%*s*set tag %c%d", n
*2, empty
,
3595 tag_class
[p
->tclass
], p
->tag
);
3598 CHECKTYPE(q
, TBLTYPE_TypeRef
);
3599 i
= ((TBLTypeRef
*)q
->data
)->typeDefId
;
3601 tr
= &typeDef_names
[i
];
3603 g_message("%*s*type#%d %s, %p", n
*2, empty
, i
, tr
->name
, (void *)tr
->pdu
);
3604 p
->asn1typename
= tr
->name
;
3606 if (tr
->defclass
== CLASSREF
) {
3608 tr
->pdu
= pdu
; /* remember this reference */
3610 tr
= &typeDef_names
[i
];
3612 g_message("%*s*refer to type#%d %s, %p", n
*2, empty
,
3613 i
, tr
->name
, (void *)tr
->pdu
);
3615 /* evaluate reference if not done before or when below recursion limit */
3616 if ((tr
->pdu
== 0) || (tr
->level
< type_recursion_level
)) {
3619 tr
->pdu
= pdu
; /* save for references we leave */
3621 p
->flags
|= ((TBLTypeRef
*)q
->data
)->implicit
? PDU_IMPLICIT
: 0;
3623 g_message("%*s*typeref %s > %s%s at %p", n
*2, empty
,
3625 ((TBLTypeRef
*)q
->data
)->implicit
?"implicit ":empty
,
3628 tbl_typeref(n
+1, pdu
, tr
->type
, ni
);
3632 g_message("%*s*typeref %s > %s already at %p", n
*2, empty
,
3633 p
->name
, tr
->name
, (void *)tr
->pdu
);
3634 p
->flags
|= PDU_REFERENCE
;
3635 p
->reference
= tr
->pdu
;
3640 g_warning("**** unknown tbl-type %d at line %d", p
->type
, __LINE__
);
3645 g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3646 n
*2, empty
, p
->name
, p
->asn1typename
, (void *)p
, TBLTYPE(p
->type
),
3647 tag_class
[p
->tclass
], p
->tag
);
3649 if (p
->value_id
== -1) { /* not registered before, do it now */
3650 proto_register_field_array(proto_asn1
, &(p
->value_hf
) , 1);
3655 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3656 p
->mytype
, p
->typenum
, p
->basetype
, p
->flags
, p
->asn1typename
,
3657 p
->name
, p
->fullname
,
3658 tbl_types_wireshark_txt
[p
->type
], p
->value_id
);
3660 list
= g_node_next_sibling(list
);
3665 PDUtext(char *txt
, gulong txt_size
, PDUinfo
*info
) /* say everything we know about this entry */
3668 const char *tt
, *nn
, *tn
, *fn
, *oo
, *ii
, *an
, *tr
, *ty
;
3673 tt
= TBLTYPE(info
->type
);
3675 tn
= info
->asn1typename
;
3676 fn
= info
->fullname
;
3677 if (info
->flags
& PDU_NAMEDNUM
)
3678 g_snprintf(&txt
[idx
], txt_size
- idx
, "name: %2d %s", info
->tag
, nn
);
3680 if (info
->flags
& PDU_TYPEDEF
)
3681 idx
+= g_snprintf(&txt
[idx
], txt_size
- idx
, "def %d: ", info
->typenum
);
3683 idx
+= g_snprintf(&txt
[idx
], txt_size
- idx
, " ");
3684 ty
= (info
->flags
& PDU_TYPETREE
) ? "typ" : "val";
3685 idx
+= g_snprintf(&txt
[idx
], txt_size
- idx
, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty
,tt
, tn
, nn
, fn
,
3686 tag_class
[info
->tclass
], info
->tag
, info
->value_id
, info
->type_id
);
3687 idx
+= g_snprintf(&txt
[idx
], txt_size
- idx
, ", mt=%d, bt=%d", info
->mytype
, info
->basetype
);
3688 oo
= (info
->flags
& PDU_OPTIONAL
) ? ", optional" : empty
;
3689 ii
= (info
->flags
& PDU_IMPLICIT
) ? ", implicit" : empty
;
3690 nn
= (info
->flags
& PDU_NAMEDNUM
) ? ", namednum" : empty
;
3691 an
= (info
->flags
& PDU_ANONYMOUS
) ? ", anonymous" : empty
;
3692 idx
+= g_snprintf(&txt
[idx
], txt_size
- idx
, "%s%s%s%s", oo
, ii
, nn
, an
);
3693 if (info
->flags
& PDU_REFERENCE
) {
3694 rinfo
= (PDUinfo
*)((GNode
*)(info
->reference
))->data
;
3695 tt
= TBLTYPE(rinfo
->type
);
3697 tn
= rinfo
->asn1typename
;
3698 fn
= rinfo
->fullname
;
3699 idx
+= g_snprintf(&txt
[idx
], txt_size
- idx
, ", reference to %s (%s)%s [%s]", tt
, tn
, nn
, fn
);
3700 if (rinfo
->flags
& PDU_TYPEDEF
)
3701 idx
+= g_snprintf(&txt
[idx
], txt_size
- idx
, " T%d", rinfo
->typenum
);
3702 idx
+= g_snprintf(&txt
[idx
], txt_size
- idx
, " tag %c%d", tag_class
[rinfo
->tclass
], rinfo
->tag
);
3703 oo
= (rinfo
->flags
& PDU_OPTIONAL
) ? ", optional" : empty
;
3704 ii
= (rinfo
->flags
& PDU_IMPLICIT
) ? ", implicit" : empty
;
3705 nn
= (rinfo
->flags
& PDU_NAMEDNUM
) ? ", namednum" : empty
;
3706 tn
= (rinfo
->flags
& PDU_REFERENCE
) ? ", reference" : empty
;
3707 tt
= (rinfo
->flags
& PDU_TYPEDEF
) ? ", typedef" : empty
;
3708 an
= (rinfo
->flags
& PDU_ANONYMOUS
) ? ", anonymous" : empty
;
3709 tr
= (rinfo
->flags
& PDU_TYPETREE
) ? ", typetree" : empty
;
3710 g_snprintf(&txt
[idx
], txt_size
- idx
, "%s%s%s%s%s%s%s", oo
, ii
, nn
, tn
, tt
, an
, tr
);
3714 g_snprintf(&txt
[idx
], txt_size
- idx
, "no info available");
3722 showPDUtree(GNode
*p
, int n
)
3728 info
= (PDUinfo
*)p
->data
;
3730 PDUtext(text
, sizeof(text
), info
);
3732 if (asn1_verbose
) g_message("%*s%s", n
*2, empty
, text
);
3734 showPDUtree(g_node_first_child(p
), n
+1);
3736 p
= g_node_next_sibling(p
);
3743 build_pdu_tree(const char *pduname
)
3746 guint pdudef
, i
, tcount
;
3755 if (asn1_verbose
) g_message("build msg tree from '%s' for '%s'", current_asn1
, pduname
);
3758 if (asn1_verbose
) g_message("no data nodes");
3763 g_node_traverse(data_nodes
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, is_typedef
, (gpointer
)&sd
);
3765 pdudef
= ((TBLTypeDef
*)(sd
.here
->data
))->typeDefId
;
3766 if (asn1_verbose
) g_message("%s found, %p, typedef %d", sd
.key
, (void *)sd
.here
, pdudef
);
3768 if (asn1_verbose
) g_message("%s not found, ignored", sd
.key
);
3772 /* If there's an existing PDU tree, free it */
3774 g_node_traverse(PDUtree
, G_POST_ORDER
, G_TRAVERSE_ALL
, -1,
3775 free_node_data
, NULL
);
3776 g_node_destroy(PDUtree
);
3779 /* initialize the PDU tree, hand craft the root entry */
3781 info
= (PDUinfo
*)g_malloc0(sizeof(PDUinfo
));
3782 info
->name
= pduname
;
3783 info
->asn1typename
= pduname
;
3784 info
->type
= TBL_SEQUENCEOF
;
3785 info
->fullname
= g_strdup_printf("%s.%s", pabbrev
, pduname
);
3786 info
->flags
= PDUinfo_initflags
= 0;
3787 info
->value_id
= -1;
3789 info
->basetype
= -1;
3790 info
->mytype
= pdudef
;
3792 info
->value_hf
.p_id
= &(info
->value_id
);
3793 info
->value_hf
.hfinfo
.name
= info
->fullname
;
3794 info
->value_hf
.hfinfo
.abbrev
= info
->fullname
;
3795 info
->value_hf
.hfinfo
.type
= tbl_types_wireshark
[info
->type
];
3796 info
->value_hf
.hfinfo
.display
= tbl_display_wireshark
[info
->type
];
3797 info
->value_hf
.hfinfo
.blurb
= info
->fullname
;
3799 anonCount
= 0; /* anonymous types counter */
3801 PDUtree
= g_node_new(info
);
3802 pabbrev_pdu_len
= g_snprintf(fieldname
, sizeof(fieldname
), "%s.%s.", pabbrev
, pduname
);
3803 sav_len
= pabbrev_pdu_len
;
3805 /* Now build the tree for this top level PDU */
3807 g_message("******** Define main type %d, %s", pdudef
, pduname
);
3808 tbl_typeref(0, PDUtree
, sd
.here
, pabbrev_pdu_len
-1); /* strip initial . for new names */
3811 g_message("%d anonymous types", anonCount
);
3813 /* Now make all types used available for matching */
3815 g_message("Define the types that are actually referenced through the top level PDU");
3816 for (i
=0, tcount
=0; i
<numTypedefs
; i
++) {
3817 tr
= &(typeDef_names
[i
]);
3819 if (tr
->pdu
) { /* ignore if not used in main pdu */
3822 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef
, pduname
);
3824 g_message("******** Define type %d, %s", i
, tr
->name
);
3826 /* .... do definition ..... */
3827 info
= (PDUinfo
*)g_malloc0(sizeof(PDUinfo
));
3828 info
->name
= tr
->name
;
3829 info
->asn1typename
= tr
->name
;
3830 info
->tclass
= tr
->defclass
;
3831 info
->tag
= tr
->deftag
;
3832 info
->type
= TBL_TYPEREF
;
3833 info
->fullname
= g_strdup_printf("%s.--.%s", pabbrev
, tr
->name
);
3834 info
->flags
= PDUinfo_initflags
= PDU_TYPETREE
;
3835 info
->value_id
= -1;
3837 info
->basetype
= -1;
3840 info
->value_hf
.p_id
= &(info
->value_id
);
3841 info
->value_hf
.hfinfo
.name
= info
->fullname
;
3842 info
->value_hf
.hfinfo
.abbrev
= info
->fullname
;
3843 info
->value_hf
.hfinfo
.type
= tbl_types_wireshark
[info
->type
];
3844 info
->value_hf
.hfinfo
.display
= tbl_display_wireshark
[info
->type
];
3845 info
->value_hf
.hfinfo
.blurb
= info
->fullname
;
3847 tr
->typetree
= g_node_new(info
);
3848 pabbrev_pdu_len
= g_snprintf(fieldname
, sizeof(fieldname
), "%s.--.%s.", pabbrev
, tr
->name
);
3849 tbl_typeref(0, tr
->typetree
, tr
->type
, pabbrev_pdu_len
-1);
3853 g_message("%d types used", tcount
);
3855 pabbrev_pdu_len
= sav_len
;
3857 /* and show the result */
3859 g_message("Type index:");
3860 for (i
=0; i
<numTypedefs
; i
++) {
3861 tr
= &(typeDef_names
[i
]);
3863 if (tr
->pdu
== 0) /* skip if not used */
3867 g_message(" %3d %s, %c%d, refs: %d",
3868 i
, tr
->name
, tag_class
[tr
->defclass
], tr
->deftag
,
3869 g_ptr_array_len(tr
->refs
));
3871 /* get defining node for this type */
3874 p
= (PDUinfo
*)(tr
->typetree
->data
);
3875 defid
= p
->value_id
;
3877 g_message(" -- defining id=%d", defid
);
3879 for(j
=0; j
< g_ptr_array_len(tr
->refs
); j
++) { /* show refs, and set type_id */
3880 p
= (PDUinfo
*)g_ptr_array_index(tr
->refs
, j
);
3881 if (p
->mytype
== (gint
)i
)
3882 p
->type_id
= defid
; /* normal reference */
3884 if ((p
->flags
& PDU_TYPETREE
) == 0) {
3885 /* we have a primitive value, find its real type */
3886 for(k
=0; k
< g_ptr_array_len(tr
->refs
); k
++) {
3887 /* look at all refs */
3888 q
= (PDUinfo
*)g_ptr_array_index(tr
->refs
, k
);
3889 if ((q
->flags
& PDU_TYPETREE
) == 0)
3890 continue; /* only type trees are interresting */
3891 if (q
->type
!= p
->type
)
3892 continue; /* must be same types */
3893 if (strcmp(q
->name
, p
->name
) == 0) {
3894 /* OK, take the first we find, not entirely
3895 * correct, it may be from a different
3896 * base-base type...... XXX */
3897 p
->type_id
= q
->value_id
;
3905 PDUtext(text
, sizeof(text
), p
);
3906 g_message(" %s", text
);
3912 g_message("The resulting PDU tree:");
3913 showPDUtree(PDUtree
, 0);
3919 #ifdef DISSECTOR_WITH_GUI
3920 /* This cannot work in tshark.... don't include for now */
3922 #endif /* DISSECTOR_WITH_GUI */
3925 static GtkWidget
*window
= NULL
;
3927 /* the columns in the tree view */
3930 TITLE_COLUMN
, /* text in this row */
3931 DEF_COLUMN
, /* definition in this row, if any */
3932 REF_COLUMN
, /* referennce from this column, if any */
3933 VALUE_COLUMN
, /* indicate this is a value */
3934 NAME_COLUMN
, /* name of this row */
3938 static FILE *namelist
= 0;
3941 build_tree_view(GtkTreeStore
*store
, GNode
*p
, GtkTreeIter
*iter
)
3944 PDUinfo
*info
, *rinfo
;
3951 info
= (PDUinfo
*)p
->data
;
3953 gtk_tree_store_append (store
, &iter2
, iter
); /* Acquire iterator */
3955 PDUtext(text
, sizeof(text
), info
);
3958 if (info
->flags
& PDU_TYPEDEF
)
3959 def
= info
->typenum
;
3961 if (info
->flags
& PDU_REFERENCE
) {
3962 rinfo
= (PDUinfo
*)((GNode
*)(info
->reference
))->data
;
3963 ref
= rinfo
->typenum
;
3965 pb
= GTK_STOCK_CANCEL
;
3966 if (G_NODE_IS_LEAF(p
)) {
3967 if (info
->flags
& PDU_NAMEDNUM
)
3968 pb
= GTK_STOCK_BOLD
;
3972 fprintf(namelist
, "%16s %s\n",
3973 &(TBLTYPE(info
->type
)[4]), info
->fullname
);
3976 switch (info
->type
) {
3977 case TBL_ENUMERATED
:
3981 fprintf(namelist
, "%16s %s\n",
3982 &(TBLTYPE(info
->type
)[4]), info
->fullname
);
3989 gtk_tree_store_set (store
, &iter2
,
3994 NAME_COLUMN
, info
->fullname
,
3997 build_tree_view(store
, g_node_first_child(p
), &iter2
);
3999 p
= g_node_next_sibling(p
);
4011 #define PATHSTACKMAX 10
4012 static GtkTreePath
*pathstack
[PATHSTACKMAX
];
4013 static gint pathstackp
= 0;
4015 static void add_path(GtkTreePath
*p
)
4017 if (pathstackp
>= PATHSTACKMAX
) { /* shift old contents */
4018 gtk_tree_path_free(pathstack
[0]); /* we forget about this one */
4019 memmove(&pathstack
[0], &pathstack
[1], (PATHSTACKMAX
-1)*sizeof(GtkTreePath
*));
4022 pathstack
[pathstackp
++] = p
;
4025 static GtkTreePath
*pop_path(void)
4028 return pathstack
[--pathstackp
];
4033 find_definition(GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, gpointer data
)
4037 struct DefFind
*df
= (struct DefFind
*)data
;
4039 gtk_tree_model_get (model
, iter
, DEF_COLUMN
, &def
, -1);
4041 if (def
== df
->def
) {
4042 df
->path
= gtk_tree_path_copy (path
);
4050 my_signal_handler(GtkTreeView
*treeview
, GtkTreePath
*spath
, GtkTreeViewColumn
*arg2
, gpointer model
)
4053 GtkTreePath
*path
, *path2
;
4054 gchar
*text
, *oldpath
, *newpath
;
4060 path
= gtk_tree_path_copy (spath
);
4062 gtk_tree_model_get_iter (model
, &iter
, path
);
4063 gtk_tree_model_get (model
, &iter
, TITLE_COLUMN
, &text
, DEF_COLUMN
, &def
, REF_COLUMN
, &ref
, -1);
4065 oldpath
= gtk_tree_path_to_string(path
);
4066 path2
= gtk_tree_path_copy (path
);
4068 add_path(gtk_tree_path_copy(path
));
4070 if (ref
!= -1) { /* this is a reference, find matching definition */
4073 gtk_tree_model_foreach (model
, find_definition
, &df
);
4075 gtk_tree_path_free(path
);
4078 } else { /* just move to the next entry, if it exists */
4079 gtk_tree_path_next(path2
);
4081 if (gtk_tree_model_get_iter (model
, &iter
, path2
)) {
4082 gtk_tree_path_free(path
);
4083 path
= path2
; /* OK */
4085 if (gtk_tree_path_get_depth (path
) > 1)
4086 gtk_tree_path_up (path
);
4091 gtk_tree_path_free (path2
);
4093 gtk_tree_view_expand_to_path (treeview
, path
);
4094 gtk_tree_view_expand_row (treeview
, path
, FALSE
);
4096 gtk_tree_view_scroll_to_cell (treeview
, path
, NULL
, TRUE
, 0.2, 0.0);
4098 gtk_tree_view_set_cursor (treeview
, path
, NULL
, FALSE
);
4100 newpath
= gtk_tree_path_to_string(path
);
4103 g_message("my_signal_handler: treeview=%p, moving from %s to %s",
4104 treeview
, oldpath
, newpath
);
4110 /* gtk_tree_path_free(df.path); */
4115 menuitem_cb (gpointer callback_data
,
4116 guint callback_action
,
4120 GtkTreeModel
*model
;
4121 GtkTreeView
*treeview
= gtk_item_factory_popup_data_from_widget(widget
);
4122 GtkTreeSelection
*selection
;
4127 gchar
*oldpath
, *newpath
;
4128 GtkTreeViewColumn
*focus_column
;
4130 selection
= gtk_tree_view_get_selection(treeview
);
4132 model
= gtk_tree_view_get_model(treeview
);
4133 gtk_tree_view_get_cursor (treeview
, &path
, &focus_column
);
4135 if (gtk_tree_model_get_iter (model
, &iter
, path
)) {
4137 gtk_tree_model_get (model
, &iter
, TITLE_COLUMN
, &text
, DEF_COLUMN
, &def
, REF_COLUMN
, &ref
,
4138 NAME_COLUMN
, &name
, -1);
4139 oldpath
= gtk_tree_path_to_string(path
);
4142 switch (callback_action
) {
4143 case 0: /* Select */
4144 gtk_tree_selection_select_path (selection
, path
);
4149 gtk_tree_view_expand_to_path (treeview
, path
);
4150 gtk_tree_view_expand_row (treeview
, path
, FALSE
);
4152 gtk_tree_view_scroll_to_cell (treeview
, path
, NULL
, TRUE
, 0.2, 0.0);
4154 gtk_tree_view_set_cursor (treeview
, path
, NULL
, FALSE
);
4156 newpath
= gtk_tree_path_to_string(path
);
4158 gtk_tree_path_free(path
);
4160 newpath
= g_strdup("** no path **");
4162 g_message("menueitem_cb: treeview=%p, moving from %s to %s",
4163 treeview
, oldpath
, newpath
);
4167 /* get all non anonymous names to the root */
4170 dialog
= gtk_message_dialog_new (GTK_WINDOW (callback_data
),
4171 GTK_DIALOG_DESTROY_WITH_PARENT
,
4174 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
4175 gtk_item_factory_path_from_widget (widget
),
4176 callback_action
, text
, oldpath
, newpath
, name
);
4178 /* Close dialog on user response */
4179 g_signal_connect (dialog
,
4181 G_CALLBACK (gtk_widget_destroy
),
4184 gtk_widget_show (dialog
);
4189 if (newpath
!= empty
)
4193 g_message("menuitem_cb: no iterator...");
4196 static GtkItemFactoryEntry menu_items
[] = {
4197 { "/Select", NULL
, menuitem_cb
, 0, NULL
, 0 },
4198 { "/Back", "<control>B", menuitem_cb
, 1, NULL
, 0 },
4199 { "/Find", "<control>F", menuitem_cb
, 2, NULL
, 0 },
4200 { "/Save", "<control>S", menuitem_cb
, 3, NULL
, 0 },
4203 static gint
button_press_callback( GtkWidget
*widget
,
4204 GdkEventButton
*event
,
4207 GtkTreeView
*treeview
= GTK_TREE_VIEW(widget
);
4209 /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
4210 * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
4213 if (event
->button
== 3) {
4214 gtk_item_factory_popup_with_data ((GtkItemFactory
*)data
, treeview
, NULL
,
4221 return FALSE
; /* continue handling this event */
4226 create_message_window(void)
4228 GtkCellRenderer
*renderer
;
4229 GtkTreeStore
*model
;
4232 GtkWidget
*treeview
;
4234 GtkItemFactory
*item_factory
;
4235 GtkAccelGroup
*accel_group
;
4236 gint nmenu_items
= sizeof (menu_items
) / sizeof (menu_items
[0]);
4240 /* create window, etc */
4241 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
4242 gtk_window_set_title (GTK_WINDOW (window
), current_pduname
);
4243 g_signal_connect (window
, "destroy",
4244 G_CALLBACK (gtk_widget_destroyed
), &window
);
4246 vbox
= gtk_vbox_new (FALSE
, 8);
4247 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 4);
4248 gtk_container_add (GTK_CONTAINER (window
), vbox
);
4250 text
= g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1
, current_pduname
);
4252 gtk_box_pack_start (GTK_BOX (vbox
),
4253 gtk_label_new (text
),
4257 sw
= gtk_scrolled_window_new (NULL
, NULL
);
4258 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw
),
4259 GTK_SHADOW_ETCHED_IN
);
4260 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
4261 GTK_POLICY_AUTOMATIC
,
4262 GTK_POLICY_AUTOMATIC
);
4263 gtk_box_pack_start (GTK_BOX (vbox
), sw
, TRUE
, TRUE
, 0);
4265 model
= gtk_tree_store_new(N_COLUMNS
, G_TYPE_STRING
, G_TYPE_INT
, G_TYPE_INT
,
4266 G_TYPE_STRING
, G_TYPE_STRING
);
4268 namelist
= ws_fopen("namelist.txt", "w");
4270 fprintf(stderr
, "unable to open file: namelist.txt for writing!\n");
4271 build_tree_view(model
, PDUtree
, NULL
);
4277 /* create tree view */
4278 treeview
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (model
));
4279 g_object_unref (model
);
4280 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview
), TRUE
);
4281 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview
)),
4282 GTK_SELECTION_MULTIPLE
);
4284 renderer
= gtk_cell_renderer_text_new ();
4286 #if 0 /* testing pango attributes */
4289 PangoAttrList
* attr
;
4291 attr
= pango_attr_list_new();
4292 bg
= pango_attr_background_new(50000,55000,50000);
4293 bg
->start_index
= 0;
4294 bg
->end_index
= 10000;
4295 pango_attr_list_insert(attr
, bg
);
4297 g_object_set(renderer
, "attributes", attr
, NULL
);
4299 #endif /* testing pango attributes */
4301 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview
),
4302 TITLE_COLUMN
, "asn1 entities", renderer
,
4303 "text", TITLE_COLUMN
, NULL
);
4305 /* renderer = gtk_cell_renderer_text_new ();
4306 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4307 * DEF_COLUMN, "type definition", renderer,
4308 * "text", DEF_COLUMN, NULL );
4310 * renderer = gtk_cell_renderer_text_new ();
4311 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4312 * REF_COLUMN, "reference", renderer,
4313 * "text", REF_COLUMN, NULL );
4315 renderer
= gtk_cell_renderer_pixbuf_new ();
4316 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview
),
4317 VALUE_COLUMN
, "value", renderer
,
4318 "stock_id", VALUE_COLUMN
, NULL
);
4320 renderer
= gtk_cell_renderer_text_new ();
4321 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview
),
4322 NAME_COLUMN
, "fieldname", renderer
,
4323 "text", NAME_COLUMN
, NULL
);
4325 gtk_container_add (GTK_CONTAINER (sw
), treeview
);
4327 /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
4331 accel_group
= gtk_accel_group_new ();
4333 /* This function initializes the item factory.
4334 * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
4335 * or GTK_TYPE_OPTION_MENU.
4336 * Param 2: The path of the menu.
4337 * Param 3: A pointer to a gtk_accel_group. The item factory sets up
4338 * the accelerator table while generating menus.
4341 item_factory
= gtk_item_factory_new (GTK_TYPE_MENU
, "<menu>", accel_group
);
4343 /* This function generates the menu items. Pass the item factory,
4344 the number of items in the array, the array itself, and any
4345 callback data for the the menu items. */
4346 gtk_item_factory_create_items (item_factory
, nmenu_items
, menu_items
, NULL
);
4348 /* Attach the new accelerator group to the window. */
4349 gtk_window_add_accel_group (GTK_WINDOW (window
), accel_group
);
4352 /* expand all rows after the treeview widget has been realized */
4353 g_signal_connect (treeview
, "realize",
4354 G_CALLBACK (gtk_tree_view_expand_all
), NULL
);
4355 g_signal_connect (treeview
, "row-activated",
4356 G_CALLBACK (my_signal_handler
), (gpointer
)model
);
4358 g_signal_connect (treeview
, "button_press_event",
4359 G_CALLBACK (button_press_callback
), item_factory
);
4361 /* g_signal_connect_swapped (treeview, "event",
4362 * G_CALLBACK (button_press_handler),
4365 gtk_window_set_default_size (GTK_WINDOW (window
), 650, 400);
4368 if (!GTK_WIDGET_VISIBLE (window
))
4369 gtk_widget_show_all (window
);
4372 gtk_widget_destroy (window
);
4376 #endif /* SHOWPDU */
4378 /************************************************************************************************
4379 * routines to find names to go with the decoded data stream *
4380 ************************************************************************************************/
4381 #define PDUSTATE_STACK_SIZE 1024
4382 typedef struct _statestack statestack
;
4383 static struct _statestack
{
4388 } PDUstate
[PDUSTATE_STACK_SIZE
];
4389 static gint PDUstatec
= 0;
4391 /* XXX - Shouldn't we do bounds checking here? */
4392 #define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
4393 #define POPSTATE PDUstate[--PDUstatec]
4396 getname(GNode
*node
) {
4397 if (node
== NULL
|| node
->data
== NULL
)
4398 THROW(ReportedBoundsError
);
4400 return ((PDUinfo
*)node
->data
)->name
;
4404 gettype(GNode
*node
) {
4405 if (node
== NULL
|| node
->data
== NULL
)
4406 THROW(ReportedBoundsError
);
4408 return ((PDUinfo
*)node
->data
)->type
& TBL_TYPEmask
;
4412 getinfo(GNode
*node
) {
4414 THROW(ReportedBoundsError
);
4416 return (PDUinfo
*)node
->data
;
4419 #define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
4420 #define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
4421 #define MATCH (info && (cls == info->tclass) && (tag == info->tag))
4422 #define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
4423 #define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
4424 #define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
4425 #define ISCHOICE (info && (info->flags & PDU_CHOICE))
4426 #define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
4429 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
4430 pos.node=NULL;PUSHNODE(pos);return ret;}}
4434 showstack(statestack
*pos
, char *txt
, int n
)
4437 const char /* *name, *type,*/ *stype
;
4438 const char *rep
, *chs
, *done
, *ref
, *pop
, *chr
, *rch
, *sch
, *con
;
4444 if ( ! asn1_verbose
)
4450 g_message("==underflow");
4453 rep
= chs
= done
= ref
= pop
= chr
= rch
= sch
= con
= empty
;
4455 #if 0 /* XXX: not used ??? */
4458 name
= ((PDUinfo
*)g
->data
)->name
;
4459 type
= TBLTYPE(((PDUinfo
*)g
->data
)->type
);
4461 name
= "node<null>";
4466 stype
= TBLTYPE(typef
);
4467 if (typef
& TBL_REPEAT
) rep
= "[repeat]";
4468 if (typef
& TBL_CHOICE_made
) chs
= "[choice]";
4469 if (typef
& TBL_SEQUENCE_done
) done
= "[done]";
4470 if (typef
& TBL_REFERENCE
) ref
= "[ref]";
4471 if (typef
& TBL_REFERENCE_pop
) pop
= "[ref-pop]";
4472 if (typef
& TBL_CHOICE_repeat
) chr
= "[chs-rep]";
4473 if (typef
& TBL_REPEAT_choice
) rch
= "[rep-chs]";
4474 if (typef
& TBL_SEQUENCE_choice
)sch
= "[seq-chs]";
4475 if (typef
& TBL_CONSTRUCTED
) con
= "[constr]";
4477 i
= g_snprintf(buf
, sizeof(buf
), "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt
, PDUstatec
,
4478 (void *)pos
->node
, stype
, rep
, chs
, done
, ref
, pop
, chr
, rch
, sch
, con
,
4479 pos
->name
, pos
->offset
);
4481 for(j
=1, n
--; n
>0; j
++, n
--) {
4482 p
= &PDUstate
[PDUstatec
-j
];
4484 stype
= TBLTYPE(typef
);
4485 rep
= (typef
& TBL_REPEAT
) ? "[repeat]" : empty
;
4486 chs
= (typef
& TBL_CHOICE_made
) ? "[choice]" : empty
;
4487 done
= (typef
& TBL_SEQUENCE_done
) ? "[done]" : empty
;
4488 ref
= (typef
& TBL_REFERENCE
) ? "[ref]" : empty
;
4489 pop
= (typef
& TBL_REFERENCE_pop
) ? "[ref-pop]" : empty
;
4490 chr
= (typef
& TBL_CHOICE_repeat
) ? "[chs-rep]" : empty
;
4491 rch
= (typef
& TBL_REPEAT_choice
) ? "[rep-chs]" : empty
;
4492 sch
= (typef
& TBL_SEQUENCE_choice
)? "[seq-chs]" : empty
;
4493 con
= (typef
& TBL_CONSTRUCTED
) ? "[constr]" : empty
;
4495 i
+= g_snprintf(&buf
[i
], sizeof(buf
) - i
, "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec
-j
,
4496 (void *)p
->node
, stype
, rep
, chs
, done
, ref
, pop
, chr
, rch
, sch
, con
,
4497 p
->name
, p
->offset
);
4499 g_message("%s", buf
);
4504 showrefNode(GNode
*node
, int n
)
4506 const char *name
= empty
, *type
= empty
, *tname
= empty
;
4507 int cls
= 0, tag
= 0;
4512 g_message("%*sstop, nesting too deep", 2*n
, empty
);
4516 info
= (PDUinfo
*)(node
->data
);
4517 type
= TBLTYPE(info
->type
);
4519 tname
= info
->asn1typename
;
4520 ref
= info
->reference
;
4524 g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4525 2*n
, empty
, tname
, type
, name
, node
, node
->data
,
4526 ref
, tag_class
[cls
], tag
);
4529 showrefNode(ref
, n
+1);
4535 showNode(GNode
*node
, int n
, int m
)
4537 const char *name
= empty
, *type
= empty
;
4544 type
= TBLTYPE(((PDUinfo
*)(node
->data
))->type
);
4545 name
= ((PDUinfo
*)(node
->data
))->name
;
4546 ref
= ((PDUinfo
*)(node
->data
))->reference
;
4548 g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4549 2*n
, empty
, type
, name
, node
, node
->data
, node
->next
, node
->prev
,
4550 node
->parent
, node
->children
);
4553 g_message("%*sstop, nesting too deep", 2*n
, empty
);
4557 if (ref
) showrefNode(ref
, n
+2);
4559 if (node
->children
) showNode(node
->children
, n
+1, m
);
4560 if (node
->next
) showNode(node
->next
, n
, m
);
4565 PDUreset(int count
, int count2
)
4569 if (asn1_verbose
) g_message("PDUreset %d-%d", count
, count2
);
4571 PDUstatec
= 0; /* stackpointer */
4572 PDUerrcount
= 0; /* error counter per asn.1 message */
4574 pos
.node
= NULL
; /* sentinel */
4575 pos
.name
= "sentinel";
4576 pos
.type
= TBL_SEQUENCEOF
;
4581 pos
.node
= PDUtree
; /* root of the tree */
4582 pos
.name
= getname(pos
.node
);
4583 pos
.type
= gettype(pos
.node
) | TBL_REPEAT
;
4589 static GNode
* /* find GNode for a choice element, 0 if none */
4590 makechoice(GNode
*p
, guint cls
, guint tag
)
4595 p
= g_node_first_child(p
); /* the list of choices */
4596 info
= 0; /* avoid gcc warning */
4599 info
= ((PDUinfo
*)p
->data
);
4601 if (info
->type
== TBL_CHOICE
) {
4603 g_message(" using sub choice (%s)%s", info
->asn1typename
, info
->name
);
4605 q
= makechoice(p
, cls
, tag
);
4606 if (q
) { /* found it */
4608 info
= ((PDUinfo
*)p
->data
);
4610 } /* continue with this level */
4614 g_message(" have %c%d, found %c%d, %s", tag_class
[cls
], tag
,
4615 tag_class
[info
->tclass
], info
->tag
, info
->name
);
4617 if ((cls
== info
->tclass
) && (tag
== info
->tag
))
4618 break; /* found it */
4621 p
= g_node_next_sibling(p
);
4624 if (p
) g_message(" OK, '%s:(%s)%s' chosen", tbl_types
[info
->type
], info
->asn1typename
,
4626 else g_message(" ...no matching choice...");
4631 /* offset is for debugging only, a reference to output on screen */
4633 getPDUprops(PDUprops
*out
, guint offset
, guint cls
, guint tag
, guint cons
)
4635 statestack pos
, pos2
, save_pos
;
4637 const char *ret
, *tmp
;
4638 int typeflags
= 0, donext
= 0, pushed
= 0, cons_handled
= 0;
4639 static char namestr
[64]; /* enough ? */
4640 static char posstr
[40];
4641 static char noname
[] = "*noname*";
4642 static PDUprops constructed_save
; /* for unexpectedly constructed entities */
4644 if (PDUstatec
> 0) /* don't read from below the stack */
4646 /* pos refers to the last asn1 node handled */
4648 /* a very simple, too simple??, way to handle constructed entities */
4649 if ((PDUstatec
> 0) && (pos
.type
& TBL_CONSTRUCTED
)) {
4650 /* unexpectedly constructed, return same info as last time */
4651 g_snprintf(posstr
, sizeof(posstr
), "==off=%d %c%d%c", offset
, tag_class
[cls
], tag
, cons
?'c':'p');
4652 showstack(&pos
, posstr
, 3);
4653 pos
.offset
= offset
;
4654 pos
.type
&= ~TBL_CONSTRUCTED
; /* remove the flag */
4655 PUSHNODE(pos
); /* push extra, to match with a EOI operation */
4656 PUSHNODE(pos
); /* restore the stack */
4657 *out
= constructed_save
;
4659 g_message(" return for constructed %s (%s)%s",
4660 TBLTYPE(out
->type
), out
->asn1typename
, out
->name
);
4664 save_pos
= pos
; /* may need it again */
4668 out
->asn1typename
= "*error*";
4675 if (PDUstatec
<= 0) {
4676 if (PDUstatec
> -10) {
4678 g_message(">>off=%d stack underflow, return", offset
);
4680 if (PDUstatec
== -10) {
4682 g_message(">>off=%d stack underflow, return, no more messages", offset
);
4684 out
->name
= "*underflow*";
4685 out
->flags
|= OUT_FLAG_noname
;
4689 g_snprintf(posstr
, sizeof(posstr
), "==off=%d %c%d%c", offset
, tag_class
[cls
], tag
, cons
?'c':'p');
4691 showstack(&pos
, posstr
, 3);
4693 if (cls
== ASN1_EOI
) { /* end of this input sequence */
4695 if (pos
.type
& TBL_REFERENCE_pop
) { /* reference finished, return to caller */
4696 if (asn1_verbose
) g_message(" EOI: reference pop");
4699 switch(pos
.type
& TBL_TYPEmask
) {
4701 if (asn1_verbose
) g_message(" EOI: pop typeref");
4702 pos
= POPSTATE
; /* remove typeref */
4704 case TBL_CHOICE_done
:
4705 if (asn1_verbose
) g_message(" EOI: mark choice");
4707 pos
.type
|= TBL_CHOICE_made
; /* poropagate this up the stack */
4715 pos
= POPSTATE
; /* this is pushed back on the stack later */
4716 if (pos
.node
== NULL
) {
4717 if (asn1_verbose
) g_message(" EOI, pos.node == NULL");
4718 out
->name
= "*no-name-EOI*";
4719 out
->flags
|= OUT_FLAG_noname
;
4724 info
= getinfo(pos
.node
);
4726 tmp
= TBLTYPE(info
->type
);
4727 if (offset
!= pos
.offset
) {
4729 g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4730 tmp
, ret
, offset
, pos
.offset
);
4731 while ((offset
< pos
.offset
) && (PDUstatec
> 0)) {
4734 g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
4735 offset
, pos
.offset
);
4737 if (offset
!= pos
.offset
)
4738 PDUerrcount
++; /* only count if still unequal */
4740 if (asn1_verbose
) g_message(" EOI %s:%s OK, offset=%d", tmp
, ret
, offset
);
4743 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4744 * indicated by the synthetic EOI call. */
4745 if ((cls
== BER_CLASS_UNI
) && (tag
== BER_UNI_TAG_EOC
)) { /* explicit EOC never has a name */
4746 PUSHNODE(pos
); /* restore stack */
4747 ret
= "explicit-EOC";
4748 if (asn1_verbose
) g_message(" return '%s', ignore", ret
);
4750 out
->asn1typename
= "ASN1";
4754 /* find appropriate node for this tag */
4756 if (pos
.node
== NULL
) {
4757 if (asn1_verbose
) g_message(" pos.node == NULL");
4758 out
->name
= "*no-name*";
4759 out
->flags
|= OUT_FLAG_noname
;
4764 /* showNode(pos.node, 3, 4); */
4766 switch (pos
.type
& TBL_TYPEmask
) {
4767 case TBL_SEQUENCE
: /* avoid finishing a choice when we have to do a sequence first */
4771 if (pos
.type
& TBL_CHOICE_made
) {
4772 if (asn1_verbose
) g_message(" finish choice");
4778 info
= getinfo(pos
.node
);
4780 if (pos
.type
& TBL_REPEAT
) { /* start of a repeat */
4781 switch(pos
.type
& TBL_TYPEmask
) { /* type of previous node */
4783 if (asn1_verbose
) g_message(" repeating choice"); /* ignore repeat */
4786 if (asn1_verbose
) g_message(" seqof: repeat start");
4787 /* decide how to continue, CHILD for next instance of sequence
4788 * or NEXT for end of repeated sequence.
4789 * use the tag to make a descision */
4790 if (asn1_verbose
) g_message(" seqof: first got %c%d, found %c%d",
4791 tag_class
[cls
], tag
,
4792 tag_class
[info
->tclass
], info
->tag
);
4794 /* This is the start of repeating */
4796 ret
= getname(pos
.node
);
4797 if (asn1_verbose
) g_message(" return for repeat '%s'", ret
);
4798 out
->type
= (pos
.type
& TBL_TYPEmask
);
4799 out
->asn1typename
= info
->asn1typename
;
4801 out
->value_id
= info
->value_id
;
4802 out
->type_id
= info
->type_id
;
4804 if (asn1_verbose
) g_message(" anonymous: dontshow");
4806 out
->flags
|= OUT_FLAG_dontshow
;
4812 /* find out where to go .... */
4814 CHILD
; /* assume sequence is repeated */
4816 info
= getinfo(pos
.node
); /* needed for MATCH to look ahead */
4818 g_message(" seqof: child: got %c%d, found %c%d",
4819 tag_class
[cls
], tag
,
4820 tag_class
[info
->tclass
], info
->tag
);
4822 if (pos2
.type
& TBL_CHOICE_repeat
) {
4825 g_message(" repeating a choice, %s",
4827 pos
.type
= TBL_CHOICE_immediate
;
4829 if ( pos
.node
&& ! MATCH
) { /* no, repeat ends, */
4830 donext
= 1; /* move on */
4832 g_message(" seqof: no repeat, force next");
4834 /* following code will take the child again */
4840 } else if (pos
.type
& TBL_REFERENCE_pop
) { /* reference finished, return to caller */
4841 if (asn1_verbose
) g_message(" reference pop, donext");
4844 } else if (pos
.type
& TBL_SEQUENCE_done
) { /* Children have been processed */
4845 if (pos
.type
& TBL_SEQUENCE_choice
) {
4846 pos
= POPSTATE
; /* expect to find a repeat here */
4849 if (asn1_verbose
) g_message(" sequence done, donext");
4853 if (pos
.type
& TBL_REFERENCE
) {
4854 if (asn1_verbose
) g_message(" reference change ref -> pop");
4855 pos
.type
^= (TBL_REFERENCE
| TBL_REFERENCE_pop
);
4858 pos
.offset
= offset
;
4861 if (asn1_verbose
) g_message(" donext");
4864 switch(pos
.type
& TBL_TYPEmask
) { /* type of previous node */
4865 case TBL_SETOF
: /* ?? */
4866 case TBL_SEQUENCEOF
:
4867 if ((pos
.type
& TBL_REPEAT
) == 0) { /* start repeating */
4868 pos
.type
|= TBL_REPEAT
;
4872 /* remember this is the start of a repeat cycle */
4873 typeflags
|= TBL_REPEAT
;
4875 g_message(" seqof: set repeat mark [push,child]");
4878 g_message(" seqof: end of repeat loop [next]");
4882 case TBL_SET
: /* ?? */
4884 pos
.type
|= TBL_SEQUENCE_done
;
4888 if (asn1_verbose
) g_message(" seq [push,child]");
4891 /* no more choice */
4892 pos
.type
= (TBL_CHOICE_done
| (pos
.type
& ~TBL_TYPEmask
));
4895 pos
.type
= 0; /* clear all type flags */
4897 g_message(" choice [push], %c%d, %s",
4898 tag_class
[info
->tclass
], info
->tag
, getname(pos
.node
));
4899 pos
.node
= makechoice(pos
.node
, cls
, tag
);
4900 if (pos
.node
== NULL
) {
4902 out
->flags
|= OUT_FLAG_noname
;
4905 info
= getinfo(pos
.node
);
4907 ret
= getname(pos
.node
);
4909 g_message(" '%s' %c%d will be used",
4910 ret
, tag_class
[info
->tclass
], info
->tag
);
4912 case TBL_CHOICE_done
:
4918 if (asn1_verbose
) g_message(" typeref [pop,next]");
4920 case TBL_ENUMERATED
:
4922 /* skip named numbers now, call to PDUenum() will retrieve a name */
4925 case TBL_CHOICE_immediate
:
4926 if (asn1_verbose
) g_message(" immediate choice [no next]");
4935 if (pos
.node
== NULL
) {
4936 ret
= "*no-name-2*";
4937 if (asn1_verbose
) g_message(" return '%s'", ret
);
4939 out
->flags
|= OUT_FLAG_noname
;
4943 ret
= pos
.name
= getname(pos
.node
);
4944 pos
.type
= gettype(pos
.node
) | (pos
.type
& ~TBL_TYPEmask
);
4945 info
= getinfo(pos
.node
);
4947 /* pos now points to the prospective current node, go check it ********************/
4948 if (asn1_verbose
&& info
) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos
.type
), ret
,
4949 (ISOPTIONAL
)?", optional":empty
,
4950 (ISIMPLICIT
)?", implicit":empty
,
4951 tag_class
[info
->tclass
], info
->tag
);
4953 if (ISOPTIONAL
) { /* must check the tag */
4954 while(! MATCH
) { /* check optional here again...? */
4955 if (asn1_verbose
&& info
)
4956 g_message(" got %c%d, found %c%d", tag_class
[cls
], tag
,
4957 tag_class
[info
->tclass
], info
->tag
);
4959 if (pos
.node
== NULL
) {
4962 pos
= save_pos
; /* reset for next time */
4963 pos
.type
|= TBL_SEQUENCE_done
;
4965 pos
.type
&= ~TBL_SEQUENCE_done
;
4967 out
->flags
|= OUT_FLAG_dontshow
;
4969 g_message(" end of optional list, constructed, expect value next time");
4972 out
->flags
|= OUT_FLAG_noname
;
4974 g_message(" *end of optional list...");
4975 info
= NULL
; /* this is not valid any more... */
4977 break; /* end of list */
4979 info
= getinfo(pos
.node
);
4980 if (asn1_verbose
) g_message(" optional, %s", getname(pos
.node
));
4982 if (pos
.node
&& ! cons_handled
) {
4983 ret
= pos
.name
= getname(pos
.node
);
4984 pos
.type
= gettype(pos
.node
);
4986 /* pos now refers to node with name we want, optional nodes skipped */
4989 if (pos
.type
== TBL_CHOICE
) { /* may be an immediate choice */
4990 pos2
= pos
; /* save current state */
4994 g_message(" already pushed, skip next push");
4996 typeflags
&= ~TBL_CHOICE_made
;
4999 if (asn1_verbose
&& info
)
5000 g_message(" immediate choice [push], %c%d, %s",
5001 tag_class
[info
->tclass
], info
->tag
, getname(pos
.node
));
5003 pos
.node
= makechoice(pos
.node
, cls
, tag
);
5005 if (pos
.node
== NULL
) {
5009 info
= getinfo(pos
.node
);
5010 pos
.type
= gettype(pos
.node
);
5011 out
->type
= (pos
.type
& TBL_TYPEmask
);
5012 out
->flags
|= OUT_FLAG_type
;
5014 g_snprintf(namestr
, sizeof(namestr
), "%s!%s", ret
, getname(pos
.node
));
5017 g_message(" %s:%s will be used", TBLTYPE(pos
.type
), ret
);
5018 if (typeflags
& TBL_REPEAT
) {
5019 pos2
.type
|= TBL_REPEAT
| TBL_REPEAT_choice
;
5021 pos
.type
|= TBL_SEQUENCE_choice
;
5024 g_message(" return from immediate choice [%s] '%s'",
5025 TBLTYPE(pos
.type
), ret
);
5027 out
->data
= pos
.node
; /* for access to named numbers... */
5029 out
->type
= (pos
.type
& TBL_TYPEmask
);
5032 out
->asn1typename
= info
->asn1typename
;
5033 out
->fullname
= info
->fullname
;
5034 out
->value_id
= info
->value_id
;
5035 out
->type_id
= info
->type_id
;
5040 typeflags
|= TBL_CHOICE_made
;
5043 if (asn1_verbose
) g_message(" matching choice '%s'", ret
);
5045 if ( ! cons
) { /* ISIMPLICIT was not OK for all */
5046 pos
= pos2
; /* reset for continuation */
5051 g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos
.type
), ret
,
5052 (ISOPTIONAL
)?", optional":empty
,
5053 (ISIMPLICIT
)?", implicit":empty
,
5054 tag_class
[info
->tclass
], info
->tag
);
5056 g_message(" using: unknown '%s'", ret
);
5059 /* must follow references now */
5060 if (pos
.type
== TBL_TYPEREF
&& info
) {
5061 out
->asn1typename
= info
->asn1typename
;
5062 out
->type_id
= info
->typenum
;
5063 out
->flags
|= OUT_FLAG_typename
;
5064 PUSHNODE(pos
); /* remember where we were */
5065 if (asn1_verbose
) g_message(" typeref [push]");
5066 typeflags
|= TBL_REFERENCE
;
5067 if (info
->reference
== 0) { /* resolved ref to universal type.... */
5068 /* showNode(pos.node, 3, 4); */
5069 pos
.type
= gettype(pos
.node
); /* the resulting type */
5070 info
= getinfo(pos
.node
);
5071 tmp
= "unknown tag";
5072 if (info
&& (info
->tclass
== BER_CLASS_UNI
) && (info
->tag
< 31)) {
5073 tmp
= asn1_tag
[info
->tag
];
5074 pos
.type
= asn1_uni_type
[info
->tag
]; /* get univsrsal type */
5076 if (asn1_verbose
&& info
)
5077 g_message(" indirect typeref to %s:%s, %s [%c%d]",
5078 TBLTYPE(pos
.type
), info
->asn1typename
, tmp
,
5079 tag_class
[info
->tclass
], info
->tag
);
5081 out
->fullname
= info
->fullname
;
5082 donext
= (ISANONYMOUS
); /* refereing entity has no name ? */
5083 pos
.node
= info
->reference
;
5084 pos
.type
= gettype(pos
.node
);
5085 info
= getinfo(pos
.node
);
5087 g_message(" typeref %s %s", TBLTYPE(pos
.type
), getname(pos
.node
));
5088 /* keep name from before going through the reference, unless anonymous */
5089 if (donext
) /* refering entity has no name */
5090 ret
= getname(pos
.node
); /* a better name */
5092 /* handle choice here ? !!mm!! */
5094 out
->type
= (pos
.type
& TBL_TYPEmask
);
5095 out
->flags
|= OUT_FLAG_type
;
5096 /* showNode(pos.node, 3, 4); */
5097 /* ret = getname(pos.node);*/
5099 out
->data
= pos
.node
;
5100 out
->flags
|= OUT_FLAG_data
;
5102 g_message(" typeref set named number list node %p", (void *)pos
.node
);
5106 pos
.type
= TBL_TYPEREF_nopop
;
5107 if (asn1_verbose
) g_message(" typeref pop");
5108 } else if ((pos
.type
== TBL_ENUMERATED
) || (pos
.type
== TBL_BITSTRING
)){
5109 /* do not enter the named-number list */
5111 pos
.type
= TBL_TYPEREF_nopop
;
5112 if (asn1_verbose
) g_message(" typeref [pop]");
5114 typeflags
|= TBL_REFERENCE
;
5119 if (cons
&& ! cons_handled
) { /* This entity is constructed, expected ? */
5121 case TBL_BOOLEAN
: /* these are not expected to be constructed */
5123 case TBL_OCTETSTRING
:
5127 case TBL_ENUMERATED
:
5129 typeflags
|= TBL_CONSTRUCTED
;
5130 /* this entry has no extra info, next is the same */
5131 out
->flags
|= (OUT_FLAG_dontshow
| OUT_FLAG_constructed
);
5132 if (asn1_verbose
) g_message(" dontshow and set constructed flag");
5134 default: /* others, such as sequences, are expected to be constructed */
5141 if (asn1_verbose
) g_message(" anonymous: dontshow");
5142 if (asn1_debug
) /* this entry has no extra info, next is the same */
5143 out
->flags
|= OUT_FLAG_dontshow
;
5145 out
->name
= empty
; /* show it, but no name */
5148 if (out
->name
!= empty
)
5151 if ( ! (out
->flags
& OUT_FLAG_data
))
5152 out
->data
= pos
.node
; /* for access to named numbers... */
5154 pos
.type
|= typeflags
;
5157 if ( ! (out
->flags
& OUT_FLAG_type
))
5158 out
->type
= pos
.type
;
5160 out
->type
&= TBL_TYPEmask
;
5162 if (ret
== noname
) {
5164 out
->flags
|= OUT_FLAG_noname
;
5167 if (info
&& ((out
->flags
& OUT_FLAG_typename
) == 0)) {
5168 out
->asn1typename
= info
->asn1typename
;
5169 out
->type_id
= info
->typenum
;
5172 if (info
&& (out
->value_id
== -1)) {
5173 out
->value_id
= info
->value_id
;
5174 out
->type_id
= info
->type_id
;
5177 if ((out
->fullname
== 0) && info
)
5178 out
->fullname
= info
->fullname
;
5180 if (typeflags
& TBL_CONSTRUCTED
)
5181 constructed_save
= *out
;
5184 g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out
->type
), out
->name
,
5185 out
->value_id
, out
->type_id
);
5191 getPDUenum(PDUprops
*props
, guint offset
, guint cls
, guint tag
, guint value
)
5195 const char *ret
, *name
;
5196 static char unnamed
[] = "*unnamed*";
5198 (void) cls
; (void) tag
; /* make a reference */
5200 if (props
->flags
& OUT_FLAG_noname
)
5204 list
= (GNode
*)props
->data
;
5207 if (asn1_verbose
) g_message("--off=%d named number list not initialized", offset
);
5209 return "*list-still-0*";
5212 if ((PDUinfo
*)list
->data
)
5213 name
= ((PDUinfo
*)list
->data
)->name
;
5217 for(list
= g_node_first_child(list
); list
; list
= g_node_next_sibling(list
)) {
5218 info
= (PDUinfo
*)list
->data
;
5219 if (value
== info
->tag
) {
5228 g_message("--off=%d namednumber %d=%s from list %s", offset
, value
, ret
, name
);
5232 #endif /* READSYNTAX */
5235 proto_register_asn1(void) {
5237 static const enum_val_t type_recursion_opts
[] = {
5251 gint
*ett
[1+MAX_NEST
+MAXPDU
];
5253 module_t
*asn1_module
;
5255 const char *orig_ptr
;
5257 asn1_logfile
= get_tempfile_path(ASN1LOGFILE
);
5259 current_asn1
= g_strdup("");
5260 asn1_filename
= g_strdup(current_asn1
);
5262 current_pduname
= g_strdup("ASN1");
5263 asn1_pduname
= g_strdup(current_pduname
);
5265 proto_asn1
= proto_register_protocol("ASN.1 decoding",
5269 for (i
=0, j
=1; i
<MAX_NEST
; i
++, j
++) {
5270 ett
[j
] = &ett_seq
[i
];
5273 for(i
=0; i
<MAXPDU
; i
++, j
++) {
5274 ett
[j
] = &ett_pdu
[i
];
5278 proto_register_subtree_array(ett
, array_length(ett
));
5280 asn1_module
= prefs_register_protocol(proto_asn1
,
5281 proto_reg_handoff_asn1
);
5282 #ifdef JUST_ONE_PORT
5283 prefs_register_uint_preference(asn1_module
, "tcp_port",
5285 "The TCP port on which "
5286 "ASN.1 messages will be read",
5287 10, &global_tcp_port_asn1
);
5288 prefs_register_uint_preference(asn1_module
, "udp_port",
5290 "The UDP port on which "
5291 "ASN.1 messages will be read",
5292 10, &global_udp_port_asn1
);
5293 prefs_register_uint_preference(asn1_module
, "sctp_port",
5295 "The SCTP port on which "
5296 "ASN.1 messages will be read",
5297 10, &global_sctp_port_asn1
);
5299 range_convert_str(&global_tcp_ports_asn1
, ep_strdup_printf("%u", TCP_PORT_ASN1
), 65535);
5300 range_convert_str(&global_udp_ports_asn1
, ep_strdup_printf("%u", UDP_PORT_ASN1
), 65535);
5301 range_convert_str(&global_sctp_ports_asn1
, ep_strdup_printf("%u", SCTP_PORT_ASN1
), 65535);
5303 prefs_register_range_preference(asn1_module
, "tcp_ports",
5305 "The TCP ports on which "
5306 "ASN.1 messages will be read",
5307 &global_tcp_ports_asn1
, 65535);
5308 prefs_register_range_preference(asn1_module
, "udp_ports",
5310 "The UDP ports on which "
5311 "ASN.1 messages will be read",
5312 &global_udp_ports_asn1
, 65535);
5313 prefs_register_range_preference(asn1_module
, "sctp_ports",
5315 "The SCTP ports on which "
5316 "ASN.1 messages will be read",
5317 &global_sctp_ports_asn1
, 65535);
5318 #endif /* JUST_ONE_PORT */
5320 prefs_register_bool_preference(asn1_module
, "desegment_messages",
5322 "Desegment ASN.1 messages that span TCP segments",
5325 old_default_asn1_filename
= get_datafile_path(OLD_DEFAULT_ASN1FILE
);
5327 bad_separator_old_default_asn1_filename
= get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE
);
5330 orig_ptr
= asn1_filename
;
5331 prefs_register_filename_preference(asn1_module
, "file",
5332 "ASN.1 type table file",
5333 "Compiled ASN.1 description of ASN.1 types",
5335 /* prefs_register_string_preference just overwrite our pointer with a pointer
5336 * to a _copy_ of our string. Free the original string.
5338 g_free((char *)orig_ptr
);
5340 orig_ptr
= asn1_pduname
;
5341 prefs_register_string_preference(asn1_module
, "pdu_name",
5343 "Name of top level PDU",
5345 g_free((char *)orig_ptr
);
5347 prefs_register_uint_preference(asn1_module
, "first_pdu_offset",
5348 "Offset to first PDU in first tcp packet",
5349 "Offset for non-reassembled packets, "
5350 "wrong if this happens on other than the first packet!",
5351 10, &first_pdu_offset
);
5352 prefs_register_bool_preference(asn1_module
, "flat",
5354 "Show full names for all values",
5356 prefs_register_enum_preference(asn1_module
, "type_recursion",
5357 "Eliminate references to level",
5358 "Allow this recursion level for eliminated type references",
5359 &type_recursion_level
,
5360 type_recursion_opts
, FALSE
);
5361 prefs_register_bool_preference(asn1_module
, "debug",
5363 "Extra output useful for debugging",
5366 prefs_register_bool_preference(asn1_module
, "message_win",
5368 "show full message description",
5371 prefs_register_obsolete_preference(asn1_module
, "message_win");
5373 prefs_register_bool_preference(asn1_module
, "verbose_log",
5374 "Write very verbose log",
5375 "log to file $TMP/" ASN1LOGFILE
,
5379 /* The registration hand-off routing */
5381 static dissector_handle_t asn1_handle
;
5384 register_tcp_port(guint32 port
)
5387 dissector_add_uint("tcp.port", port
, asn1_handle
);
5391 unregister_tcp_port(guint32 port
)
5394 dissector_delete_uint("tcp.port", port
, asn1_handle
);
5398 register_udp_port(guint32 port
)
5401 dissector_add_uint("udp.port", port
, asn1_handle
);
5405 unregister_udp_port(guint32 port
)
5408 dissector_delete_uint("udp.port", port
, asn1_handle
);
5412 register_sctp_port(guint32 port
)
5415 dissector_add_uint("sctp.port", port
, asn1_handle
);
5419 unregister_sctp_port(guint32 port
)
5422 dissector_delete_uint("sctp.port", port
, asn1_handle
);
5426 proto_reg_handoff_asn1(void) {
5427 static gboolean asn1_initialized
= FALSE
;
5428 /* XXX: Note that the "saved" ports [or port ranges] will not be initialized the first time */
5429 /* thru pro_reg_handoff_asn1 if no PDUtree is built; So: we init with the definition. */
5430 #ifdef JUST_ONE_PORT
5431 static guint tcp_port_asn1
= 0;
5432 static guint udp_port_asn1
= 0;
5433 static guint sctp_port_asn1
= 0;
5435 static range_t
*tcp_ports_asn1
= NULL
;
5436 static range_t
*udp_ports_asn1
= NULL
;
5437 static range_t
*sctp_ports_asn1
= NULL
;
5442 #ifdef JUST_ONE_PORT
5443 if (asn1_verbose
) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegment=%d, "
5444 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5445 global_tcp_port_asn1
, global_udp_port_asn1
, global_sctp_port_asn1
, asn1_desegment
,
5446 asn1_filename
, asn1_pduname
, first_pdu_offset
, asn1_debug
, asn1_message_win
, asn1_verbose
);
5449 char *tcp_ports_asn1_string
, *udp_ports_asn1_string
, *sctp_ports_asn1_string
;
5450 tcp_ports_asn1_string
= range_convert_range(global_tcp_ports_asn1
);
5451 udp_ports_asn1_string
= range_convert_range(global_udp_ports_asn1
);
5452 sctp_ports_asn1_string
= range_convert_range(global_sctp_ports_asn1
);
5453 g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegment=%d, "
5454 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5455 tcp_ports_asn1_string
, udp_ports_asn1_string
, sctp_ports_asn1_string
, asn1_desegment
,
5456 asn1_filename
, asn1_pduname
, first_pdu_offset
, asn1_debug
, asn1_message_win
, asn1_verbose
);
5458 #endif /* JUST_ONE_PORT */
5460 if(!asn1_initialized
) {
5461 asn1_handle
= new_create_dissector_handle(dissect_asn1
,proto_asn1
);
5462 asn1_initialized
= TRUE
;
5463 } else { /* clean up ports and their lists */
5464 #ifdef JUST_ONE_PORT
5465 unregister_tcp_port(tcp_port_asn1
);
5466 unregister_udp_port(udp_port_asn1
);
5467 unregister_sctp_port(sctp_port_asn1
);
5469 if (tcp_ports_asn1
!= NULL
) {
5470 range_foreach(tcp_ports_asn1
, unregister_tcp_port
);
5471 g_free(tcp_ports_asn1
);
5474 if (udp_ports_asn1
!= NULL
) {
5475 range_foreach(udp_ports_asn1
, unregister_udp_port
);
5476 g_free(udp_ports_asn1
);
5479 if (sctp_ports_asn1
!= NULL
) {
5480 range_foreach(sctp_ports_asn1
, unregister_sctp_port
);
5481 g_free(sctp_ports_asn1
);
5483 #endif /* JUST_ONE_PORT */
5486 if (strcmp(asn1_filename
, current_asn1
) != 0) {
5487 /* new definitions, parse the file if we have one */
5488 /* !!! should be postponed until we really need it !!! */
5490 read_asn1_type_table(asn1_filename
);
5491 #endif /* READSYNTAX */
5492 g_free(current_asn1
);
5493 current_asn1
= g_strdup(asn1_filename
);
5495 if (!PDUtree
|| /* no tree built yet for PDU type */
5496 strcmp(asn1_pduname
, current_pduname
) != 0) { /* new PDU type, build tree for it */
5497 if (build_pdu_tree(asn1_pduname
)) {
5498 g_free(current_pduname
);
5499 current_pduname
= g_strdup(asn1_pduname
);
5503 if (asn1_message_win
) { /* show what we are prepared to recognize */
5505 gtk_widget_destroy (window
);
5508 create_message_window();
5510 #endif /* SHOWPDU */
5512 /* If we now have a PDU tree, register for the port or ports we have */
5514 #ifdef JUST_ONE_PORT
5515 tcp_port_asn1
= global_tcp_port_asn1
;
5516 udp_port_asn1
= global_udp_port_asn1
;
5517 sctp_port_asn1
= global_sctp_port_asn1
;
5519 register_tcp_port(tcp_port_asn1
);
5520 register_udp_port(udp_port_asn1
);
5521 register_sctp_port(sctp_port_asn1
);
5523 tcp_ports_asn1
= range_copy(global_tcp_ports_asn1
);
5524 udp_ports_asn1
= range_copy(global_udp_ports_asn1
);
5525 sctp_ports_asn1
= range_copy(global_sctp_ports_asn1
);
5527 range_foreach(tcp_ports_asn1
, register_tcp_port
);
5528 range_foreach(udp_ports_asn1
, register_udp_port
);
5529 range_foreach(sctp_ports_asn1
, register_sctp_port
);
5530 #endif /* JUST_ONE_PORT */