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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.
66 #include <sys/types.h>
77 #include <epan/packet.h>
78 #include <epan/addr_resolv.h>
79 #include <epan/prefs.h>
80 #include <epan/strutil.h>
81 #include <epan/filesystem.h>
82 #include <epan/report_err.h>
83 #include <epan/emem.h>
84 #include <epan/dissectors/packet-tcp.h>
85 #include <epan/asn1.h>
86 #include <wiretap/file_util.h>
88 #ifdef DISSECTOR_WITH_GUI
92 #include <epan/ipproto.h>
99 /* Define default ports */
101 #define TCP_PORT_ASN1 801
102 #define UDP_PORT_ASN1 801
103 #define SCTP_PORT_ASN1 801
105 void proto_reg_handoff_asn1(void);
107 /* Define the asn1 proto */
109 static int proto_asn1 = -1;
111 /* Define the tree for asn1*/
113 static int ett_asn1 = -1;
115 #define MAXPDU 64 /* max # PDU's in one packet */
116 static int ett_pdu[MAXPDU];
118 #define MAX_NEST 32 /* max nesting level for ASN.1 elements */
119 static int ett_seq[MAX_NEST];
122 * Global variables associated with the preferences for asn1
126 static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
127 static guint global_udp_port_asn1 = UDP_PORT_ASN1;
128 static guint global_sctp_port_asn1 = SCTP_PORT_ASN1;
129 static guint tcp_port_asn1 = TCP_PORT_ASN1;
130 static guint udp_port_asn1 = UDP_PORT_ASN1;
131 static guint sctp_port_asn1 = SCTP_PORT_ASN1;
133 static range_t *global_tcp_ports_asn1;
134 static range_t *global_udp_ports_asn1;
135 static range_t *global_sctp_ports_asn1;
137 static range_t *tcp_ports_asn1;
138 static range_t *udp_ports_asn1;
139 static range_t *sctp_ports_asn1;
140 #endif /* JUST_ONE_PORT */
142 static gboolean asn1_desegment = TRUE;
143 static const char *asn1_filename = NULL;
144 static char *old_default_asn1_filename = NULL;
145 #define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
147 #define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
148 static char *bad_separator_old_default_asn1_filename = NULL;
150 static char *current_asn1 = NULL;
151 static const char *asn1_pduname = NULL;
152 static char *current_pduname = NULL;
153 static gboolean asn1_debug = FALSE;
154 static guint first_pdu_offset = 0;
155 static gboolean asn1_message_win = FALSE;
156 static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
157 static gboolean asn1_full = FALSE; /* show full names */
158 static guint type_recursion_level = 1; /* eliminate 1 level of references */
159 static char *asn1_logfile = NULL;
161 #define ASN1LOGFILE "wireshark.log"
163 /* PDU counter, for correlation between GUI display and log file in debug mode */
164 static int pcount = 0;
166 static tvbuff_t *asn1_desc; /* the PDU description */
167 static GNode *asn1_nodes = NULL; /* GNode tree pointing to every asn1 data element */
168 static GNode *data_nodes = NULL; /* GNode tree describing the syntax data */
169 static GNode *PDUtree = NULL; /* GNode tree describing the expected PDU format */
171 static guint PDUerrcount = 0; /* count of parse errors in one ASN.1 message */
173 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
176 static char pabbrev[] = "asn1"; /* field prefix */
178 static char fieldname[512]; /* for constructing full names */
179 static guint pabbrev_pdu_len; /* length initial part of fieldname with 'abbrev.asn1pdu.' */
182 * Text strings describing the standard, universal, ASN.1 names.
185 #define ASN1_EOI 4 /* this is in the class number space... */
186 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
188 static const char tag_class[] = "UACPX";
190 static const char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
192 static const char *asn1_con[] = { "Primitive", "Constructed" };
194 static const char *asn1_tag[] = {
195 /* 0 */ "EOC", "Boolean", "Integer", "BitString",
196 /* 4 */ "OctetString", "Null", "ObjectIdentifier", "ObjectDescriptor",
197 /* 8 */ "External", "Real", "Enumerated", "tag11",
198 /* 12 */ "UTF8String", "tag13", "tag14", "tag15",
199 /* 16 */ "Sequence", "Set", "NumericString", "PrintableString",
200 /* 20 */ "TeletexString", "VideotexString", "IA5String", "UTCTime",
201 /* 24 */ "GeneralTime", "GraphicString", "ISO646String", "GeneralString",
202 /* 28 */ "UniversalString", "tag29", "BMPString", "Long tag prefix"
203 /* TT61 == TELETEX */
204 /* ISO646 == VISIBLE*/
207 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
208 static gboolean tbl_types_verified = FALSE;
210 typedef enum { /* copied from .../snacc/c-lib/boot/tbl.h */
219 TBL__SIMPLE = 8, /* values smaller than this can have a value */
227 TBL_SEQUENCEOF_start, /* to mark potential sequence-of repeat */
228 TBL_TYPEREF_nopop, /* typeref has been handled immediately */
229 TBL_CHOICE_done, /* choice is finished */
230 TBL_reserved, /* this sequence has been visited */
231 TBL_CHOICE_immediate, /* immediate choice, no next */
233 TBL_INVALID /* incorrect value for this enum */
236 /* Universal tags mapped to snacc ASN.1 table types */
237 static int asn1_uni_type[] = {
238 /* 0 */ TBL_INVALID, TBL_BOOLEAN, TBL_INTEGER, TBL_BITSTRING,
239 /* 4 */ TBL_OCTETSTRING, TBL_NULL, TBL_OID, TBL_INVALID,
240 /* 8 */ TBL_INVALID, TBL_REAL, TBL_ENUMERATED, TBL_INVALID,
241 /* 12 */ TBL_OCTETSTRING, TBL_INVALID, TBL_INVALID, TBL_INVALID,
242 /* 16 */ TBL_SEQUENCE, TBL_SET, TBL_OCTETSTRING, TBL_OCTETSTRING,
243 /* 20 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
244 /* 24 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
245 /* 28 */ TBL_OCTETSTRING, TBL_INVALID, TBL_OCTETSTRING, TBL_INVALID,
249 #define TBL_REPEAT 0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
250 #define TBL_REPEAT_choice 0x00020000 /* repeating a choice */
251 #define TBL_CHOICE_made 0x00040000 /* This was a choice entry */
252 #define TBL_SEQUENCE_done 0x00080000 /* children have been processed */
253 #define TBL_CHOICE_repeat 0x00100000 /* a repeating choice */
254 #define TBL_REFERENCE 0x00200000 /* This entry is result of a typeref */
255 #define TBL_REFERENCE_pop 0x00400000 /* reference handled, do pop i.s.o. next */
256 #define TBL_SEQUENCE_choice 0x00800000 /* this sequence is a first of a repeating choice */
257 #define TBL_CONSTRUCTED 0x01000000 /* unexpectedly constructed entry */
258 #define TBL_TYPEmask 0x0000FFFF /* Mask just the type */
260 /* XXX - Should we use val_to_str here? */
261 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
263 /* text tables for debugging and GUI */
264 static const char *tbl_types[] = {
265 /* 0 */ "tbl-boolean",
266 /* 1 */ "tbl-integer",
267 /* 2 */ "tbl-bitstring",
268 /* 2 */ "tbl-octetstring",
272 /* 7 */ "tbl-enumerated",
273 /* 8 */ "tbl-sequence",
275 /* 10 */ "tbl-sequenceof",
276 /* 11 */ "tbl-setof",
277 /* 12 */ "tbl-choice",
278 /* 13 */ "tbl-typeref",
280 /* 14 */ "tbl-sequenceof-start",
281 /* 15 */ "tbl-typeref-nopop",
282 /* 16 */ "tbl-choice-done",
283 /* 17 */ "tbl-reserved",
284 /* 18 */ "tbl-choice-immediate",
286 /* 19 */ "tbl-invalid",
288 static const char *tbl_types_asn1[] = {
292 /* 2 */ "OCTET STRING",
294 /* 5 */ "OBJECT IDENTIFIER",
296 /* 7 */ "ENUMERATED",
299 /* 10 */ "SEQUENCE OF",
304 /* 14 */ "start-SEQUENCE OF",
305 /* 15 */ "TYPEREF nopop",
306 /* 16 */ "CHOICE done",
308 /* 18 */ "CHOICE immediate",
310 /* 19 */ "INVALID entry",
312 /* conversion from snacc type to appropriate wireshark type */
313 static guint tbl_types_wireshark[] = {
314 /* 0 */ FT_BOOLEAN, /* TBL_BOOLEAN */
315 /* 1 */ FT_UINT32, /* TBL_INTEGER */
316 /* 2 */ FT_UINT32, /* TBL_BITSTRING */
317 /* 2 */ FT_STRINGZ, /* TBL_OCTETSTRING */
318 /* 4 */ FT_NONE, /* TBL_NULL */
319 /* 5 */ FT_BYTES, /* TBL_OID */
320 /* 6 */ FT_DOUBLE, /* TBL_REAL */
321 /* 7 */ FT_UINT32, /* TBL_ENUMERATED */
322 /* 8 */ FT_NONE, /* TBL_SEQUENCE */
323 /* 9 */ FT_NONE, /* TBL_SET */
324 /* 10 */ FT_NONE, /* TBL_SEQUENCEOF */
325 /* 11 */ FT_NONE, /* TBL_SETOF */
326 /* 12 */ FT_NONE, /* TBL_CHOICE */
327 /* 13 */ FT_NONE, /* TBL_TYPEREF */
329 /* 14 */ FT_NONE, /* TBL_SEQUENCEOF_start */
330 /* 15 */ FT_NONE, /* TBL_TYPEREF_nopop */
331 /* 16 */ FT_NONE, /* TBL_CHOICE_done */
332 /* 17 */ FT_NONE, /* TBL_reserved */
333 /* 18 */ FT_NONE, /* TBL_CHOICE_immediate */
335 /* 19 */ FT_NONE, /* TBL_INVALID */
338 static const char *tbl_types_wireshark_txt[] = {
339 /* 0 */ "FT_BOOLEAN", /* TBL_BOOLEAN */
340 /* 1 */ "FT_UINT32", /* TBL_INTEGER */
341 /* 2 */ "FT_UINT32", /* TBL_BITSTRING */
342 /* 2 */ "FT_STRINGZ", /* TBL_OCTETSTRING */
343 /* 4 */ "FT_NONE", /* TBL_NULL */
344 /* 5 */ "FT_BYTES", /* TBL_OID */
345 /* 6 */ "FT_DOUBLE", /* TBL_REAL */
346 /* 7 */ "FT_UINT32", /* TBL_ENUMERATED */
347 /* 8 */ "FT_NONE", /* TBL_SEQUENCE */
348 /* 9 */ "FT_NONE", /* TBL_SET */
349 /* 10 */ "FT_NONE", /* TBL_SEQUENCEOF */
350 /* 11 */ "FT_NONE", /* TBL_SETOF */
351 /* 12 */ "FT_NONE", /* TBL_CHOICE */
352 /* 13 */ "FT_NONE", /* TBL_TYPEREF */
354 /* 14 */ "FT_NONE", /* TBL_SEQUENCEOF_start */
355 /* 15 */ "FT_NONE", /* TBL_TYPEREF_nopop */
356 /* 16 */ "FT_NONE", /* TBL_CHOICE_done */
357 /* 17 */ "FT_NONE", /* TBL_reserved */
358 /* 18 */ "FT_NONE", /* TBL_CHOICE_immediate */
360 /* 19 */ "FT_NONE", /* TBL_INVALID */
363 typedef struct _PDUinfo PDUinfo;
367 const char *typename;
368 const char *fullname;
374 gint basetype; /* parent type */
375 gint mytype; /* original type number, typenum may have gone through a reference */
376 gint value_id; /* wireshark field id for the value in this PDU */
377 gint type_id; /* wireshark field id for the type of this PDU */
378 hf_register_info value_hf; /* wireshark field info for this value */
382 /* bits in the flags collection */
383 #define PDU_OPTIONAL 1
384 #define PDU_IMPLICIT 2
385 #define PDU_NAMEDNUM 4
386 #define PDU_REFERENCE 8
387 #define PDU_TYPEDEF 0x10
388 #define PDU_ANONYMOUS 0x20
389 #define PDU_TYPETREE 0x40
391 #define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
393 static guint PDUinfo_initflags = 0; /* default flags for newly allocated PDUinfo structs */
395 /* description of PDU properties as passed from the matching routine
396 * to the decoder and GUI.
398 typedef struct _PDUprops PDUprops;
400 guint type; /* value from enum TBLTypeId */
402 const char *typename;
403 const char *fullname;
409 /* flags defined in PDUprops.flags */
410 #define OUT_FLAG_type 1
411 #define OUT_FLAG_data 2
412 #define OUT_FLAG_typename 4
413 #define OUT_FLAG_dontshow 8
414 #define OUT_FLAG_noname 0x10
415 #define OUT_FLAG_constructed 0x20
417 static PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
418 static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
420 static const char empty[] = ""; /* address of the empt string, avoids many tests for NULL */
421 #define MAX_OTSLEN 256 /* max printed size for an octet string */
424 #undef NEST /* show nesting of asn.1 enties */
426 #ifdef NEST /* only for debugging */
427 /* show nesting, only for debugging... */
428 #define MAXTAGS MAX_NEST
434 static char *showtaglist(guint level)
436 static char tagtxt[BUFLM];
441 for(i=0; i<= level; i++) {
442 switch(taglist[i].cls) {
443 case ASN1_UNI: *p++ = 'U'; break;
444 case ASN1_APL: *p++ = 'A'; break;
445 case ASN1_CTX: *p++ = 'C'; break;
446 case ASN1_PRV: *p++ = 'P'; break;
447 default: *p++ = 'x'; break;
449 p += sprintf(p, "%d.", taglist[i].tag);
451 #else /* only context tags */
453 for(i=0; i<= level; i++) {
454 if (taglist[i].cls == ASN1_CTX) {
455 p += sprintf(p, "%d.", taglist[i].tag);
459 *--p = 0; /* remove trailing '.' */
464 get_context(guint level)
469 for(i=0; i<=level; i++) {
470 if (taglist[i].cls == ASN1_CTX)
471 ctx = (ctx << 8) | taglist[i].tag;
475 #endif /* NEST, only for debugging */
478 /* Convert a bit string to an ascii representation for printing
479 * -- not thread safe ...
481 static const char *showbits(guchar *val, guint count)
483 static char str[BUFLM];
488 return "*too many bits*";
491 for(i=0; i<count; i++) {
492 if (i && ((i & 7) == 0)) *p++ = ' ';
493 *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
500 /* get bitnames string for bits set */
502 showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
504 static char str[BUFLL];
508 if (props->flags & OUT_FLAG_noname)
512 return "*too many bits, no names...*";
515 for(i=0; i<count; i++) {
516 if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
517 p += sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
521 --p; /* remove terminating , */
529 /* Convert an oid to its conventional text representation
530 * -- not thread safe...
532 static char *showoid(subid_t *oid, guint len)
534 static char str[BUFLM];
539 for(i=0; i<len; i++) {
541 p += sprintf(p, "%lu", (unsigned long)oid[i]);
548 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
550 showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
555 const char *endstr = empty;
561 for (i=0; i<len; i++) {
562 if (!isprint(octets[i])) /* maybe isblank() as well ... */
565 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
567 endstr = "...."; /* this is 5 bytes !! */
570 str = p = g_malloc(len*2 + 5);
571 for (i=0; i<len; i++) {
572 p += sprintf(p, "%2.2X", octets[i]);
576 if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
577 str = p = g_malloc(len*3+2);
578 for (i=0; i<len; i++) {
579 p += sprintf(p, "%2.2X", octets[i]);
581 *p++ = ' '; /* insert space */
582 strncpy(p, octets, len);
585 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
586 str = g_malloc(len+5);
587 strncpy(str, octets, len);
588 strcpy(&str[len], endstr);
595 /* allow NULL pointers in strcmp, handle them as empty strings */
597 g_strcmp(gconstpointer a, gconstpointer b)
599 if (a == 0) a = empty;
600 if (b == 0) b = empty;
604 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
605 /* WARNING WARNING WARNING WARNING WARNING WARNING */
607 /* Most of the following routine is guesswork in order to */
608 /* speed up resynchronisation if the dissector lost the */
609 /* encoding due to incomplete captures, or a capture that */
610 /* starts in the middle of a fragmented ip packet */
611 /* If this poses to many problems, these settings can be */
612 /* made part of the protocol settings in the user interface */
613 /*************************************************************/
615 /* check length for a reasonable value, return a corrected value */
617 checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
622 g_snprintf(lenstr, strmax, "indefinite");
626 if (len < 0) /* negative ..... */
629 if (cls != ASN1_UNI) { /* don't know about the tags */
634 case ASN1_EOC: /* End Of Contents */
635 case ASN1_NUL: /* Null */
638 case ASN1_BOL: /* Boolean */
641 case ASN1_INT: /* Integer */
642 case ASN1_ENUM: /* Enumerated */
646 case ASN1_BTS: /* Bit String */
650 case ASN1_OTS: /* Octet String */
651 case ASN1_NUMSTR: /* Numerical String */
652 case ASN1_PRNSTR: /* Printable String */
653 case ASN1_TEXSTR: /* Teletext String */
654 case ASN1_VIDSTR: /* Video String */
655 case ASN1_IA5STR: /* IA5 String */
656 case ASN1_GRASTR: /* Graphical String */
657 case ASN1_VISSTR: /* Visible String */
658 case ASN1_GENSTR: /* General String */
662 case ASN1_OJI: /* Object Identifier */
663 case ASN1_OJD: /* Description */
664 case ASN1_EXT: /* External */
668 case ASN1_REAL: /* Real */
672 case ASN1_SEQ: /* Sequence */
673 case ASN1_SET: /* Set */
677 case ASN1_UNITIM: /* Universal Time */
678 case ASN1_GENTIM: /* General Time */
691 /* a change was needed.... */
692 g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
694 g_snprintf(lenstr, strmax, "%d", len);
699 static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
700 static void PDUreset(int count, int counr2);
703 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
706 guint cls, con, tag, def, len, offset, reassembled;
711 const char *name, *tname;
712 volatile guint boffset;
713 volatile int i = 0; /* PDU counter */
714 proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
716 static guint lastseq;
721 reassembled = 1; /* UDP is not a stream, and thus always reassembled .... */
722 if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
723 struct tcpinfo *info = (struct tcpinfo *)pinfo->private_data;
724 gint delta = info->seq - lastseq;
725 reassembled = info->is_reassembled;
729 g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
730 info->seq, delta, reassembled);
733 g_message("dissect_asn1: udp");
736 /* Set the protocol column */
737 if(check_col(pinfo->cinfo, COL_PROTOCOL)){
738 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
741 if(check_col(pinfo->cinfo, COL_INFO))
742 col_clear(pinfo->cinfo, COL_INFO);
746 if ((first_pdu_offset > 0) && !reassembled) {
747 boffset = first_pdu_offset;
748 g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
751 /* open BER decoding */
752 asn1_open(&asn1, tvb, boffset);
754 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
756 asn1_close(&asn1, &offset);
758 PDUreset(pcount, 0); /* arguments are just for debugging */
759 getPDUprops(&props, boffset, cls, tag, con);
761 tname = props.typename;
763 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
767 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
769 g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
776 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
782 if (props.flags & OUT_FLAG_noname) {
783 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
784 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
786 g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
789 /* Set the info column */
790 if(check_col(pinfo->cinfo, COL_INFO)){
791 col_add_str(pinfo->cinfo, COL_INFO, headstr );
795 * If we have a non-null tree (ie we are building the proto_tree
796 * instead of just filling out the columns ), then add a BER
800 /* ignore the tree here, must decode BER to know how to reassemble!! */
803 TRY { /* catch incomplete PDU's */
805 ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
806 def? (int) (offset - boffset + len) : -1,
807 "ASN.1 %s", current_pduname);
809 tree2 = proto_item_add_subtree(ti, ett_asn1);
811 proto_tree_add_item_hidden(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
812 def? (int) (offset - boffset + len) : -1, TRUE);
814 offset = boffset; /* the first packet */
815 while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
818 /* open BER decoding */
819 asn1_open(&asn1, tvb, offset);
820 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
821 asn1_close(&asn1, &offset);
823 PDUreset(pcount, i+1);
824 getPDUprops(&props, boffset, cls, tag, con);
826 tname = props.typename;
829 len = tvb_length_remaining(tvb, offset);
831 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
835 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
837 g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
840 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
843 tvb_length_remaining(tvb, offset) );
845 if (props.value_id == -1)
846 ti2 = proto_tree_add_text(tree2, tvb, boffset,
847 def? (int) (offset - boffset + len) : -1,
848 "%s: (%s)%s %d-%d %s", current_pduname,
849 tname, name, pcount, i+1, headstr);
851 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
852 def? (int) (offset - boffset + len) : -1,
853 "%s: (%s)%s %d-%d %s ~", current_pduname,
854 tname, name, pcount, i+1, headstr);
856 if (props.type_id != -1)
857 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
858 def? (int) (offset - boffset + len) : -1, TRUE);
862 if (props.flags & OUT_FLAG_noname) {
863 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
864 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
866 if (props.value_id == -1)
867 ti2 = proto_tree_add_text(tree2, tvb, boffset,
868 def? (int) (offset - boffset + len) : -1,
869 "%s: (%s)%s", current_pduname, tname, name);
871 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
872 def? (int) (offset - boffset + len) : -1,
873 "%s: (%s)%s ~", current_pduname, tname, name);
874 if (props.type_id != -1)
875 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
876 def? (int) (offset - boffset + len) : -1, TRUE);
879 asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
882 taglist[0].cls = cls;
883 taglist[0].tag = tag;
886 if (!def) len++; /* make sure we get an exception if we run off the end! */
888 offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
890 proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
892 i++; /* one more full message handled */
894 if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
895 proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
897 if(check_col(pinfo->cinfo, COL_INFO))
898 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
900 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
905 CATCH(ReportedBoundsError) {
906 if(check_col(pinfo->cinfo, COL_INFO))
907 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
909 proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
911 proto_item_append_text(ti2, " (incomplete)");
912 if (asn1_desegment) {
913 pinfo->desegment_offset = boffset;
914 pinfo->desegment_len = 1;
916 g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
917 boffset, 1, pinfo->can_desegment);
925 g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
926 pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
929 /* decode an ASN.1 sequence, until we have consumed the specified length */
931 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
934 guint ret, cls, con, tag, def, len, boffset, soffset, eos;
936 const char *clsstr, *constr, *tagstr;
940 proto_tree *ti, *pt2;
941 guchar *octets, *bits, unused;
943 /* the debugging formats */
944 static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s"; /* decimal */
945 static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s"; /* enum */
946 static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s"; /* octet string */
947 static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s"; /* bit field */
948 static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s"; /* constructed */
949 static char matchind[] = " ~"; /* indication of possible match */
950 const char *name, *ename, *tname;
954 ti = 0; /* suppress gcc warning */
956 soffset = offset; /* where this sequence starts */
958 while (offset < eos) { /* while this entity has not ended... */
960 asn1_open(&asn1, tvb, offset);
961 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
962 asn1_close(&asn1, &offset); /* mark current position */
963 if (ret != ASN1_ERR_NOERROR) {
964 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
968 getPDUprops(&props, boffset, cls, tag, con);
970 tname = props.typename;
972 name = &props.fullname[pabbrev_pdu_len]; /* no abbrev.pduname */
973 if (asn1_debug) { /* show both names */
974 sprintf(fieldname, "%s[%s]", props.name, props.fullname);
978 clsstr = asn1_cls[cls];
979 constr = asn1_con[con];
980 if ((cls == ASN1_UNI) && ( tag < 32 )) {
981 tagstr = asn1_tag[tag];
983 g_snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
987 len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
990 g_snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
992 strncpy(nnbuf, "NN-", sizeof(nnbuf));
993 /* make sure we get an exception if we run off the end! */
994 len = tvb_length_remaining(tvb, offset) + 1;
996 if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
997 /* just give type name if we don't know any better */
999 name = nnbuf; /* this is better than just empty.... */
1003 taglist[level].cls = cls;
1004 taglist[level].tag = tag;
1008 if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
1011 oname = g_malloc(strlen(name) + 32);
1012 sprintf(oname, "%s ** nesting cut off **", name);
1016 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
1019 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1020 asn1_close(&asn1, &offset); /* mark where we are now */
1022 if ( (props.value_id == -1) ||
1023 (tbl_types_wireshark[props.type] != FT_UINT32) )
1024 /* unknown or unexpected: just text */
1025 proto_tree_add_text(pt, tvb, boffset,
1026 offset - boffset, textfmt_d, boffset,
1027 clsstr, constr, tagstr, tname, name, value,
1030 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1031 offset - boffset, value, textfmt_d, boffset,
1032 clsstr, constr, tagstr, tname, name, value,
1034 if (props.type_id != -1)
1035 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1036 boffset, offset - boffset, value);
1039 if ( (props.value_id == -1) ||
1040 (tbl_types_wireshark[props.type] != FT_UINT32) )
1041 /* unknown or unexpected, just text */
1042 proto_tree_add_text(pt, tvb, boffset,
1044 "(%s)%s: %d", tname, name, value);
1046 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1047 offset - boffset, value,
1048 "(%s)%s: %d ~", tname, name, value);
1049 if (props.type_id != -1)
1050 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1051 boffset, offset - boffset, value);
1057 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1058 asn1_close(&asn1, &offset); /* mark where we are now */
1059 ename = getPDUenum(&props, boffset, cls, tag, value);
1061 if ( (props.value_id == -1) ||
1062 (tbl_types_wireshark[props.type] != FT_UINT32) )
1063 /* unknown or unexpected, just text */
1064 proto_tree_add_text(pt, tvb, boffset,
1066 textfmt_e, boffset, clsstr, constr, tagstr,
1067 tname, name, value, ename, empty);
1069 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1070 offset - boffset, value,
1071 textfmt_e, boffset, clsstr, constr, tagstr,
1072 tname, name, value, ename, matchind);
1073 if (props.type_id != -1)
1074 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1075 boffset, offset - boffset, value);
1078 if ( (props.value_id == -1) ||
1079 (tbl_types_wireshark[props.type] != FT_UINT32) )
1080 /* unknown or unexpected, just text */
1081 proto_tree_add_text(pt, tvb, boffset,
1083 "(%s)%s: %d:%s", tname, name, value, ename);
1085 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1086 offset - boffset, value,
1087 "(%s)%s: %d:%s ~", tname, name, value, ename);
1088 if (props.type_id != -1)
1089 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1090 boffset, offset - boffset, value);
1096 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1097 asn1_close(&asn1, &offset); /* mark where we are now */
1099 if ( (props.value_id == -1) ||
1100 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1101 /* unknown or unexpected, just text */
1102 proto_tree_add_text(pt, tvb, boffset,
1104 textfmt_s, boffset, clsstr, constr, tagstr,
1105 tname, name, value? "true" : "false", empty);
1107 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1108 offset - boffset, value != 0,
1109 textfmt_s, boffset, clsstr, constr, tagstr,
1110 tname, name, value? "true" : "false", matchind);
1111 if (props.type_id != -1)
1112 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1113 boffset, offset - boffset, value != 0);
1116 if ( (props.value_id == -1) ||
1117 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1118 /* unknown or unexpected, just text */
1119 proto_tree_add_text(pt, tvb, boffset,
1121 "(%s)%s: %s", tname, name,
1122 value? "true" : "false");
1124 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1125 offset - boffset, value != 0,
1126 "(%s)%s: %s ~", tname, name,
1127 value? "true" : "false");
1128 if (props.type_id != -1)
1129 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1130 boffset, offset - boffset, value != 0);
1143 /* read value, \0 terminated */
1144 ret = asn1_string_value_decode(&asn1, len, &octets);
1145 asn1_close(&asn1, &offset); /* mark where we are now */
1146 ename = showoctets(octets, len, (tag == ASN1_OTS) ? 4 : 0 );
1148 if ( (props.value_id == -1) ||
1149 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1150 /* unknown or unexpected, just text */
1151 proto_tree_add_text(pt, tvb, boffset,
1153 textfmt_s, boffset, clsstr, constr, tagstr,
1154 tname, name, ename, empty);
1156 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1157 offset - boffset, octets, /* \0 termnated */
1158 textfmt_s, boffset, clsstr, constr, tagstr,
1159 tname, name, ename, matchind);
1160 if (props.type_id != -1)
1161 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1162 boffset, offset - boffset, octets);
1165 if ( (props.value_id == -1) ||
1166 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1167 /* unknown or unexpected, just text */
1168 proto_tree_add_text(pt, tvb, boffset,
1170 "(%s)%s: %s", tname, name, ename);
1172 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1173 offset - boffset, octets, /* \0 terminated */
1174 "(%s)%s: %s ~", tname, name, ename);
1175 if (props.type_id != -1)
1176 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1177 boffset, offset - boffset, octets);
1185 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1186 asn1_close(&asn1, &offset); /* mark where we are now */
1187 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1189 if ( (props.value_id == -1) ||
1190 (tbl_types_wireshark[props.type] != FT_UINT32) )
1191 /* unknown or unexpected, just text */
1192 proto_tree_add_text(pt, tvb, boffset,
1194 textfmt_b, boffset, clsstr, constr, tagstr,
1196 showbits(bits, (con*8)-unused), ename, empty);
1198 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1199 offset - boffset, *bits, /* XXX length ? XXX */
1200 textfmt_b, boffset, clsstr, constr, tagstr,
1202 showbits(bits, (con*8)-unused),ename, matchind);
1203 if (props.type_id != -1)
1204 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1205 boffset, offset - boffset, *bits);
1209 if ( (props.value_id == -1) ||
1210 (tbl_types_wireshark[props.type] != FT_UINT32) )
1211 /* unknown or unexpected, just text */
1212 proto_tree_add_text(pt, tvb, boffset,
1214 "(%s)%s: %s:%s", tname, name,
1215 showbits(bits, (con*8)-unused), ename);
1217 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1218 offset - boffset, *bits, /* XXX length ? XXX */
1219 "(%s)%s: %s:%s ~", tname, name,
1220 showbits(bits, (con*8)-unused), ename);
1221 if (props.type_id != -1)
1222 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1223 boffset, offset - boffset, *bits);
1231 /* show full sequence length */
1234 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1236 if ( (props.flags & OUT_FLAG_constructed))
1237 ename = ", unexpected constructed";
1239 if (props.value_id == -1)
1240 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1241 textfmt_c, boffset, clsstr, constr, tagstr,
1242 tname, name, ename, empty);
1244 ti = proto_tree_add_item(pt, props.value_id, tvb,
1246 /* change te text to to what I really want */
1247 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1248 tagstr, tname, name, ename, matchind);
1249 if (props.type_id != -1)
1250 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1254 if (props.value_id == -1) {
1255 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1256 ti = proto_tree_add_text(pt, tvb, boffset,
1257 offset - boffset + len,
1258 "(%s)%s", tname, name);
1260 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1261 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1262 boffset, offset - boffset + len,
1263 "(%s)%s ~", tname, name);
1265 /* don't care about the text */
1266 ti = proto_tree_add_item_hidden(pt, props.value_id, tvb,
1269 if (props.type_id != -1)
1270 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1274 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1276 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1277 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1281 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1283 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1284 proto_item_set_len(ti, offset - boffset);
1289 if (asn1_debug) { /* don't show if not debugging */
1290 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1291 boffset, clsstr, constr, tagstr, tname, name,
1292 offset - soffset, empty);
1294 getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1298 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1299 asn1_close(&asn1, &offset); /* mark where we are now */
1300 ename = showoid(oid, con);
1302 if ( (props.value_id == -1) ||
1303 (tbl_types_wireshark[props.type] != FT_BYTES) )
1304 /* unknown or unexpected, just text */
1305 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1306 boffset, clsstr, constr, tagstr, tname, name,
1309 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1310 offset - boffset, ename,/* XXX length?*/
1311 "(%s)%s: %s ~", tname, name, ename);
1312 if (props.type_id != -1)
1313 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1314 boffset, offset - boffset, ename);
1317 if ( (props.value_id == -1) ||
1318 (tbl_types_wireshark[props.type] != FT_BYTES) )
1319 /* unknown or unexpected, just text */
1320 proto_tree_add_text(pt, tvb, boffset,
1322 "(%s)%s: %s", tname, name, ename);
1324 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1325 offset - boffset, ename, /* XXX length ? */
1326 "(%s)%s: %s ~", tname, name, ename);
1327 if (props.type_id != -1)
1328 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1329 boffset, offset - boffset, ename);
1337 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1338 boffset, clsstr, constr, tagstr, tname, name,
1341 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1342 "(%s)%s: [NULL]", tname, name);
1344 offset += len; /* skip value ... */
1356 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1357 textfmt_s, boffset, clsstr, constr, tagstr,
1358 tname, name, lenbuf, empty);
1360 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1361 "(%s)%s: %s bytes", tname, name, lenbuf);
1363 proto_item_append_text(ti, " *"); /* indicate default is used */
1364 offset += len; /* skip value ... */
1369 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1370 case ASN1_APL: /* fprintf(stderr, "Application\n"); */
1371 case ASN1_PRV: /* fprintf(stderr, "Private\n"); */
1374 if (props.value_id == -1) /* type unknown, handle as string */
1376 switch(props.type) {
1377 /* this is via the asn1 description, don't trust the length */
1381 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1382 asn1_close(&asn1, &offset); /* mark where we are now */
1384 if ( (props.value_id == -1) ||
1385 (tbl_types_wireshark[props.type] != FT_UINT32) )
1386 /* unknown or unexpected, just text */
1387 proto_tree_add_text(pt, tvb,
1388 boffset, offset - boffset,
1389 textfmt_d, boffset, clsstr, constr,
1390 tagstr, tname, name, value, empty);
1392 proto_tree_add_uint_format(pt, props.value_id, tvb,
1393 boffset, offset - boffset, value,
1394 textfmt_d, boffset, clsstr, constr,
1395 tagstr, tname, name, value, matchind);
1396 if (props.type_id != -1)
1397 proto_tree_add_uint_hidden(pt, props.type_id,
1398 tvb, boffset, offset - boffset, value);
1401 if ( (props.value_id == -1) ||
1402 (tbl_types_wireshark[props.type] != FT_UINT32) )
1403 /* unknown or unexpected, just text */
1404 proto_tree_add_text(pt, tvb,
1405 boffset, offset - boffset,
1406 "(%s)%s: %d", tname, name, value);
1408 proto_tree_add_uint_format(pt, props.value_id, tvb,
1409 boffset, offset - boffset, value,
1410 "(%s)%s: %d ~", tname, name, value);
1411 if (props.type_id != -1)
1412 proto_tree_add_uint_hidden(pt, props.type_id,
1413 tvb, boffset, offset - boffset, value);
1418 case TBL_ENUMERATED:
1421 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1422 asn1_close(&asn1, &offset); /* mark where we are now */
1423 ename = getPDUenum(&props, boffset, cls, tag, value);
1425 if ( (props.value_id == -1) ||
1426 (tbl_types_wireshark[props.type] != FT_UINT32) )
1427 /* unknown or unexpected, just text */
1428 proto_tree_add_text(pt, tvb,
1429 boffset, offset - boffset,
1430 textfmt_e, boffset, clsstr, constr,
1431 tagstr, tname, name, value, ename, empty);
1433 proto_tree_add_uint_format(pt, props.value_id, tvb,
1434 boffset, offset - boffset, value,
1435 textfmt_e, boffset, clsstr, constr,
1436 tagstr, tname, name, value, ename, matchind);
1437 if (props.type_id != -1)
1438 proto_tree_add_uint_hidden(pt, props.type_id,
1439 tvb, boffset, offset - boffset, value);
1442 if ( (props.value_id == -1) ||
1443 (tbl_types_wireshark[props.type] != FT_UINT32) )
1444 /* unknown or unexpected, just text */
1445 proto_tree_add_text(pt, tvb,
1446 boffset, offset - boffset,
1447 "(%s)%s: %d:%s", tname, name, value, ename);
1449 proto_tree_add_uint_format(pt, props.value_id, tvb,
1450 boffset, offset - boffset, value,
1451 "(%s)%s: %d:%s ~", tname, name, value, ename);
1452 if (props.type_id != -1)
1453 proto_tree_add_uint_hidden(pt, props.type_id,
1454 tvb, boffset, offset - boffset, value);
1459 if (len > (1+4)) /* max 32 bits ...?.. */
1462 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1463 asn1_close(&asn1, &offset); /* mark where we are now */
1464 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1466 if ( (props.value_id == -1) ||
1467 (tbl_types_wireshark[props.type] != FT_UINT32) )
1468 /* unknown or unexpected, just text */
1469 proto_tree_add_text(pt, tvb,
1470 boffset, offset - boffset,
1471 textfmt_b, boffset, clsstr, constr,
1472 tagstr, tname, name,
1473 showbits(bits, (con*8)-unused), ename,
1476 proto_tree_add_uint_format(pt, props.value_id, tvb,
1477 boffset, offset - boffset, *bits,
1478 textfmt_b, boffset, clsstr, constr,
1479 tagstr, tname, name,
1480 showbits(bits, (con*8)-unused), ename,
1482 if (props.type_id != -1)
1483 proto_tree_add_uint_hidden(pt, props.type_id,
1484 tvb, boffset, offset - boffset, *bits);
1487 if ( (props.value_id == -1) ||
1488 (tbl_types_wireshark[props.type] != FT_UINT32) )
1489 /* unknown or unexpected, just text */
1490 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1491 "(%s)%s: %s:%s", tname, name,
1492 showbits(bits, (con*8)-unused), ename);
1494 proto_tree_add_uint_format(pt, props.value_id, tvb,
1495 boffset, offset - boffset, *bits,
1496 "(%s)%s: %s:%s ~", tname, name,
1497 showbits(bits, (con*8)-unused), ename);
1498 if (props.type_id != -1)
1499 proto_tree_add_uint_hidden(pt, props.type_id,
1500 tvb, boffset, offset - boffset, *bits);
1508 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1509 asn1_close(&asn1, &offset); /* mark where we are now */
1511 if ( (props.value_id == -1) ||
1512 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1513 /* unknown or unexpected, just text */
1514 proto_tree_add_text(pt, tvb,
1515 boffset, offset - boffset,
1516 textfmt_s, boffset, clsstr, constr,
1517 tagstr, tname, name,
1518 value? "true" : "false", empty);
1520 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1521 boffset, offset - boffset, value != 0,
1522 textfmt_s, boffset, clsstr, constr,
1523 tagstr, tname, name,
1524 value? "true" : "false", matchind);
1525 if (props.type_id != -1)
1526 proto_tree_add_boolean_hidden(pt, props.type_id,
1527 tvb, boffset, offset - boffset, value != 0);
1530 if ( (props.value_id == -1) ||
1531 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1532 /* unknown or unexpected, just text */
1533 proto_tree_add_text(pt, tvb,
1534 boffset, offset - boffset,
1535 "(%s)%s: %s", tname, name,
1536 value? "true" : "false");
1538 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1539 boffset, offset - boffset, value != 0,
1540 "(%s)%s: %s ~", tname, name,
1541 value? "true" : "false");
1542 if (props.type_id != -1)
1543 proto_tree_add_boolean_hidden(pt, props.type_id,
1544 tvb, boffset, offset - boffset, value != 0);
1552 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1553 textfmt_s, boffset, clsstr, constr,
1554 tagstr, tname, name, "[NULL]", empty);
1556 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1557 "(%s)%s: [NULL]", tname, name);
1559 offset += len; /* skip value ... */
1563 props.value_id = -1; /* unlikely this is correct, dont use it */
1565 case TBL_OCTETSTRING:
1566 /* defined length, not constructed, must be a string.... */
1567 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1568 asn1_close(&asn1, &offset); /* mark where we are now */
1569 ename = showoctets(octets, len, 2); /* convert octets to printable */
1571 if ( (props.value_id == -1) ||
1572 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1573 /* unknown or unexpected, just text */
1574 proto_tree_add_text(pt, tvb,
1575 boffset, offset - boffset,
1576 textfmt_s, boffset, clsstr, constr,
1577 tagstr, tname, name, ename, empty);
1579 proto_tree_add_string_format(pt, props.value_id, tvb,
1580 boffset, offset - boffset, octets, /* XXX */
1581 textfmt_s, boffset, clsstr, constr,
1582 tagstr, tname, name, ename, matchind);
1583 if (props.type_id != -1)
1584 proto_tree_add_string_hidden(pt, props.type_id,
1585 tvb, boffset, offset - boffset, octets);
1588 if ( (props.value_id == -1) ||
1589 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1590 /* unknown or unexpected, just text */
1591 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1592 "(%s)%s: %s", tname, name, ename);
1594 proto_tree_add_string_format(pt, props.value_id, tvb,
1595 boffset, offset - boffset, octets, /* XXX */
1596 "(%s)%s: %s ~", tname, name, ename);
1597 if (props.type_id != -1)
1598 proto_tree_add_string_hidden(pt, props.type_id,
1599 tvb, boffset, offset - boffset, octets);
1607 /* indefinite length or constructed.... must be a sequence .... */
1608 /* show full sequence length */
1611 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1613 if ( (props.flags & OUT_FLAG_constructed))
1614 ename = ", unexpected constructed";
1616 if (props.value_id == -1)
1617 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1618 textfmt_c, boffset, clsstr, constr,
1619 tagstr, tname, name, ename, empty);
1621 ti = proto_tree_add_item(pt, props.value_id, tvb,
1623 /* change te text to to what I really want */
1625 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1626 tagstr, tname, name, ename, matchind);
1627 if (props.type_id != -1)
1628 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1631 ti = proto_tree_add_text(pt, tvb, boffset,
1632 offset - boffset + len,
1633 textfmt_c, boffset, clsstr, constr,
1634 tagstr, tname, name, ename, empty);
1638 if (props.value_id == -1) {
1639 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1640 ti = proto_tree_add_text(pt, tvb, boffset,
1641 offset - boffset + len, "(%s)%s", tname, name);
1643 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1644 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1646 "(%s)%s ~", tname, name);
1648 /* don't care about the text */
1649 ti = proto_tree_add_item_hidden(pt, props.value_id,
1650 tvb, boffset, 1, TRUE);
1652 if (props.type_id != -1)
1653 proto_tree_add_item_hidden(pt, props.type_id,
1654 tvb, boffset, 1, TRUE);
1658 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1660 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1661 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1665 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1667 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1668 proto_item_set_len(ti, offset - boffset);
1672 default: /* fprintf(stderr, "Other\n"); */
1674 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1675 textfmt_s, boffset, clsstr, constr, tagstr,
1676 tname, name, lenbuf, empty);
1678 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1679 "(%s)%s: %s bytes %s data", tname, name,
1682 proto_item_append_text(ti, " *"); /* indicate default is used */
1683 offset += len; /* skip value ... */
1686 g_free(oname); /* XXX, memory management ? */
1688 /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1690 getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1697 /************************************************************************************************/
1698 /* search throug the ASN.1 description for appropriate names */
1699 /************************************************************************************************/
1701 guint lev_limit = G_MAXINT;
1703 int icount = 0; /* item counter */
1706 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1709 guint eos, ret, cls, con, tag, def, len, value;
1710 guchar *octets, *bits, unused;
1712 const char *clsstr, *constr, *tagstr;
1715 GNode *cur_node = 0;
1717 eos = offset + size;
1719 if (level > lev_limit)
1722 while(offset < eos) {
1723 if (ptr) /* build pointer tree to all asn1 enteties */
1724 cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
1726 asn1_open(&asn1, tvb, offset);
1727 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1728 asn1_close(&asn1, &offset); /* mark where we are */
1730 clsstr = asn1_cls[cls];
1731 constr = asn1_con[con];
1732 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1733 tagstr = asn1_tag[tag];
1735 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1739 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1741 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1742 len = tvb_length_remaining(tvb, offset);
1746 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
1750 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1751 asn1_close(&asn1, &offset); /* mark where we are */
1755 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1756 asn1_close(&asn1, &offset); /* mark where we are */
1767 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1768 asn1_close(&asn1, &offset); /* mark where we are */
1773 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1774 asn1_close(&asn1, &offset); /* mark where we are */
1780 if (len == 0) /* don't recurse if offset isn't going to change */
1783 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1790 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1791 asn1_close(&asn1, &offset); /* mark where we are */
1807 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1808 offset += len; /* skip value ... */
1813 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1815 g_snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
1817 /* defined length, not constructed, must be a string.... */
1818 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1819 asn1_close(&asn1, &offset); /* mark where we are */
1822 /* indefinite length or constructed.... must be a sequence .... */
1823 if (len == 0) /* don't recurse if offset isn't going to change */
1826 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1830 default: /* fprintf(stderr, "Other\n"); */
1831 if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1832 offset += len; /* skip value ... */
1839 static void showGNodes(GNode *p, int n);
1843 myLeaf(GNode *node, gpointer data)
1846 guint ret, cls, con, tag, def, len;
1847 char *clsstr, *constr, *tagstr;
1851 (void) data; /* make a reference */
1852 asn1_open(&asn1, asn1_desc, (int)node->data);
1854 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1856 clsstr = asn1_cls[cls];
1857 constr = asn1_con[con];
1858 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1859 tagstr = asn1_tag[tag];
1861 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1865 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1867 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1871 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1879 if (asn1_verbose) g_message("build GNode tree:");
1880 showGNodes(g_node_first_child(asn1_nodes), 0);
1881 if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1882 g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1883 g_node_max_height (asn1_nodes),
1884 g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1885 g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1887 g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1893 tt_build_tree(void) /* build a GNode tree with all offset's to ASN.1 entities */
1896 g_node_destroy(asn1_nodes);
1897 asn1_nodes = g_node_new(0);
1899 parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1903 /*****************************************************************************************************/
1905 static guint anonCount; /* for naming anonymous types */
1907 typedef struct _TBLModule TBLModule;
1908 typedef struct _TBLTypeDef TBLTypeDef;
1909 typedef struct _TBLTag TBLTag;
1910 typedef struct _TBLType TBLType;
1911 typedef struct _TBLTypeRef TBLTypeRef;
1912 typedef struct _TBLNamedNumber TBLNamedNumber;
1913 typedef struct _TBLRange TBLRange;
1921 TBLTYPE_NamedNumber,
1924 typedef enum _tbl_t tbl_t;
1925 /* text for 'tbl_t' type for debugging */
1926 static const char *data_types[] = {
1936 enum _TBLTypeContent_t {
1938 TBLTYPETYPE_Primitive,
1939 TBLTYPETYPE_Elements,
1942 typedef enum _TBLTypeContent_t TBLTypeContent_t;
1944 struct _TBLNamedNumber {
1956 struct _TBLTypeRef {
1972 TBLTypeContent_t content;
1975 gboolean constraint;
1978 struct _TBLTypeDef {
1993 guint totalNumModules;
1994 guint totalNumTypeDefs;
1995 guint totalNumTypes;
1997 guint totalNumStrings;
1998 guint totalLenStrings;
2001 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2004 get_asn1_int(guint want_tag, guint offset)
2007 guint ret, cls, con, tag, def, len;
2010 /* g_message("%d get_asn1_int", offset); */
2012 asn1_open(&asn1, asn1_desc, offset);
2014 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2015 if (ret == ASN1_ERR_NOERROR) {
2016 /* do not check class, both Unversal and Context are OK */
2017 if (con == ASN1_PRI && tag == want_tag) {
2019 asn1_uint32_value_decode(&asn1, len, &value);
2022 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2024 ret = ASN1_ERR_WRONG_TYPE;
2026 g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2031 static subid_t * /* with prepended length ..... */
2032 get_asn1_oid(guint want_tag, guint offset)
2035 guint ret, cls, con, tag, def, len;
2038 /* g_message("%d get_asn1_oid", offset); */
2040 asn1_open(&asn1, asn1_desc, offset);
2042 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2043 if (ret == ASN1_ERR_NOERROR) {
2044 /* do not check class, both Unversal and Context are OK */
2045 if ((con == ASN1_PRI) && (tag == want_tag)) {
2047 asn1_oid_value_decode(&asn1, len, &oid, &con);
2048 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2049 memmove(&oid[1], oid, con*sizeof(guint));
2053 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2055 ret = ASN1_ERR_WRONG_TYPE;
2057 g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2062 static guchar * /* 0 terminated string */
2063 get_asn1_string(guint want_tag, guint offset)
2066 guint ret, cls, con, tag, def, len;
2069 /* g_message("%d get_asn1_string", offset); */
2071 asn1_open(&asn1, asn1_desc, offset);
2073 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2074 if (ret == ASN1_ERR_NOERROR) {
2075 /* do not check class, both Unversal and Context are OK */
2076 if ((con == ASN1_PRI) && (tag == want_tag)) {
2078 asn1_string_value_decode(&asn1, len, &octets);
2079 octets = g_realloc(octets, len+1); /* need space for sentinel */
2083 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2085 ret = ASN1_ERR_WRONG_TYPE;
2087 g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2093 get_asn1_uint(guint offset)
2096 guint ret, len, value;
2098 /* g_message( "%d get_asn1_uint", offset); */
2100 asn1_open(&asn1, asn1_desc, offset);
2102 ret = asn1_uint32_decode(&asn1, &value, &len);
2104 if (ret != ASN1_ERR_NOERROR) {
2105 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2112 check_tag(guint want_tag, guint offset)
2115 guint ret, cls, con, tag, def, len;
2117 asn1_open(&asn1, asn1_desc, offset);
2119 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2120 if (ret == ASN1_ERR_NOERROR) {
2121 ret = (tag == want_tag) ? TRUE : FALSE;
2122 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2125 g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2132 constructed(guint offset)
2135 guint ret, cls, con, tag, def, len;
2137 /* g_message("%d constructed?", offset); */
2139 asn1_open(&asn1, asn1_desc, offset);
2141 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2142 if (ret == ASN1_ERR_NOERROR) {
2148 /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2155 define_constraint(GNode *p, GNode *q)
2157 TBLRange *range = g_malloc(sizeof(TBLRange));
2158 g_node_append_data(q, range);
2160 range->type = TBLTYPE_Range;
2162 /* g_message("define_constraint %p, %p", p, q); */
2164 p = g_node_first_child(p);
2166 range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2167 p = g_node_next_sibling(p);
2169 range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2174 define_namednumber(GNode *p, GNode *q)
2176 TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2177 g_node_append_data(q, num);
2179 num->type = TBLTYPE_NamedNumber;
2181 /* g_message("define_namednumber %p, %p", p, q); */
2183 p = g_node_first_child(p);
2185 num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2186 p = g_node_next_sibling(p);
2188 num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2192 define_typeref(GNode *p, GNode *q)
2194 TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2195 g_node_append_data(q, ref);
2197 ref->type = TBLTYPE_TypeRef;
2199 /* g_message("define_typeref %p, %p", p, q); */
2201 p = g_node_first_child(p);
2203 ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2204 p = g_node_next_sibling(p);
2206 ref->implicit = get_asn1_int(ASN1_BOL, GPOINTER_TO_UINT(p->data));
2210 define_tag(GNode *p, GNode *q)
2212 TBLTag *type = g_malloc(sizeof(TBLTag));
2213 g_node_append_data(q, type);
2215 type->type = TBLTYPE_Tag;
2217 /* g_message("define_tag %p, %p", p, q); */
2219 p = g_node_first_child(p);
2221 type->tclass = get_asn1_int(ASN1_ENUM, GPOINTER_TO_UINT(p->data));
2222 p = g_node_next_sibling(p);
2224 type->code = get_asn1_int(ASN1_INT, GPOINTER_TO_UINT(p->data));
2229 define_type(GNode *p, GNode *q)
2232 TBLType *type = g_malloc(sizeof(TBLType));
2234 GNode *t = g_node_append_data(q, type);
2236 type->type = TBLTYPE_Type;
2238 /* g_message("define_type %p, %p", p, q); */
2240 type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2241 p = g_node_next_sibling(p);
2243 type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2244 p = g_node_next_sibling(p);
2246 if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
2247 r = g_node_first_child(p);
2250 r = g_node_next_sibling(r);
2252 p = g_node_next_sibling(p);
2255 if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
2256 g_warning("expect tag 3, ERROR");
2258 r = g_node_first_child(p);
2260 type->content = TBLTYPETYPE_None;
2261 if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
2262 if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
2263 if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
2264 switch(type->content) {
2265 case TBLTYPETYPE_Primitive:
2267 case TBLTYPETYPE_Elements:
2268 r = g_node_first_child(r);
2270 define_type(g_node_first_child(r), t);
2271 r = g_node_next_sibling(r);
2274 case TBLTYPETYPE_TypeRef:
2275 define_typeref(r, t);
2277 case TBLTYPETYPE_None:
2278 g_warning("expected a contents choice, error");
2281 p = g_node_next_sibling(p);
2283 type->fieldName = 0;
2284 type->anonymous = FALSE;
2285 if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
2286 type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
2287 p = g_node_next_sibling(p);
2289 type->anonymous = TRUE;
2292 type->constraint = FALSE;
2293 if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
2294 type->constraint = TRUE;
2295 define_constraint(p, t);
2296 p = g_node_next_sibling(p);
2299 if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
2300 r = g_node_first_child(p);
2302 define_namednumber(r, t);
2303 r = g_node_next_sibling(r);
2309 define_typedef(GNode *p, GNode *q)
2311 TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2313 GNode *t = g_node_append_data(q, type_def);
2315 /* g_message("define_typedef %p, %p", p, q); */
2317 type_def->type = TBLTYPE_TypeDef;
2319 p = g_node_first_child(p);
2321 type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2322 p = g_node_next_sibling(p);
2324 type_def->typeName = get_asn1_string(ASN1_PRNSTR, GPOINTER_TO_UINT(p->data));
2325 p = g_node_next_sibling(p);
2327 define_type(g_node_first_child(p), t);
2328 p = g_node_next_sibling(p);
2330 type_def->isPdu = (p != 0); /* true if it exists, value ignored */
2334 define_module(GNode *p, GNode *q)
2336 TBLModule *module = g_malloc(sizeof(TBLModule));
2338 GNode *m = g_node_append_data(q, module);
2340 /* g_message("define_module %p %p", p, q); */
2342 module->type = TBLTYPE_Module;
2344 p = g_node_first_child(p);
2346 module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2347 p = g_node_next_sibling(p);
2350 if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */
2351 module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
2352 p = g_node_next_sibling(p);
2355 module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
2356 p = g_node_next_sibling(p);
2358 p = g_node_first_child(p);
2360 define_typedef(p, m);
2361 p = g_node_next_sibling(p);
2365 typedef struct _SearchDef SearchDef;
2372 is_typedef(GNode *node, gpointer data)
2374 TBLTypeDef *d = (TBLTypeDef *)node->data;
2375 SearchDef *s = (SearchDef *)data;
2377 if (d == 0) return FALSE;
2378 if (d->type != TBLTYPE_TypeDef) return FALSE;
2379 if (strcmp(s->key, d->typeName) == 0) {
2386 typedef struct _TypeRef TypeRef;
2392 GNode *pdu; /* location in PDU descriptor tree */
2393 guint level; /* recursion counter */
2395 GPtrArray *refs; /* pointers to PDUinfo structures teferencing this entry */
2398 typedef struct _NameDefs NameDefs;
2404 #define ALLOC_INCR 4
2405 #define CLASSREF (ASN1_PRV+1)
2408 is_named(GNode *node, gpointer data)
2410 TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2411 NameDefs *n = (NameDefs *)data;
2414 if (num == 0) return FALSE;
2415 if (num->type != TBLTYPE_NamedNumber) return FALSE;
2417 if (num->value >= n->max) { /* need larger array */
2419 n->max = num->value + ALLOC_INCR;
2420 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2421 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2423 if (num->value > n->used) /* track max used value, there may be holes... */
2424 n->used = num->value;
2426 n->info[num->value].name = num->name;
2432 index_typedef(GNode *node, gpointer data)
2434 TBLTypeDef *d = (TBLTypeDef *)node->data;
2435 NameDefs *n = (NameDefs *)data;
2440 if (d == 0) return FALSE;
2441 if (d->type != TBLTYPE_TypeDef) return FALSE;
2443 if (d->typeDefId >= n->max) { /* need larger array */
2445 n->max = d->typeDefId + ALLOC_INCR;
2446 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2447 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2449 if (d->typeDefId > n->used) /* track max used value, there may be holes... */
2450 n->used = d->typeDefId;
2452 t = &(n->info[d->typeDefId]);
2453 t->name = d->typeName;
2455 t->refs = g_ptr_array_new(); /* collect references here */
2456 node = g_node_first_child(node); /* the real type */
2457 tag = (TBLTag *)node->data;
2458 if ((tag->type == TBLTYPE_Type) && (((TBLType *)tag)->typeId == TBL_CHOICE)) {
2459 /* no reasonable default... ! */
2460 t->defclass = 3; /* Private .... */
2461 t->deftag= 9999; /* a random value */
2463 node = g_node_first_child(node); /* the default tag */
2464 tag = (TBLTag *)node->data;
2467 t->defclass = tag->tclass;
2468 t->deftag = tag->code;
2470 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2471 t->defclass = CLASSREF; /* invalid class.. */
2472 t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2475 g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2476 data_types[tag->type]);
2477 t->defclass = 3; /* Private .... */
2478 t->deftag= 9998; /* another random value */
2486 static TypeRef *typeDef_names = 0;
2487 static guint numTypedefs = 0;
2490 free_node_data(GNode *node, gpointer data _U_)
2497 get_values(void) /* collect values from ASN.1 tree */
2498 /* coded according to the tbl.asn1 description of snacc output */
2499 { /* This routine does not leave references to the tvbuff or */
2500 /* to the asn1_nodes, both can be freed by the caller of this.*/
2506 const char *t, *s, *E;
2507 static char missing[] = " **missing** ";
2509 if (asn1_verbose) g_message("interpreting tree");
2510 typeDef_names = 0; /* just forget allocated any data .... */
2513 g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2514 free_node_data, NULL);
2515 g_node_destroy(data_nodes);
2518 data_nodes = g_node_new(0);
2520 p = g_node_first_child(asn1_nodes); /* top of the data tree */
2522 p = g_node_first_child(p);
2523 TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2524 p = g_node_next_sibling(p);
2525 TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2526 p = g_node_next_sibling(p);
2527 TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2528 p = g_node_next_sibling(p);
2529 TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2530 p = g_node_next_sibling(p);
2531 TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2532 p = g_node_next_sibling(p);
2533 TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2534 p = g_node_next_sibling(p);
2536 p = g_node_first_child(p);
2538 define_module(p, data_nodes);
2539 p = g_node_next_sibling(p);
2542 /* g_message("finished with tree"); */
2544 if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2545 sd.key = "TBLTypeId";
2547 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2548 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", sd.here);
2552 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2553 g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2555 if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, nd.info);
2557 for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2560 s = nd.info[i].name;
2561 if (s == 0) s = missing;
2562 if (g_strcmp(t, s) == 0) { /* OK ! */
2566 E = ", X with errors X";
2568 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2570 if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2572 tbl_types_verified = TRUE;
2574 /* build table with typedef names */
2577 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2578 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2579 if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, nd.info);
2581 for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2582 TypeRef *ref = &(nd.info[i]);
2585 t = ref->name = missing;
2586 if (asn1_verbose) g_message(" %3d %s", i, t);
2588 if (asn1_verbose) g_message(" %3d %s, %c%d", i, t,
2589 tag_class[ref->defclass], ref->deftag);
2591 if (ref->pdu) { /* should be 0 */
2592 if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, ref->pdu);
2595 typeDef_names = nd.info;
2597 if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
2602 showGNode(GNode *p, int n)
2605 n *=2; /* 2 spaces per level */
2606 if (p->data) { /* show value ... */
2607 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
2608 switch (((TBLTag *)p->data)->type) {
2609 case TBLTYPE_Module: {
2610 TBLModule *m = (TBLModule *)p->data;
2612 g_message("%*smodule %s%s", n, empty, m->name,
2613 m->isUseful ? ", useful" : empty);
2616 case TBLTYPE_TypeDef: {
2617 TBLTypeDef *t = (TBLTypeDef *)p->data;
2619 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
2620 t->isPdu ? ", isPDU" : empty);
2623 case TBLTYPE_Type: {
2624 TBLType *t = (TBLType *)p->data;
2625 const char *fn, *s = empty;
2628 /* typeId is a value from enum TBLTypeId */
2629 fn = TBLTYPE(t->typeId);
2630 if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
2631 t->optional ? " opt" : empty, s );
2635 TBLTag *t = (TBLTag *)p->data;
2636 const char *s = empty;
2637 if ((t->tclass == ASN1_UNI) && (t->code < 32))
2638 s = asn1_tag[t->code];
2639 if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
2640 tag_class[t->tclass], t->code, s);
2643 case TBLTYPE_NamedNumber: {
2644 TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
2645 if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
2646 nn->value, nn->name);
2649 case TBLTYPE_Range: {
2650 TBLRange *r = (TBLRange *)p->data;
2651 if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
2655 case TBLTYPE_TypeRef: {
2656 TBLTypeRef *r = (TBLTypeRef *)p->data;
2657 const char *s = empty;
2659 s = typeDef_names[r->typeDefId].name;
2660 if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
2661 r->typeDefId, s, r->implicit ? ", implicit" : empty );
2665 TBLTag *x = (TBLTag *)p->data;
2666 if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
2670 } else { /* just show tree */
2672 g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
2673 n, empty, p, p->data, p->next, p->prev, p->parent, p->children);
2678 showGNodes(GNode *p, int n)
2682 showGNodes(p->children, n+1);
2683 showGNodes(p->next, n);
2686 static void showGenv(GNode *p, int n, int m)
2692 if (asn1_verbose) g_message("%*s.....", n*2, empty);
2696 for(i=0; p && (i < 3); p = p->next, i++) {
2698 showGenv(p->children, n+1, m);
2700 if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
2705 debug_dump_TT(void) /* dump contents of TT struct, for debugging */
2708 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
2710 TT.totalNumTypeDefs,
2714 TT.totalLenStrings);
2718 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
2719 const gchar *message, gpointer user_data)
2721 static FILE* logf = 0;
2722 static char eol[] = "\r\n";
2724 (void) log_domain; (void) log_level; (void) user_data; /* make references */
2726 if (logf == NULL && asn1_logfile) {
2727 logf = eth_fopen(asn1_logfile, "w");
2730 fputs(message, logf);
2732 fflush(logf); /* debugging ... */
2737 read_asn1_type_table(const char *filename)
2744 if ((filename == 0) || (strlen(filename) == 0))
2745 return; /* no filename provided */
2747 f = eth_fopen(filename, "rb");
2750 * Ignore "file not found" errors if it's the old default
2751 * ASN.1 file name, as we never shipped such a file.
2752 * Also, on Win32, ignore the earlier default, which
2753 * had a "/" rather than a "\" as the last pathname
2757 if (strcmp(filename, bad_separator_old_default_asn1_filename) != 0)
2759 if ((strcmp(filename, old_default_asn1_filename) != 0) || errno != ENOENT)
2760 report_open_failure(filename, errno, FALSE);
2763 fstat(fileno(f), &stat);
2764 size = (int)stat.st_size;
2766 if (asn1_verbose) g_message("file %s is empty, ignored", filename);
2770 if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
2772 data = g_malloc(size);
2773 if (fread(data, size, 1, f) < 1) {
2774 g_warning("error reading %s, %s", filename, strerror(errno));
2779 /* ***** from the time when logging was just in a console... *****
2780 * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
2781 * " Sleep 5 sec...");
2785 static guint mylogh = 0;
2787 g_message("logging to file %s", asn1_logfile);
2790 mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2791 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
2795 asn1_desc = tvb_new_real_data(data, size, size);
2798 if (asn1_verbose) g_message("read %d items from %s", icount, filename);
2806 g_node_destroy(asn1_nodes); asn1_nodes = 0;
2807 #ifndef _WIN32 /* tvb_free not yet exported to plugins... */
2808 tvb_free(asn1_desc);
2811 g_free(data); data = 0;
2813 showGNodes(data_nodes, 0);
2819 /* XXX - Shoudn't we make sure we're not dereferencing a NULL pointer here? */
2820 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
2821 g_warning("**** unexpected type %s, want %s, at line %d", \
2822 data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
2826 save_reference(PDUinfo *p)
2833 g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
2837 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex);
2841 /* evaluate typeref, pointer to current pdu node and typedef */
2843 tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
2846 PDUinfo *p = (PDUinfo *)pdu->data, *p1;
2850 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
2851 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
2855 CHECKTYPE(tree, TBLTYPE_TypeDef);
2857 if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
2858 p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2860 p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
2861 p->flags |= PDU_TYPEDEF;
2863 tree = g_node_first_child(tree); /* move to its underlying type */
2864 CHECKTYPE(tree, TBLTYPE_Type);
2865 p->type = ((TBLType *)tree->data)->typeId;
2867 q = g_node_first_child(tree); /* the tag of this type entry ... is optional... */
2868 if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
2869 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
2873 /* XXX -- hack -- hack -- hack -- hack -- hack --
2874 * only change tag when class+tag == EOC,
2875 * or class is a reference,
2876 * or new class is not universal.
2878 if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
2879 (((TBLTag *)q->data)->tclass != ASN1_UNI) ) {
2880 p->tclass = ((TBLTag *)q->data)->tclass;
2881 p->tag = ((TBLTag *)q->data)->code;
2883 g_message("%*s*change typeref tag from %c%d to %c%d",
2887 tag_class[p->tclass],
2891 g_message("%*sNOT changing tag from %c%d to %c%d",
2895 tag_class[((TBLTag *)q->data)->tclass],
2896 ((TBLTag *)q->data)->code);
2904 if (p->tclass==CLASSREF)
2905 g_snprintf(ss, 128, ", CLASSREF %d", p->tag);
2906 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
2908 if (p->tclass==CLASSREF) {
2910 int i = p->basetype;
2911 /* CLASSREF....., get it defined using type of the reference */
2913 /* p->basetype may be -1 .... ? XXX */
2916 tr = &typeDef_names[i];
2918 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
2919 p->tag, tr->name, tr->pdu);
2921 tbl_typeref(n+1, pdu, tr->type, fullindex);
2928 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
2929 p->name, p->typename, p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2933 case TBL_ENUMERATED:
2934 /* names do not have a fullname */
2935 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
2936 /* read the enumeration [save min-max somewhere ?] */
2937 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type]; /* XXX change field type... */
2939 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2944 g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2945 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2946 p->name, p->fullname,
2947 tbl_types_wireshark_txt[p->type], p->value_id);
2950 while((q = g_node_next_sibling(q))) {
2951 CHECKTYPE(q, TBLTYPE_NamedNumber);
2952 p = g_malloc0(sizeof(PDUinfo));
2954 p->type = TBL_ENUMERATED;
2955 p->name = (((TBLNamedNumber *)q->data)->name);
2956 p->tag = (((TBLNamedNumber *)q->data)->value);
2957 p->flags = PDU_NAMEDNUM;
2958 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
2959 g_node_append_data(pdu, p);
2962 /* list all enum values in the field structure for matching */
2963 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
2964 q = g_node_first_child(pdu);
2967 p = (PDUinfo *)q->data;
2968 v[nvals].value = p->tag;
2969 v[nvals].strptr = p->name;
2970 /* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
2972 q = g_node_next_sibling(q);
2974 /* last entry is already initialized to { 0, NULL } */
2979 if (p->value_id == -1) { /* not yet registered ..... */
2980 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
2981 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2986 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2987 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2988 p->name, p->fullname,
2989 tbl_types_wireshark_txt[p->type], p->value_id);
2991 tbl_type(n, pdu, q, fullindex);
2995 if (p->value_id == -1) { /* not yet registered ..... */
2996 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
2997 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3002 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3003 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3004 p->name, p->fullname,
3005 tbl_types_wireshark_txt[p->type], p->value_id);
3007 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
3012 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
3020 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
3021 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3025 /* showGenv(list, n, n+1); */
3028 pdu1 = pdu; /* save start location for append */
3029 while (list) { /* handle all entries */
3031 g_message("%*s+handle a %s, list=%p", n*2, empty,
3032 data_types[((TBLTag *)list->data)->type], list);
3034 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
3035 list = g_node_next_sibling(list);
3036 if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
3041 /******* change to positive comparation, but leave comment for reference
3042 * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3043 * CHECKTYPE(list, TBLTYPE_Type);
3046 if (((TBLTag *)list->data)->type == TBLTYPE_Type) {
3047 CHECKTYPE(list, TBLTYPE_Type);
3049 p = g_malloc0(sizeof(PDUinfo));
3050 pdu = g_node_append_data(pdu1, p);
3052 p->type = ((TBLType *)list->data)->typeId;
3053 p->typename = tbl_types_asn1[p->type]; /* the default type */
3056 p->basetype = ((PDUinfo *)pdu1->data)->typenum;
3057 p->flags = PDUinfo_initflags;
3058 p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
3059 p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
3061 if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
3062 /* assign an anonymous name [XXX refer to parent typename...] */
3063 ((TBLType *)list->data)->fieldName =
3064 g_strdup_printf("anon%d", anonCount++);
3066 p->name = ((TBLType *)list->data)->fieldName;
3069 ni += snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
3070 p->fullname = g_strdup(fieldname);
3072 /* initialize field info */
3075 p->value_hf.p_id = &(p->value_id);
3076 p->value_hf.hfinfo.name = p->fullname;
3077 p->value_hf.hfinfo.abbrev = p->fullname;
3078 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3079 p->value_hf.hfinfo.display = BASE_DEC;
3080 p->value_hf.hfinfo.blurb = p->fullname;
3081 /* all the other fields are already 0 ! */
3083 if (p->type < TBL__SIMPLE) {
3084 /* only register fields with a value here, postpone others */
3085 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3090 g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3091 p->mytype, p->typenum, p->basetype, p->flags,
3092 p->typename, p->name, p->fullname,
3093 tbl_types_wireshark_txt[p->type], p->value_id);
3096 q = g_node_first_child(list);
3098 p = (PDUinfo *)pdu->data;
3103 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
3108 case TBL_OCTETSTRING:
3112 CHECKTYPE(q, TBLTYPE_Tag);
3113 p->tclass = ((TBLTag *)q->data)->tclass;
3114 p->tag = ((TBLTag *)q->data)->code;
3118 case TBL_ENUMERATED:
3119 CHECKTYPE(q, TBLTYPE_Tag);
3120 p->tclass = ((TBLTag *)q->data)->tclass;
3121 p->tag = ((TBLTag *)q->data)->code;
3122 if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
3123 /* read the enumeration [save min-max somewhere ?] */
3126 while((q = g_node_next_sibling(q))) {
3127 CHECKTYPE(q, TBLTYPE_NamedNumber);
3128 p = g_malloc0(sizeof(PDUinfo));
3130 p->type = TBL_ENUMERATED;
3131 p->name = (((TBLNamedNumber *)q->data)->name);
3132 p->tag = (((TBLNamedNumber *)q->data)->value);
3133 p->flags = PDU_NAMEDNUM;
3134 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3135 g_node_append_data(pdu, p);
3138 /* list all enum values in the field structure for matching */
3139 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3140 q = g_node_first_child(pdu);
3143 p = (PDUinfo *)q->data;
3144 v[nvals].value = p->tag;
3145 v[nvals].strptr = p->name;
3146 /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3148 q = g_node_next_sibling(q);
3150 /* last entry is already initialized to { 0, NULL } */
3156 case TBL_SEQUENCEOF:
3159 CHECKTYPE(q, TBLTYPE_Tag);
3160 q = g_node_first_child(list);
3161 tbl_type(n+1, pdu, q, ni);
3164 case TBL_TYPEREF: { /* may have a tag ... */
3170 if ( ((TBLTag *)q->data)->type == TBLTYPE_Tag) {
3171 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3172 p->tclass = ((TBLTag *)q->data)->tclass;
3173 p->tag = ((TBLTag *)q->data)->code;
3175 g_message("%*s*insert type tag %c%d", n*2, empty,
3176 tag_class[p->tclass], p->tag);
3178 q = g_node_next_sibling(q);
3179 } else { /* use default tag for this type */
3180 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3181 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != ASN1_UNI)) ||
3182 ((p->tclass | p->tag) == 0 )) {
3183 /* not implicit, use this tag */
3184 p->tclass = tr->defclass;
3185 p->tag = tr->deftag;
3186 if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3187 tag_class[p->tclass], p->tag);
3190 CHECKTYPE(q, TBLTYPE_TypeRef);
3191 i = ((TBLTypeRef *)q->data)->typeDefId;
3193 tr = &typeDef_names[i];
3195 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, tr->pdu);
3196 p->typename = tr->name;
3198 if (tr->defclass == CLASSREF) {
3200 tr->pdu = pdu; /* remember this reference */
3202 tr = &typeDef_names[i];
3204 g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3205 i, tr->name, tr->pdu);
3207 /* evaluate reference if not done before or when below recursion limit */
3208 if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3211 tr->pdu = pdu; /* save for references we leave */
3213 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3215 g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3217 ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3220 tbl_typeref(n+1, pdu, tr->type, ni);
3224 g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3225 p->name, tr->name, tr->pdu);
3226 p->flags |= PDU_REFERENCE;
3227 p->reference = tr->pdu;
3232 g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3237 g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3238 n*2, empty, p->name, p->typename, p, TBLTYPE(p->type),
3239 tag_class[p->tclass], p->tag);
3241 if (p->value_id == -1) { /* not registered before, do it now */
3242 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3247 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3248 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3249 p->name, p->fullname,
3250 tbl_types_wireshark_txt[p->type], p->value_id);
3252 list = g_node_next_sibling(list);
3257 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
3260 const char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3263 tt = TBLTYPE(info->type);
3265 tn = info->typename;
3266 fn = info->fullname;
3267 if (info->flags & PDU_NAMEDNUM)
3268 txt += sprintf(txt, "name: %2d %s", info->tag, nn);
3270 if (info->flags & PDU_TYPEDEF)
3271 txt += sprintf(txt, "def %d: ", info->typenum);
3273 txt += sprintf(txt, " ");
3274 ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3275 txt += sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3276 tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3277 txt += sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
3278 oo = (info->flags & PDU_OPTIONAL) ? ", optional" : empty;
3279 ii = (info->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3280 nn = (info->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3281 an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3282 txt += sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
3283 if (info->flags & PDU_REFERENCE) {
3284 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3285 tt = TBLTYPE(rinfo->type);
3287 tn = rinfo->typename;
3288 fn = rinfo->fullname;
3289 txt += sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3290 if (rinfo->flags & PDU_TYPEDEF)
3291 txt += sprintf(txt, " T%d", rinfo->typenum);
3292 txt += sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3293 oo = (rinfo->flags & PDU_OPTIONAL) ? ", optional" : empty;
3294 ii = (rinfo->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3295 nn = (rinfo->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3296 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3297 tt = (rinfo->flags & PDU_TYPEDEF) ? ", typedef" : empty;
3298 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3299 tr = (rinfo->flags & PDU_TYPETREE) ? ", typetree" : empty;
3300 txt += sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3304 strcpy(txt, "no info available");
3312 showPDUtree(GNode *p, int n)
3318 info = (PDUinfo *)p->data;
3320 PDUtext(text, info);
3322 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3324 showPDUtree(g_node_first_child(p), n+1);
3326 p = g_node_next_sibling(p);
3333 build_pdu_tree(const char *pduname)
3336 guint pdudef, i, tcount;
3340 if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3343 if (asn1_verbose) g_message("no data nodes");
3348 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3350 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3351 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, sd.here, pdudef);
3353 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3357 /* If there's an existing PDU tree, free it */
3359 g_node_traverse(PDUtree, G_POST_ORDER, G_TRAVERSE_ALL, -1,
3360 free_node_data, NULL);
3361 g_node_destroy(PDUtree);
3364 /* initialize the PDU tree, hand craft the root entry */
3366 info = g_malloc0(sizeof(PDUinfo));
3367 info->name = pduname;
3368 info->typename = pduname;
3369 info->type = TBL_SEQUENCEOF;
3370 info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3371 info->flags = PDUinfo_initflags = 0;
3372 info->value_id = -1;
3374 info->basetype = -1;
3375 info->mytype = pdudef;
3377 info->value_hf.p_id = &(info->value_id);
3378 info->value_hf.hfinfo.name = info->fullname;
3379 info->value_hf.hfinfo.abbrev = info->fullname;
3380 info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3381 info->value_hf.hfinfo.display = BASE_DEC;
3382 info->value_hf.hfinfo.blurb = info->fullname;
3384 anonCount = 0; /* anonymous types counter */
3386 PDUtree = g_node_new(info);
3387 pabbrev_pdu_len = sprintf(fieldname, "%s.%s.", pabbrev, pduname);
3388 sav_len = pabbrev_pdu_len;
3390 /* Now build the tree for this top level PDU */
3392 g_message("******** Define main type %d, %s", pdudef, pduname);
3393 tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1); /* strip initial . for new names */
3396 g_message("%d anonymous types", anonCount);
3398 /* Now make all types used available for matching */
3400 g_message("Define the types that are actually referenced through the top level PDU");
3401 for (i=0, tcount=0; i<numTypedefs; i++) {
3402 TypeRef *tr = &(typeDef_names[i]);
3404 if (tr->pdu) { /* ignore if not used in main pdu */
3407 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3409 g_message("******** Define type %d, %s", i, tr->name);
3411 /* .... do definition ..... */
3412 info = g_malloc0(sizeof(PDUinfo));
3413 info->name = tr->name;
3414 info->typename = tr->name;
3415 info->tclass = tr->defclass;
3416 info->tag = tr->deftag;
3417 info->type = TBL_TYPEREF;
3418 info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3419 info->flags = PDUinfo_initflags = PDU_TYPETREE;
3420 info->value_id = -1;
3422 info->basetype = -1;
3425 info->value_hf.p_id = &(info->value_id);
3426 info->value_hf.hfinfo.name = info->fullname;
3427 info->value_hf.hfinfo.abbrev = info->fullname;
3428 info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3429 info->value_hf.hfinfo.display = BASE_DEC;
3430 info->value_hf.hfinfo.blurb = info->fullname;
3432 tr->typetree = g_node_new(info);
3433 pabbrev_pdu_len = sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
3434 tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3438 g_message("%d types used", tcount);
3440 pabbrev_pdu_len = sav_len;
3442 /* and show the result */
3444 g_message("Type index:");
3445 for (i=0; i<numTypedefs; i++) {
3446 TypeRef *tr = &(typeDef_names[i]);
3452 if (tr->pdu == 0) /* skip if not used */
3456 g_message(" %3d %s, %c%d, refs: %d",
3457 i, tr->name, tag_class[tr->defclass], tr->deftag,
3458 g_ptr_array_len(tr->refs));
3460 /* get defining node for this type */
3463 p = (PDUinfo *)(tr->typetree->data);
3464 defid = p->value_id;
3466 g_message(" -- defining id=%d", defid);
3468 for(j=0; j < g_ptr_array_len(tr->refs); j++) { /* show refs, and set type_id */
3469 p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3470 if (p->mytype == (gint)i)
3471 p->type_id = defid; /* normal reference */
3473 if ((p->flags & PDU_TYPETREE) == 0) {
3474 /* we have a primitive value, find its real type */
3475 for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3476 /* look at all refs */
3477 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3478 if ((q->flags & PDU_TYPETREE) == 0)
3479 continue; /* only type trees are interresting */
3480 if (q->type != p->type)
3481 continue; /* must be same types */
3482 if (strcmp(q->name, p->name) == 0) {
3483 /* OK, take the first we find, not entirely
3484 * correct, it may be from a different
3485 * base-base type...... XXX */
3486 p->type_id = q->value_id;
3495 g_message(" %s", text);
3501 g_message("The resulting PDU tree:");
3502 showPDUtree(PDUtree, 0);
3508 #ifdef DISSECTOR_WITH_GUI
3509 /* This cannot work in tshark.... don't include for now */
3510 #if GTK_MAJOR_VERSION >= 2
3511 #define SHOWPDU /* this needs GTK2 */
3513 #endif /* DISSECTOR_WITH_GUI */
3516 static GtkWidget *window = NULL;
3518 /* the columns in the tree view */
3521 TITLE_COLUMN, /* text in this row */
3522 DEF_COLUMN, /* definition in this row, if any */
3523 REF_COLUMN, /* referennce from this column, if any */
3524 VALUE_COLUMN, /* indicate this is a value */
3525 NAME_COLUMN, /* name of this row */
3529 static FILE *namelist = 0;
3532 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3535 PDUinfo *info, *rinfo;
3542 info = (PDUinfo *)p->data;
3544 gtk_tree_store_append (store, &iter2, iter); /* Acquire iterator */
3546 PDUtext(text, info);
3549 if (info->flags & PDU_TYPEDEF)
3550 def = info->typenum;
3552 if (info->flags & PDU_REFERENCE) {
3553 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3554 ref = rinfo->typenum;
3556 pb = GTK_STOCK_CANCEL;
3557 if (G_NODE_IS_LEAF(p)) {
3558 if (info->flags & PDU_NAMEDNUM)
3559 pb = GTK_STOCK_BOLD;
3563 fprintf(namelist, "%16s %s\n",
3564 &(TBLTYPE(info->type)[4]), info->fullname);
3567 switch (info->type) {
3568 case TBL_ENUMERATED:
3572 fprintf(namelist, "%16s %s\n",
3573 &(TBLTYPE(info->type)[4]), info->fullname);
3580 gtk_tree_store_set (store, &iter2,
3585 NAME_COLUMN, info->fullname,
3588 build_tree_view(store, g_node_first_child(p), &iter2);
3590 p = g_node_next_sibling(p);
3602 #define PATHSTACKMAX 10
3603 static GtkTreePath *pathstack[PATHSTACKMAX];
3604 static gint pathstackp = 0;
3606 static void add_path(GtkTreePath *p)
3608 if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
3609 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
3610 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
3613 pathstack[pathstackp++] = p;
3616 static GtkTreePath *pop_path(void)
3619 return pathstack[--pathstackp];
3624 find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
3628 struct DefFind *df = (struct DefFind *)data;
3630 gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
3632 if (def == df->def) {
3633 df->path = gtk_tree_path_copy (path);
3641 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
3644 GtkTreePath *path, *path2;
3645 gchar *text, *oldpath, *newpath;
3651 path = gtk_tree_path_copy (spath);
3653 gtk_tree_model_get_iter (model, &iter, path);
3654 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
3656 oldpath = gtk_tree_path_to_string(path);
3657 path2 = gtk_tree_path_copy (path);
3659 add_path(gtk_tree_path_copy(path));
3661 if (ref != -1) { /* this is a reference, find matching definition */
3664 gtk_tree_model_foreach (model, find_definition, &df);
3666 gtk_tree_path_free(path);
3669 } else { /* just move to the next entry, if it exists */
3670 gtk_tree_path_next(path2);
3672 if (gtk_tree_model_get_iter (model, &iter, path2)) {
3673 gtk_tree_path_free(path);
3674 path = path2; /* OK */
3676 if (gtk_tree_path_get_depth (path) > 1)
3677 gtk_tree_path_up (path);
3682 gtk_tree_path_free (path2);
3684 gtk_tree_view_expand_to_path (treeview, path);
3685 gtk_tree_view_expand_row (treeview, path, FALSE);
3687 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3689 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3691 newpath = gtk_tree_path_to_string(path);
3694 g_message("my_signal_handler: treeview=%p, moveing from %s to %s",
3695 treeview, oldpath, newpath);
3701 /* gtk_tree_path_free(df.path); */
3706 menuitem_cb (gpointer callback_data,
3707 guint callback_action,
3711 GtkTreeModel *model;
3712 GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
3713 GtkTreeSelection *selection;
3718 gchar *oldpath, *newpath;
3719 GtkTreeViewColumn *focus_column;
3721 selection = gtk_tree_view_get_selection(treeview);
3723 model = gtk_tree_view_get_model(treeview);
3724 gtk_tree_view_get_cursor (treeview, &path, &focus_column);
3726 if (gtk_tree_model_get_iter (model, &iter, path)) {
3728 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
3729 NAME_COLUMN, &name, -1);
3730 oldpath = gtk_tree_path_to_string(path);
3733 switch (callback_action) {
3734 case 0: /* Select */
3735 gtk_tree_selection_select_path (selection, path);
3740 gtk_tree_view_expand_to_path (treeview, path);
3741 gtk_tree_view_expand_row (treeview, path, FALSE);
3743 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3745 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3747 newpath = gtk_tree_path_to_string(path);
3749 gtk_tree_path_free(path);
3751 newpath = g_strdup("** no path **");
3753 g_message("menueitem_cb: treeview=%p, moveing from %s to %s",
3754 treeview, oldpath, newpath);
3758 /* get all non anonymous names to the root */
3761 dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
3762 GTK_DIALOG_DESTROY_WITH_PARENT,
3765 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
3766 gtk_item_factory_path_from_widget (widget),
3767 callback_action, text, oldpath, newpath, name);
3769 /* Close dialog on user response */
3770 g_signal_connect (dialog,
3772 G_CALLBACK (gtk_widget_destroy),
3775 gtk_widget_show (dialog);
3780 if (newpath != empty)
3784 g_message("menuitem_cb: no iterator...");
3787 static GtkItemFactoryEntry menu_items[] = {
3788 { "/Select", NULL, menuitem_cb, 0, NULL, 0 },
3789 { "/Back", "<control>B", menuitem_cb, 1, NULL, 0 },
3790 { "/Find", "<control>F", menuitem_cb, 2, NULL, 0 },
3791 { "/Save", "<control>S", menuitem_cb, 3, NULL, 0 },
3794 static gint button_press_callback( GtkWidget *widget,
3795 GdkEventButton *event,
3798 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
3800 /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
3801 * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
3804 if (event->button == 3) {
3805 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
3812 return FALSE; /* continue handling this event */
3817 create_message_window(void)
3819 GtkCellRenderer *renderer;
3820 GtkTreeStore *model;
3823 GtkWidget *treeview;
3825 GtkItemFactory *item_factory;
3826 GtkAccelGroup *accel_group;
3827 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3831 /* create window, etc */
3832 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3833 gtk_window_set_title (GTK_WINDOW (window), current_pduname);
3834 g_signal_connect (window, "destroy",
3835 G_CALLBACK (gtk_widget_destroyed), &window);
3837 vbox = gtk_vbox_new (FALSE, 8);
3838 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3839 gtk_container_add (GTK_CONTAINER (window), vbox);
3841 text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
3843 gtk_box_pack_start (GTK_BOX (vbox),
3844 gtk_label_new (text),
3848 sw = gtk_scrolled_window_new (NULL, NULL);
3849 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
3850 GTK_SHADOW_ETCHED_IN);
3851 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
3852 GTK_POLICY_AUTOMATIC,
3853 GTK_POLICY_AUTOMATIC);
3854 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3856 model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3857 G_TYPE_STRING, G_TYPE_STRING);
3859 namelist = eth_fopen("namelist.txt", "w");
3860 build_tree_view(model, PDUtree, NULL);
3864 /* create tree view */
3865 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
3866 g_object_unref (model);
3867 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
3868 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
3869 GTK_SELECTION_MULTIPLE);
3871 renderer = gtk_cell_renderer_text_new ();
3873 #if 0 /* testing pango attributes */
3876 PangoAttrList* attr;
3878 attr = pango_attr_list_new();
3879 bg = pango_attr_background_new(50000,55000,50000);
3880 bg->start_index = 0;
3881 bg->end_index = 10000;
3882 pango_attr_list_insert(attr, bg);
3884 g_object_set(renderer, "attributes", attr, NULL);
3886 #endif /* testing pango attributes */
3888 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3889 TITLE_COLUMN, "asn1 entities", renderer,
3890 "text", TITLE_COLUMN, NULL );
3892 /* renderer = gtk_cell_renderer_text_new ();
3893 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3894 * DEF_COLUMN, "type definition", renderer,
3895 * "text", DEF_COLUMN, NULL );
3897 * renderer = gtk_cell_renderer_text_new ();
3898 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3899 * REF_COLUMN, "reference", renderer,
3900 * "text", REF_COLUMN, NULL );
3902 renderer = gtk_cell_renderer_pixbuf_new ();
3903 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3904 VALUE_COLUMN, "value", renderer,
3905 "stock_id", VALUE_COLUMN, NULL );
3907 renderer = gtk_cell_renderer_text_new ();
3908 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3909 NAME_COLUMN, "fieldname", renderer,
3910 "text", NAME_COLUMN, NULL );
3912 gtk_container_add (GTK_CONTAINER (sw), treeview);
3914 /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
3918 accel_group = gtk_accel_group_new ();
3920 /* This function initializes the item factory.
3921 * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
3922 * or GTK_TYPE_OPTION_MENU.
3923 * Param 2: The path of the menu.
3924 * Param 3: A pointer to a gtk_accel_group. The item factory sets up
3925 * the accelerator table while generating menus.
3928 item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
3930 /* This function generates the menu items. Pass the item factory,
3931 the number of items in the array, the array itself, and any
3932 callback data for the the menu items. */
3933 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
3935 /* Attach the new accelerator group to the window. */
3936 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
3939 /* expand all rows after the treeview widget has been realized */
3940 g_signal_connect (treeview, "realize",
3941 G_CALLBACK (gtk_tree_view_expand_all), NULL);
3942 g_signal_connect (treeview, "row-activated",
3943 G_CALLBACK (my_signal_handler), (gpointer)model);
3945 g_signal_connect (treeview, "button_press_event",
3946 G_CALLBACK (button_press_callback), item_factory);
3948 /* g_signal_connect_swapped (treeview, "event",
3949 * G_CALLBACK (button_press_handler),
3952 gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
3955 if (!GTK_WIDGET_VISIBLE (window))
3956 gtk_widget_show_all (window);
3959 gtk_widget_destroy (window);
3963 #endif /* SHOWPDU */
3965 /************************************************************************************************
3966 * routines to find names to go with the decoded data stream *
3967 ************************************************************************************************/
3968 #define PDUSTATE_STACK_SIZE 1024
3969 typedef struct _statestack statestack;
3970 static struct _statestack {
3975 } PDUstate[PDUSTATE_STACK_SIZE];
3976 static gint PDUstatec = 0;
3978 /* XXX - Shouldn't we do bounds checking here? */
3979 #define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
3980 #define POPSTATE PDUstate[--PDUstatec]
3983 getname(GNode *node) {
3984 if (node == NULL || node->data == NULL)
3985 THROW(ReportedBoundsError);
3987 return ((PDUinfo *)node->data)->name;
3991 gettype(GNode *node) {
3992 if (node == NULL || node->data == NULL)
3993 THROW(ReportedBoundsError);
3995 return ((PDUinfo *)node->data)->type & TBL_TYPEmask;
3999 getinfo(GNode *node) {
4001 THROW(ReportedBoundsError);
4006 #define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
4007 #define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
4008 #define MATCH ((class == info->tclass) && (tag == info->tag))
4009 #define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
4010 #define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
4011 #define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
4012 #define ISCHOICE (info && (info->flags & PDU_CHOICE))
4013 #define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
4016 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
4017 pos.node=NULL;PUSHNODE(pos);return ret;}}
4021 showstack(statestack *pos, char *txt, int n)
4024 const char *name, *type, *stype;
4025 const char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
4031 if ( ! asn1_verbose)
4037 g_message("==underflow");
4040 rep = chs = done = ref = pop = chr = rch = sch = con = empty;
4044 name = ((PDUinfo *)g->data)->name;
4045 type = TBLTYPE(((PDUinfo *)g->data)->type);
4047 name = "node<null>";
4051 stype = TBLTYPE(typef);
4052 if (typef & TBL_REPEAT) rep = "[repeat]";
4053 if (typef & TBL_CHOICE_made) chs = "[choice]";
4054 if (typef & TBL_SEQUENCE_done) done = "[done]";
4055 if (typef & TBL_REFERENCE) ref = "[ref]";
4056 if (typef & TBL_REFERENCE_pop) pop = "[ref-pop]";
4057 if (typef & TBL_CHOICE_repeat) chr = "[chs-rep]";
4058 if (typef & TBL_REPEAT_choice) rch = "[rep-chs]";
4059 if (typef & TBL_SEQUENCE_choice)sch = "[seq-chs]";
4060 if (typef & TBL_CONSTRUCTED) con = "[constr]";
4062 i = sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
4063 pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4064 pos->name, pos->offset);
4066 for(j=1, n--; n>0; j++, n--) {
4067 p = &PDUstate[PDUstatec-j];
4069 stype = TBLTYPE(typef);
4070 rep = (typef & TBL_REPEAT) ? "[repeat]" : empty;
4071 chs = (typef & TBL_CHOICE_made) ? "[choice]" : empty;
4072 done = (typef & TBL_SEQUENCE_done) ? "[done]" : empty;
4073 ref = (typef & TBL_REFERENCE) ? "[ref]" : empty;
4074 pop = (typef & TBL_REFERENCE_pop) ? "[ref-pop]" : empty;
4075 chr = (typef & TBL_CHOICE_repeat) ? "[chs-rep]" : empty;
4076 rch = (typef & TBL_REPEAT_choice) ? "[rep-chs]" : empty;
4077 sch = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
4078 con = (typef & TBL_CONSTRUCTED) ? "[constr]" : empty;
4080 i += sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
4081 p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4082 p->name, p->offset);
4088 showrefNode(GNode *node, int n)
4090 const char *name = empty, *type = empty, *tname = empty;
4091 int cls = 0, tag = 0;
4096 g_message("%*sstop, nesting too deep", 2*n, empty);
4100 info = (PDUinfo *)(node->data);
4101 type = TBLTYPE(info->type);
4103 tname = info->typename;
4104 ref = info->reference;
4108 g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4109 2*n, empty, tname, type, name, node, node->data,
4110 ref, tag_class[cls], tag);
4113 showrefNode(ref, n+1);
4117 showNode(GNode *node, int n, int m)
4119 const char *name = empty, *type = empty;
4126 type = TBLTYPE(((PDUinfo *)(node->data))->type);
4127 name = ((PDUinfo *)(node->data))->name;
4128 ref = ((PDUinfo *)(node->data))->reference;
4130 g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4131 2*n, empty, type, name, node, node->data, node->next, node->prev,
4132 node->parent, node->children);
4135 g_message("%*sstop, nesting too deep", 2*n, empty);
4139 if (ref) showrefNode(ref, n+2);
4141 if (node->children) showNode(node->children, n+1, m);
4142 if (node->next) showNode(node->next, n, m);
4146 PDUreset(int count, int count2)
4150 if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
4152 PDUstatec = 0; /* stackpointer */
4153 PDUerrcount = 0; /* error counter per asn.1 message */
4155 pos.node = NULL; /* sentinel */
4156 pos.name = "sentinel";
4157 pos.type = TBL_SEQUENCEOF;
4162 pos.node = PDUtree; /* root of the tree */
4163 pos.name = getname(pos.node);
4164 pos.type = gettype(pos.node) | TBL_REPEAT;
4170 static GNode * /* find GNode for a choice element, 0 if none */
4171 makechoice(GNode *p, guint class, guint tag)
4176 p = g_node_first_child(p); /* the list of choices */
4177 info = 0; /* avoid gcc warning */
4180 info = ((PDUinfo *)p->data);
4182 if (info->type == TBL_CHOICE) {
4184 g_message(" using sub choice (%s)%s", info->typename, info->name);
4186 q = makechoice(p, class, tag);
4187 if (q) { /* found it */
4189 info = ((PDUinfo *)p->data);
4191 } /* continue with this level */
4195 g_message(" have %c%d, found %c%d, %s", tag_class[class], tag,
4196 tag_class[info->tclass], info->tag, info->name);
4198 if ((class == info->tclass) && (tag == info->tag))
4199 break; /* found it */
4202 p = g_node_next_sibling(p);
4205 if (p) g_message(" OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
4207 else g_message(" ...no matching choice...");
4212 /* offset is for debugging only, a reference to output on screen */
4214 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
4216 statestack pos, pos2, save_pos;
4218 const char *ret, *tmp;
4219 int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4220 static char namestr[64]; /* enough ? */
4221 static char posstr[40];
4222 static char noname[] = "*noname*";
4223 static PDUprops constructed_save; /* for unexpectedly constructed enteties */
4225 if (PDUstatec > 0) /* don't read from below the stack */
4227 /* pos refers to the last asn1 node handled */
4229 /* a very simple, too simple??, way to handle constructed entities */
4230 if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4231 /* unexpectedly constructed, return same info as last time */
4232 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4233 showstack(&pos, posstr, 3);
4234 pos.offset = offset;
4235 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4236 PUSHNODE(pos); /* push extra, to match with a EOI operation */
4237 PUSHNODE(pos); /* restore the stack */
4238 *out = constructed_save;
4240 g_message(" return for constructed %s (%s)%s",
4241 TBLTYPE(out->type), out->typename, out->name);
4245 save_pos = pos; /* may need it again */
4249 out->typename = "*error*";
4256 if (PDUstatec <= 0) {
4257 if (PDUstatec > -10) {
4259 g_message(">>off=%d stack underflow, return", offset);
4261 if (PDUstatec == -10) {
4263 g_message(">>off=%d stack underflow, return, no more messages", offset);
4265 out->name = "*underflow*";
4266 out->flags |= OUT_FLAG_noname;
4270 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4272 showstack(&pos, posstr, 3);
4276 if (class == ASN1_EOI) { /* end of this input sequence */
4278 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4279 if (asn1_verbose) g_message(" EOI: reference pop");
4282 switch(pos.type & TBL_TYPEmask) {
4284 if (asn1_verbose) g_message(" EOI: pop typeref");
4285 pos = POPSTATE; /* remove typeref */
4287 case TBL_CHOICE_done:
4288 if (asn1_verbose) g_message(" EOI: mark choice");
4290 pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4298 pos = POPSTATE; /* this is pushed back on the stack later */
4299 if (pos.node == NULL) {
4300 if (asn1_verbose) g_message(" EOI, pos.node == NULL");
4301 out->name = "*no-name-EOI*";
4302 out->flags |= OUT_FLAG_noname;
4307 info = getinfo(pos.node);
4309 tmp = TBLTYPE(info->type);
4310 if (offset != pos.offset) {
4312 g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4313 tmp, ret, offset, pos.offset);
4314 while ((offset < pos.offset) && (PDUstatec > 0)) {
4317 g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
4318 offset, pos.offset);
4320 if (offset != pos.offset)
4321 PDUerrcount++; /* only count if still unequal */
4323 if (asn1_verbose) g_message(" EOI %s:%s OK, offset=%d", tmp, ret, offset);
4326 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4327 * indicated by the synthetic EOI call. */
4328 if ((class == ASN1_UNI) && (tag == ASN1_EOC)) { /* explicit EOC never has a name */
4329 PUSHNODE(pos); /* restore stack */
4330 ret = "explicit-EOC";
4331 if (asn1_verbose) g_message(" return '%s', ignore", ret);
4333 out->typename = "ASN1";
4337 /* find appropriate node for this tag */
4339 if (pos.node == NULL) {
4340 if (asn1_verbose) g_message(" pos.node == NULL");
4341 out->name = "*no-name*";
4342 out->flags |= OUT_FLAG_noname;
4347 /* showNode(pos.node, 3, 4); */
4349 switch (pos.type & TBL_TYPEmask) {
4350 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4354 if (pos.type & TBL_CHOICE_made) {
4355 if (asn1_verbose) g_message(" finish choice");
4361 info = getinfo(pos.node);
4363 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4364 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4366 if (asn1_verbose) g_message(" repeating choice"); /* ignore repeat */
4369 if (asn1_verbose) g_message(" seqof: repeat start");
4370 /* decide how to continue, CHILD for next instance of sequence
4371 * or NEXT for end of repeated sequence.
4372 * use the tag to make a descision */
4373 if (asn1_verbose) g_message(" seqof: first got %c%d, found %c%d",
4374 tag_class[class], tag,
4375 tag_class[info->tclass], info->tag);
4377 /* This is the start of repeating */
4379 ret = getname(pos.node);
4380 if (asn1_verbose) g_message(" return for repeat '%s'", ret);
4381 out->type = (pos.type & TBL_TYPEmask);
4382 out->typename = info->typename;
4384 out->value_id = info->value_id;
4385 out->type_id = info->type_id;
4387 if (asn1_verbose) g_message(" anonymous: dontshow");
4389 out->flags |= OUT_FLAG_dontshow;
4395 /* find out where to go .... */
4397 CHILD; /* assume sequence is repeated */
4399 info = getinfo(pos.node); /* needed for MATCH to look ahead */
4401 g_message(" seqof: child: got %c%d, found %c%d",
4402 tag_class[class], tag,
4403 tag_class[info->tclass], info->tag);
4405 if (pos2.type & TBL_CHOICE_repeat) {
4408 g_message(" repeating a choice, %s",
4410 pos.type = TBL_CHOICE_immediate;
4412 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4413 donext = 1; /* move on */
4415 g_message(" seqof: no repeat, force next");
4417 /* following code will take the child again */
4423 } else if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4424 if (asn1_verbose) g_message(" reference pop, donext");
4427 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4428 if (pos.type & TBL_SEQUENCE_choice) {
4429 pos = POPSTATE; /* expect to find a repeat here */
4432 if (asn1_verbose) g_message(" sequence done, donext");
4436 if (pos.type & TBL_REFERENCE) {
4437 if (asn1_verbose) g_message(" reference change ref -> pop");
4438 pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4441 pos.offset = offset;
4443 ret = pos.name; /* for the debug messages */
4446 if (asn1_verbose) g_message(" donext");
4449 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4450 case TBL_SETOF: /* ?? */
4451 case TBL_SEQUENCEOF:
4452 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4453 pos.type |= TBL_REPEAT;
4457 /* remember this is the start of a repeat cycle */
4458 typeflags |= TBL_REPEAT;
4460 g_message(" seqof: set repeat mark [push,child]");
4463 g_message(" seqof: end of reapeat loop [next]");
4467 case TBL_SET: /* ?? */
4469 pos.type |= TBL_SEQUENCE_done;
4473 if (asn1_verbose) g_message(" seq [push,child]");
4476 /* no more choice */
4477 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4480 pos.type = 0; /* clear all type flags */
4482 g_message(" choice [push], %c%d, %s",
4483 tag_class[info->tclass], info->tag, getname(pos.node));
4484 pos.node = makechoice(pos.node, class, tag);
4485 if (pos.node == NULL) {
4487 out->flags |= OUT_FLAG_noname;
4490 info = getinfo(pos.node);
4492 ret = getname(pos.node);
4494 g_message(" '%s' %c%d will be used",
4495 ret, tag_class[info->tclass], info->tag);
4497 case TBL_CHOICE_done:
4503 if (asn1_verbose) g_message(" typeref [pop,next]");
4505 case TBL_ENUMERATED:
4507 /* skip named numbers now, call to PDUenum() will retrieve a name */
4510 case TBL_CHOICE_immediate:
4511 if (asn1_verbose) g_message(" immediate choice [no next]");
4520 if (pos.node == NULL) {
4521 ret = "*no-name-2*";
4522 if (asn1_verbose) g_message(" return '%s'", ret);
4524 out->flags |= OUT_FLAG_noname;
4528 ret = pos.name = getname(pos.node);
4529 pos.type = gettype(pos.node) | (pos.type & ~TBL_TYPEmask);
4530 info = getinfo(pos.node);
4532 /* pos now points to the prospective current node, go check it ********************/
4533 if (asn1_verbose) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4534 (ISOPTIONAL)?", optional":empty,
4535 (ISIMPLICIT)?", implicit":empty,
4536 tag_class[info->tclass], info->tag );
4538 if (ISOPTIONAL) { /* must check the tag */
4539 while(! MATCH) { /* check optional here again...? */
4541 g_message(" got %c%d, found %c%d", tag_class[class], tag,
4542 tag_class[info->tclass], info->tag);
4544 if (pos.node == NULL) {
4547 pos = save_pos; /* reset for next time */
4548 pos.type |= TBL_SEQUENCE_done;
4550 pos.type &= ~TBL_SEQUENCE_done;
4552 out->flags |= OUT_FLAG_dontshow;
4554 g_message(" end of optional list, constructed, expect value next time");
4557 out->flags |= OUT_FLAG_noname;
4559 g_message(" *end of optional list...");
4560 info = 0; /* this is not valid any more... */
4562 break; /* end of list */
4564 info = getinfo(pos.node);
4565 if (asn1_verbose) g_message(" optional, %s", getname(pos.node));
4567 if (pos.node && ! cons_handled) {
4568 ret = pos.name = getname(pos.node);
4569 pos.type = gettype(pos.node);
4571 /* pos now refers to node with name we want, optional nodes skipped */
4574 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4575 pos2 = pos; /* save current state */
4579 g_message(" already pushed, skip next push");
4581 typeflags &= ~TBL_CHOICE_made;
4584 if (asn1_verbose && info)
4585 g_message(" immediate choice [push], %c%d, %s",
4586 tag_class[info->tclass], info->tag, getname(pos.node));
4588 pos.node = makechoice(pos.node, class, tag);
4590 if (pos.node == NULL) {
4594 info = getinfo(pos.node);
4595 pos.type = gettype(pos.node);
4596 out->type = (pos.type & TBL_TYPEmask);
4597 out->flags |= OUT_FLAG_type;
4599 sprintf(namestr, "%s!%s", ret, getname(pos.node));
4602 g_message(" %s:%s will be used", TBLTYPE(pos.type), ret);
4603 if (typeflags & TBL_REPEAT) {
4604 pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
4606 pos.type |= TBL_SEQUENCE_choice;
4609 g_message(" return from immediate choice [%s] '%s'",
4610 TBLTYPE(pos.type), ret);
4612 out->data = pos.node; /* for access to named numbers... */
4614 out->type = (pos.type & TBL_TYPEmask);
4617 out->typename = info->typename;
4618 out->fullname = info->fullname;
4619 out->value_id = info->value_id;
4620 out->type_id = info->type_id;
4625 typeflags |= TBL_CHOICE_made;
4628 if (asn1_verbose) g_message(" matching choice '%s'", ret);
4630 if ( ! cons ) { /* ISIMPLICIT was not OK for all */
4631 pos = pos2; /* reset for continuation */
4636 g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4637 (ISOPTIONAL)?", optional":empty,
4638 (ISIMPLICIT)?", implicit":empty,
4639 tag_class[info->tclass], info->tag );
4641 g_message(" using: unknown '%s'", ret);
4644 /* must follow references now */
4645 if (pos.type == TBL_TYPEREF && info) {
4646 out->typename = info->typename;
4647 out->type_id = info->typenum;
4648 out->flags |= OUT_FLAG_typename;
4650 PUSHNODE(pos); /* remember where we were */
4651 if (asn1_verbose) g_message(" typeref [push]");
4652 typeflags |= TBL_REFERENCE;
4653 if (info->reference == 0) { /* resolved ref to universal type.... */
4654 /* showNode(pos.node, 3, 4); */
4655 pos.type = gettype(pos.node); /* the resulting type */
4656 info = getinfo(pos.node);
4657 tmp = "inknown tag";
4658 if ((info->tclass == ASN1_UNI) && (info->tag < 31)) {
4659 tmp = asn1_tag[info->tag];
4660 pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
4662 if (asn1_verbose && info)
4663 g_message(" indirect typeref to %s:%s, %s [%c%d]",
4664 TBLTYPE(pos.type), info->typename, tmp,
4665 tag_class[info->tclass], info->tag );
4667 out->fullname = info->fullname;
4668 donext = (ISANONYMOUS); /* refereing entity has no name ? */
4669 pos.node = info->reference;
4670 pos.type = gettype(pos.node);
4671 info = getinfo(pos.node);
4673 g_message(" typeref %s %s", TBLTYPE(pos.type), getname(pos.node));
4674 /* keep name from before going through the reference, unless anonymous */
4675 if (donext) /* refering entity has no name */
4676 ret = getname(pos.node); /* a better name */
4678 /* handle choice here ? !!mm!! */
4680 out->type = (pos.type & TBL_TYPEmask);
4681 out->flags |= OUT_FLAG_type;
4682 /* showNode(pos.node, 3, 4); */
4683 /* ret = getname(pos.node);*/
4685 out->data = pos.node;
4686 out->flags |= OUT_FLAG_data;
4688 g_message(" typeref set named number list node %p", pos.node);
4692 pos.type = TBL_TYPEREF_nopop;
4693 if (asn1_verbose) g_message(" typeref pop");
4694 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
4695 /* do not enter the named-number list */
4697 pos.type = TBL_TYPEREF_nopop;
4698 if (asn1_verbose) g_message(" typeref [pop]");
4700 typeflags |= TBL_REFERENCE;
4705 if (cons && ! cons_handled) { /* This entity is constructed, expected ? */
4707 case TBL_BOOLEAN: /* these are not expected to be constructed */
4709 case TBL_OCTETSTRING:
4713 case TBL_ENUMERATED:
4715 typeflags |= TBL_CONSTRUCTED;
4716 /* this entry has no extra info, next is the same */
4717 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
4718 if (asn1_verbose) g_message(" dontshow and set constructed flag");
4720 default: /* others, such as sequences, are expected to be constructed */
4727 if (asn1_verbose) g_message(" anonymous: dontshow");
4728 if (asn1_debug) /* this entry has no extra info, next is the same */
4729 out->flags |= OUT_FLAG_dontshow;
4731 out->name = empty; /* show it, but no name */
4734 if (out->name != empty)
4737 if ( ! (out->flags & OUT_FLAG_data))
4738 out->data = pos.node; /* for access to named numbers... */
4740 pos.type |= typeflags;
4743 if ( ! (out->flags & OUT_FLAG_type))
4744 out->type = pos.type;
4746 out->type &= TBL_TYPEmask;
4748 if (ret == noname) {
4750 out->flags |= OUT_FLAG_noname;
4753 if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
4754 out->typename = info->typename;
4755 out->type_id = info->typenum;
4758 if (info && (out->value_id == -1)) {
4759 out->value_id = info->value_id;
4760 out->type_id = info->type_id;
4763 if ((out->fullname == 0) && info)
4764 out->fullname = info->fullname;
4766 if (typeflags & TBL_CONSTRUCTED)
4767 constructed_save = *out;
4770 g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
4771 out->value_id, out->type_id);
4777 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
4781 const char *ret, *name;
4782 static char unnamed[] = "*unnamed*";
4784 (void) cls; (void) tag; /* make a reference */
4786 if (props->flags & OUT_FLAG_noname)
4790 list = (GNode *)props->data;
4793 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
4795 return "*list-still-0*";
4798 if ((PDUinfo *)list->data)
4799 name = ((PDUinfo *)list->data)->name;
4803 for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
4804 info = (PDUinfo *)list->data;
4805 if (value == info->tag) {
4814 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
4818 #endif /* READSYNTAX */
4821 proto_register_asn1(void) {
4823 static const enum_val_t type_recursion_opts[] = {
4837 static gint *ett[1+MAX_NEST+MAXPDU];
4841 module_t *asn1_module;
4844 asn1_logfile = get_tempfile_path(ASN1LOGFILE);
4846 current_asn1 = g_strdup("");
4847 asn1_filename = g_strdup(current_asn1);
4849 current_pduname = g_strdup("ASN1");
4850 asn1_pduname = g_strdup(current_pduname);
4852 proto_asn1 = proto_register_protocol("ASN.1 decoding",
4856 for (i=0, j=1; i<MAX_NEST; i++, j++) {
4857 ett[j] = &ett_seq[i];
4860 for(i=0; i<MAXPDU; i++, j++) {
4861 ett[j] = &ett_pdu[i];
4865 proto_register_subtree_array(ett, array_length(ett));
4867 asn1_module = prefs_register_protocol(proto_asn1,
4868 proto_reg_handoff_asn1);
4869 #ifdef JUST_ONE_PORT
4870 prefs_register_uint_preference(asn1_module, "tcp_port",
4872 "The TCP port on which "
4873 "ASN.1 messages will be read",
4874 10, &global_tcp_port_asn1);
4875 prefs_register_uint_preference(asn1_module, "udp_port",
4877 "The UDP port on which "
4878 "ASN.1 messages will be read",
4879 10, &global_udp_port_asn1);
4880 prefs_register_uint_preference(asn1_module, "sctp_port",
4882 "The SCTP port on which "
4883 "ASN.1 messages will be read",
4884 10, &global_sctp_port_asn1);
4886 g_snprintf(tmpstr, sizeof(tmpstr), "%u", TCP_PORT_ASN1);
4887 range_convert_str(&global_tcp_ports_asn1, tmpstr, 65535);
4889 g_snprintf(tmpstr, sizeof(tmpstr), "%u", UDP_PORT_ASN1);
4890 range_convert_str(&global_udp_ports_asn1, tmpstr, 65535);
4892 g_snprintf(tmpstr, sizeof(tmpstr), "%u", SCTP_PORT_ASN1);
4893 range_convert_str(&global_sctp_ports_asn1, tmpstr, 65535);
4895 prefs_register_range_preference(asn1_module, "tcp_ports",
4897 "The TCP ports on which "
4898 "ASN.1 messages will be read",
4899 &global_tcp_ports_asn1, 65535);
4900 prefs_register_range_preference(asn1_module, "udp_ports",
4902 "The UDP ports on which "
4903 "ASN.1 messages will be read",
4904 &global_udp_ports_asn1, 65535);
4905 prefs_register_range_preference(asn1_module, "sctp_ports",
4907 "The SCTP ports on which "
4908 "ASN.1 messages will be read",
4909 &global_sctp_ports_asn1, 65535);
4910 #endif /* JUST_ONE_PORT */
4912 prefs_register_bool_preference(asn1_module, "desegment_messages",
4914 "Desegment ASN.1 messages that span TCP segments",
4917 old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
4919 bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
4922 prefs_register_string_preference(asn1_module, "file",
4923 "ASN.1 type table file",
4924 "Compiled ASN.1 description of ASN.1 types",
4926 prefs_register_string_preference(asn1_module, "pdu_name",
4928 "Name of top level PDU",
4930 prefs_register_uint_preference(asn1_module, "first_pdu_offset",
4931 "Offset to first PDU in first tcp packet",
4932 "Offset for non-reassembled packets, "
4933 "wrong if this happens on other than the first packet!",
4934 10, &first_pdu_offset);
4935 prefs_register_bool_preference(asn1_module, "flat",
4937 "Show full names for all values",
4939 prefs_register_enum_preference(asn1_module, "type_recursion",
4940 "Eliminate references to level",
4941 "Allow this recursion level for eliminated type references",
4942 &type_recursion_level,
4943 type_recursion_opts, FALSE);
4944 prefs_register_bool_preference(asn1_module, "debug",
4946 "Extra output useful for debuging",
4949 prefs_register_bool_preference(asn1_module, "message_win",
4951 "show full message description",
4954 prefs_register_obsolete_preference(asn1_module, "message_win");
4956 prefs_register_bool_preference(asn1_module, "verbose_log",
4957 "Write very verbose log",
4958 "log to file $TMP/" ASN1LOGFILE,
4962 /* The registration hand-off routing */
4964 static dissector_handle_t asn1_handle;
4967 register_tcp_port(guint32 port)
4969 dissector_add("tcp.port", port, asn1_handle);
4973 unregister_tcp_port(guint32 port)
4975 dissector_delete("tcp.port", port, asn1_handle);
4979 register_udp_port(guint32 port)
4981 dissector_add("udp.port", port, asn1_handle);
4985 unregister_udp_port(guint32 port)
4987 dissector_delete("udp.port", port, asn1_handle);
4991 register_sctp_port(guint32 port)
4993 dissector_add("sctp.port", port, asn1_handle);
4997 unregister_sctp_port(guint32 port)
4999 dissector_delete("sctp.port", port, asn1_handle);
5003 proto_reg_handoff_asn1(void) {
5004 static int asn1_initialized = FALSE;
5005 #ifndef JUST_ONE_PORT
5006 char *tcp_ports_asn1_string, *udp_ports_asn1_string, *sctp_ports_asn1_string;
5011 #ifdef JUST_ONE_PORT
5012 if (asn1_verbose) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegnment=%d, "
5013 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5014 global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
5015 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5018 tcp_ports_asn1_string = range_convert_range(global_tcp_ports_asn1);
5019 udp_ports_asn1_string = range_convert_range(global_udp_ports_asn1);
5020 sctp_ports_asn1_string = range_convert_range(global_sctp_ports_asn1);
5021 g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegnment=%d, "
5022 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5023 tcp_ports_asn1_string, udp_ports_asn1_string, sctp_ports_asn1_string, asn1_desegment,
5024 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5026 #endif /* JUST_ONE_PORT */
5028 if(!asn1_initialized) {
5029 asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
5030 asn1_initialized = TRUE;
5031 } else { /* clean up ports and their lists */
5032 #ifdef JUST_ONE_PORT
5033 unregister_tcp_port(tcp_port_asn1);
5034 unregister_udp_port(udp_port_asn1);
5035 unregister_sctp_port(sctp_port_asn1);
5037 if (tcp_ports_asn1 != NULL) {
5038 range_foreach(tcp_ports_asn1, unregister_tcp_port);
5039 g_free(tcp_ports_asn1);
5042 if (udp_ports_asn1 != NULL) {
5043 range_foreach(udp_ports_asn1, unregister_udp_port);
5044 g_free(udp_ports_asn1);
5047 if (sctp_ports_asn1 != NULL) {
5048 range_foreach(sctp_ports_asn1, unregister_sctp_port);
5049 g_free(sctp_ports_asn1);
5051 #endif /* JUST_ONE_PORT */
5054 if (strcmp(asn1_filename, current_asn1) != 0) {
5055 /* new definitions, parse the file if we have one */
5056 /* !!! should be postponed until we really need it !!! */
5058 read_asn1_type_table(asn1_filename);
5059 #endif /* READSYNTAX */
5060 g_free(current_asn1);
5061 current_asn1 = g_strdup(asn1_filename);
5063 if (!PDUtree || /* no tree built yet for PDU type */
5064 strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
5065 if (build_pdu_tree(asn1_pduname)) {
5066 g_free(current_pduname);
5067 current_pduname = g_strdup(asn1_pduname);
5071 if (asn1_message_win) { /* show what we are prepared to recognize */
5073 gtk_widget_destroy (window);
5076 create_message_window();
5078 #endif /* SHOWPDU */
5080 /* If we now have a PDU tree, register for the port or ports we have */
5082 #ifdef JUST_ONE_PORT
5083 tcp_port_asn1 = global_tcp_port_asn1;
5084 udp_port_asn1 = global_udp_port_asn1;
5085 sctp_port_asn1 = global_sctp_port_asn1;
5087 register_tcp_port(tcp_port_asn1);
5088 register_udp_port(udp_port_asn1);
5089 register_sctp_port(sctp_port_asn1);
5091 tcp_ports_asn1 = range_copy(global_tcp_ports_asn1);
5092 udp_ports_asn1 = range_copy(global_udp_ports_asn1);
5093 sctp_ports_asn1 = range_copy(global_sctp_ports_asn1);
5095 range_foreach(tcp_ports_asn1, register_tcp_port);
5096 range_foreach(udp_ports_asn1, register_udp_port);
5097 range_foreach(sctp_ports_asn1, register_sctp_port);
5099 #endif /* JUST_ONE_PORT */