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.
72 #include <glib/gprintf.h>
74 #include <epan/packet.h>
75 #include <epan/addr_resolv.h>
76 #include <epan/prefs.h>
77 #include <epan/filesystem.h>
78 #include <epan/report_err.h>
79 #include <epan/dissectors/packet-tcp.h>
80 #include <epan/oids.h>
81 #include <epan/emem.h>
82 #include <plugins/asn1/asn1.h>
83 #include <wsutil/file_util.h>
85 #ifdef DISSECTOR_WITH_GUI
89 #include <epan/ipproto.h>
96 /* Define default ports */
98 #define TCP_PORT_ASN1 0
99 #define UDP_PORT_ASN1 0
100 #define SCTP_PORT_ASN1 0
102 void proto_reg_handoff_asn1(void);
104 /* Define the asn1 proto */
106 static int proto_asn1 = -1;
108 /* Define the tree for asn1*/
110 static int ett_asn1 = -1;
112 #define MAXPDU 64 /* max # PDU's in one packet */
113 static int ett_pdu[MAXPDU];
115 #define MAX_NEST 32 /* max nesting level for ASN.1 elements */
116 static int ett_seq[MAX_NEST];
119 * Global variables associated with the preferences for asn1
123 static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
124 static guint global_udp_port_asn1 = UDP_PORT_ASN1;
125 static guint global_sctp_port_asn1 = SCTP_PORT_ASN1;
127 static range_t *global_tcp_ports_asn1;
128 static range_t *global_udp_ports_asn1;
129 static range_t *global_sctp_ports_asn1;
130 #endif /* JUST_ONE_PORT */
132 static gboolean asn1_desegment = TRUE;
133 static const char *asn1_filename = NULL;
134 static char *old_default_asn1_filename = NULL;
135 #define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
137 #define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
138 static char *bad_separator_old_default_asn1_filename = NULL;
140 static char *current_asn1 = NULL;
141 static const char *asn1_pduname = NULL;
142 static char *current_pduname = NULL;
143 static gboolean asn1_debug = FALSE;
144 static guint first_pdu_offset = 0;
145 static gboolean asn1_message_win = FALSE;
146 static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
147 static gboolean asn1_full = FALSE; /* show full names */
148 static guint type_recursion_level = 1; /* eliminate 1 level of references */
149 static char *asn1_logfile = NULL;
151 #define ASN1LOGFILE "wireshark.log"
153 /* PDU counter, for correlation between GUI display and log file in debug mode */
154 static int pcount = 0;
156 static tvbuff_t *asn1_desc; /* the PDU description */
157 static GNode *asn1_nodes = NULL; /* GNode tree pointing to every asn1 data element */
158 static GNode *data_nodes = NULL; /* GNode tree describing the syntax data */
159 static GNode *PDUtree = NULL; /* GNode tree describing the expected PDU format */
161 static guint PDUerrcount = 0; /* count of parse errors in one ASN.1 message */
163 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
166 static char pabbrev[] = "asn1"; /* field prefix */
168 static char fieldname[512]; /* for constructing full names */
169 static guint pabbrev_pdu_len; /* length initial part of fieldname with 'abbrev.asn1pdu.' */
172 * Text strings describing the standard, universal, ASN.1 names.
175 #define ASN1_EOI 4 /* this is in the class number space... */
176 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
178 static const char tag_class[] = "UACPX";
180 static const char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
182 static const char *asn1_con[] = { "Primitive", "Constructed" };
184 static const char *asn1_tag[] = {
185 /* 0 */ "EOC", "Boolean", "Integer", "BitString",
186 /* 4 */ "OctetString", "Null", "ObjectIdentifier", "ObjectDescriptor",
187 /* 8 */ "External", "Real", "Enumerated", "tag11",
188 /* 12 */ "UTF8String", "tag13", "tag14", "tag15",
189 /* 16 */ "Sequence", "Set", "NumericString", "PrintableString",
190 /* 20 */ "TeletexString", "VideotexString", "IA5String", "UTCTime",
191 /* 24 */ "GeneralTime", "GraphicString", "ISO646String", "GeneralString",
192 /* 28 */ "UniversalString", "tag29", "BMPString", "Long tag prefix"
193 /* TT61 == TELETEX */
194 /* ISO646 == VISIBLE*/
197 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
198 static gboolean tbl_types_verified = FALSE;
200 typedef enum { /* copied from .../snacc/c-lib/boot/tbl.h */
209 TBL__SIMPLE = 8, /* values smaller than this can have a value */
217 TBL_SEQUENCEOF_start, /* to mark potential sequence-of repeat */
218 TBL_TYPEREF_nopop, /* typeref has been handled immediately */
219 TBL_CHOICE_done, /* choice is finished */
220 TBL_reserved, /* this sequence has been visited */
221 TBL_CHOICE_immediate, /* immediate choice, no next */
223 TBL_INVALID /* incorrect value for this enum */
226 /* Universal tags mapped to snacc ASN.1 table types */
227 static int asn1_uni_type[] = {
228 /* 0 */ TBL_INVALID, TBL_BOOLEAN, TBL_INTEGER, TBL_BITSTRING,
229 /* 4 */ TBL_OCTETSTRING, TBL_NULL, TBL_OID, TBL_INVALID,
230 /* 8 */ TBL_INVALID, TBL_REAL, TBL_ENUMERATED, TBL_INVALID,
231 /* 12 */ TBL_OCTETSTRING, TBL_INVALID, TBL_INVALID, TBL_INVALID,
232 /* 16 */ TBL_SEQUENCE, TBL_SET, TBL_OCTETSTRING, TBL_OCTETSTRING,
233 /* 20 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
234 /* 24 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
235 /* 28 */ TBL_OCTETSTRING, TBL_INVALID, TBL_OCTETSTRING, TBL_INVALID,
239 #define TBL_REPEAT 0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
240 #define TBL_REPEAT_choice 0x00020000 /* repeating a choice */
241 #define TBL_CHOICE_made 0x00040000 /* This was a choice entry */
242 #define TBL_SEQUENCE_done 0x00080000 /* children have been processed */
243 #define TBL_CHOICE_repeat 0x00100000 /* a repeating choice */
244 #define TBL_REFERENCE 0x00200000 /* This entry is result of a typeref */
245 #define TBL_REFERENCE_pop 0x00400000 /* reference handled, do pop i.s.o. next */
246 #define TBL_SEQUENCE_choice 0x00800000 /* this sequence is a first of a repeating choice */
247 #define TBL_CONSTRUCTED 0x01000000 /* unexpectedly constructed entry */
248 #define TBL_TYPEmask 0x0000FFFF /* Mask just the type */
250 /* XXX - Should we use val_to_str here? */
251 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
253 /* text tables for debugging and GUI */
254 static const char *tbl_types[] = {
255 /* 0 */ "tbl-boolean",
256 /* 1 */ "tbl-integer",
257 /* 2 */ "tbl-bitstring",
258 /* 2 */ "tbl-octetstring",
262 /* 7 */ "tbl-enumerated",
263 /* 8 */ "tbl-sequence",
265 /* 10 */ "tbl-sequenceof",
266 /* 11 */ "tbl-setof",
267 /* 12 */ "tbl-choice",
268 /* 13 */ "tbl-typeref",
270 /* 14 */ "tbl-sequenceof-start",
271 /* 15 */ "tbl-typeref-nopop",
272 /* 16 */ "tbl-choice-done",
273 /* 17 */ "tbl-reserved",
274 /* 18 */ "tbl-choice-immediate",
276 /* 19 */ "tbl-invalid",
278 static const char *tbl_types_asn1[] = {
282 /* 2 */ "OCTET STRING",
284 /* 5 */ "OBJECT IDENTIFIER",
286 /* 7 */ "ENUMERATED",
289 /* 10 */ "SEQUENCE OF",
294 /* 14 */ "start-SEQUENCE OF",
295 /* 15 */ "TYPEREF nopop",
296 /* 16 */ "CHOICE done",
298 /* 18 */ "CHOICE immediate",
300 /* 19 */ "INVALID entry",
302 /* conversion from snacc type to appropriate wireshark type */
303 static guint tbl_types_wireshark[] = {
304 /* 0 */ FT_BOOLEAN, /* TBL_BOOLEAN */
305 /* 1 */ FT_UINT32, /* TBL_INTEGER */
306 /* 2 */ FT_UINT32, /* TBL_BITSTRING */
307 /* 2 */ FT_STRINGZ, /* TBL_OCTETSTRING */
308 /* 4 */ FT_NONE, /* TBL_NULL */
309 /* 5 */ FT_BYTES, /* TBL_OID */
310 /* 6 */ FT_DOUBLE, /* TBL_REAL */
311 /* 7 */ FT_UINT32, /* TBL_ENUMERATED */
312 /* 8 */ FT_NONE, /* TBL_SEQUENCE */
313 /* 9 */ FT_NONE, /* TBL_SET */
314 /* 10 */ FT_NONE, /* TBL_SEQUENCEOF */
315 /* 11 */ FT_NONE, /* TBL_SETOF */
316 /* 12 */ FT_NONE, /* TBL_CHOICE */
317 /* 13 */ FT_NONE, /* TBL_TYPEREF */
319 /* 14 */ FT_NONE, /* TBL_SEQUENCEOF_start */
320 /* 15 */ FT_NONE, /* TBL_TYPEREF_nopop */
321 /* 16 */ FT_NONE, /* TBL_CHOICE_done */
322 /* 17 */ FT_NONE, /* TBL_reserved */
323 /* 18 */ FT_NONE, /* TBL_CHOICE_immediate */
325 /* 19 */ FT_NONE, /* TBL_INVALID */
328 static const char *tbl_types_wireshark_txt[] = {
329 /* 0 */ "FT_BOOLEAN", /* TBL_BOOLEAN */
330 /* 1 */ "FT_UINT32", /* TBL_INTEGER */
331 /* 2 */ "FT_UINT32", /* TBL_BITSTRING */
332 /* 2 */ "FT_STRINGZ", /* TBL_OCTETSTRING */
333 /* 4 */ "FT_NONE", /* TBL_NULL */
334 /* 5 */ "FT_BYTES", /* TBL_OID */
335 /* 6 */ "FT_DOUBLE", /* TBL_REAL */
336 /* 7 */ "FT_UINT32", /* TBL_ENUMERATED */
337 /* 8 */ "FT_NONE", /* TBL_SEQUENCE */
338 /* 9 */ "FT_NONE", /* TBL_SET */
339 /* 10 */ "FT_NONE", /* TBL_SEQUENCEOF */
340 /* 11 */ "FT_NONE", /* TBL_SETOF */
341 /* 12 */ "FT_NONE", /* TBL_CHOICE */
342 /* 13 */ "FT_NONE", /* TBL_TYPEREF */
344 /* 14 */ "FT_NONE", /* TBL_SEQUENCEOF_start */
345 /* 15 */ "FT_NONE", /* TBL_TYPEREF_nopop */
346 /* 16 */ "FT_NONE", /* TBL_CHOICE_done */
347 /* 17 */ "FT_NONE", /* TBL_reserved */
348 /* 18 */ "FT_NONE", /* TBL_CHOICE_immediate */
350 /* 19 */ "FT_NONE", /* TBL_INVALID */
353 typedef struct _PDUinfo PDUinfo;
357 const char *typename;
358 const char *fullname;
364 gint basetype; /* parent type */
365 gint mytype; /* original type number, typenum may have gone through a reference */
366 gint value_id; /* wireshark field id for the value in this PDU */
367 gint type_id; /* wireshark field id for the type of this PDU */
368 hf_register_info value_hf; /* wireshark field info for this value */
372 /* bits in the flags collection */
373 #define PDU_OPTIONAL 1
374 #define PDU_IMPLICIT 2
375 #define PDU_NAMEDNUM 4
376 #define PDU_REFERENCE 8
377 #define PDU_TYPEDEF 0x10
378 #define PDU_ANONYMOUS 0x20
379 #define PDU_TYPETREE 0x40
381 #define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
383 static guint PDUinfo_initflags = 0; /* default flags for newly allocated PDUinfo structs */
385 /* description of PDU properties as passed from the matching routine
386 * to the decoder and GUI.
388 typedef struct _PDUprops PDUprops;
390 guint type; /* value from enum TBLTypeId */
392 const char *typename;
393 const char *fullname;
399 /* flags defined in PDUprops.flags */
400 #define OUT_FLAG_type 1
401 #define OUT_FLAG_data 2
402 #define OUT_FLAG_typename 4
403 #define OUT_FLAG_dontshow 8
404 #define OUT_FLAG_noname 0x10
405 #define OUT_FLAG_constructed 0x20
407 static PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
408 static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
410 static const char empty[] = ""; /* address of the empt string, avoids many tests for NULL */
411 #define MAX_OTSLEN 256 /* max printed size for an octet string */
414 #undef NEST /* show nesting of asn.1 enties */
416 #ifdef NEST /* only for debugging */
417 /* show nesting, only for debugging... */
418 #define MAXTAGS MAX_NEST
424 static char *showtaglist(guint level)
426 static char tagtxt[BUFLM];
431 for(i=0; i<= level; i++) {
432 switch(taglist[i].cls) {
433 case BER_CLASS_UNI: *p++ = 'U'; break;
434 case BER_CLASS_APP: *p++ = 'A'; break;
435 case BER_CLASS_CON: *p++ = 'C'; break;
436 case BER_CLASS_PRI: *p++ = 'P'; break;
437 default: *p++ = 'x'; break;
439 p += g_sprintf(p, "%d.", taglist[i].tag);
441 #else /* only context tags */
443 for(i=0; i<= level; i++) {
444 if (taglist[i].cls == BER_CLASS_CON) {
445 p += g_sprintf(p, "%d.", taglist[i].tag);
449 *--p = 0; /* remove trailing '.' */
454 get_context(guint level)
459 for(i=0; i<=level; i++) {
460 if (taglist[i].cls == BER_CLASS_CON)
461 ctx = (ctx << 8) | taglist[i].tag;
465 #endif /* NEST, only for debugging */
468 /* Convert a bit string to an ascii representation for printing
469 * -- not thread safe ...
471 static const char *showbits(guchar *val, guint count)
473 static char str[BUFLM];
478 return "*too many bits*";
481 for(i=0; i<count; i++) {
482 if (i && ((i & 7) == 0)) *p++ = ' ';
483 *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
490 /* get bitnames string for bits set */
492 showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
494 static char str[BUFLL];
498 if (props->flags & OUT_FLAG_noname)
502 return "*too many bits, no names...*";
505 for(i=0; i<count; i++) {
506 if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
507 p += g_sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
511 --p; /* remove terminating , */
519 /* Convert an oid to its conventional text representation
520 * -- not thread safe...
522 static char *showoid(subid_t *oid, guint len)
524 static char str[BUFLM];
529 for(i=0; i<len; i++) {
531 p += g_sprintf(p, "%lu", (unsigned long)oid[i]);
538 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
540 showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
545 const char *endstr = empty;
551 for (i=0; i<len; i++) {
552 if (!isprint(octets[i])) /* maybe isblank() as well ... */
555 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
557 endstr = "...."; /* this is 5 bytes !! */
560 str = p = g_malloc(len*2 + 5);
561 for (i=0; i<len; i++) {
562 p += g_sprintf(p, "%2.2X", octets[i]);
564 strncpy(p, endstr, 5);
566 if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
567 str = p = g_malloc(len*3+2);
568 for (i=0; i<len; i++) {
569 p += g_sprintf(p, "%2.2X", octets[i]);
571 *p++ = ' '; /* insert space */
572 strncpy(p, octets, len);
575 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
576 str = g_malloc(len+5);
577 strncpy(str, octets, len);
578 strncpy(&str[len], endstr, 5);
585 /* allow NULL pointers in strcmp, handle them as empty strings */
587 g_strcmp(gconstpointer a, gconstpointer b)
589 if (a == 0) a = empty;
590 if (b == 0) b = empty;
594 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
595 /* WARNING WARNING WARNING WARNING WARNING WARNING */
597 /* Most of the following routine is guesswork in order to */
598 /* speed up resynchronisation if the dissector lost the */
599 /* encoding due to incomplete captures, or a capture that */
600 /* starts in the middle of a fragmented ip packet */
601 /* If this poses to many problems, these settings can be */
602 /* made part of the protocol settings in the user interface */
603 /*************************************************************/
605 /* check length for a reasonable value, return a corrected value */
607 checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
612 g_snprintf(lenstr, strmax, "indefinite");
616 if (len < 0) /* negative ..... */
619 if (cls != BER_CLASS_UNI) { /* don't know about the tags */
624 case BER_UNI_TAG_EOC: /* End Of Contents */
625 case BER_UNI_TAG_NULL: /* Null */
628 case BER_UNI_TAG_BOOLEAN: /* Boolean */
631 case BER_UNI_TAG_INTEGER: /* Integer */
632 case BER_UNI_TAG_ENUMERATED: /* Enumerated */
636 case BER_UNI_TAG_BITSTRING: /* Bit String */
640 case BER_UNI_TAG_OCTETSTRING: /* Octet String */
641 case BER_UNI_TAG_NumericString: /* Numerical String */
642 case BER_UNI_TAG_PrintableString: /* Printable String */
643 case BER_UNI_TAG_TeletexString: /* Teletext String */
644 case BER_UNI_TAG_VideotexString: /* Video String */
645 case BER_UNI_TAG_IA5String: /* IA5 String */
646 case BER_UNI_TAG_GraphicString: /* Graphical String */
647 case BER_UNI_TAG_VisibleString: /* Visible String */
648 case BER_UNI_TAG_GeneralString: /* General String */
652 case BER_UNI_TAG_OID: /* Object Identifier */
653 case BER_UNI_TAG_ObjectDescriptor: /* Description */
654 case ASN1_EXT: /* External */
658 case BER_UNI_TAG_REAL: /* Real */
662 case BER_UNI_TAG_SEQUENCE: /* Sequence */
663 case BER_UNI_TAG_SET: /* Set */
667 case BER_UNI_TAG_UTCTime: /* Universal Time */
668 case BER_UNI_TAG_GeneralizedTime: /* General Time */
681 /* a change was needed.... */
682 g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
684 g_snprintf(lenstr, strmax, "%d", len);
689 static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
690 static void PDUreset(int count, int counr2);
693 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
696 guint cls, con, tag, len, offset, reassembled;
702 const char *name, *tname;
703 volatile guint boffset;
704 volatile int i = 0; /* PDU counter */
705 proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
706 proto_item *hidden_item;
708 static guint lastseq;
709 struct tcpinfo *info;
715 reassembled = 1; /* UDP is not a stream, and thus always reassembled .... */
716 if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
717 info = (struct tcpinfo *)pinfo->private_data;
718 delta = info->seq - lastseq;
719 reassembled = info->is_reassembled;
723 g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
724 info->seq, delta, reassembled);
727 g_message("dissect_asn1: udp");
730 /* Set the protocol column */
731 if(check_col(pinfo->cinfo, COL_PROTOCOL)){
732 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
735 col_clear(pinfo->cinfo, COL_INFO);
739 if ((first_pdu_offset > 0) && !reassembled) {
740 boffset = first_pdu_offset;
741 g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
744 /* open BER decoding */
745 asn1_open(&asn1, tvb, boffset);
747 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
749 asn1_close(&asn1, &offset);
751 PDUreset(pcount, 0); /* arguments are just for debugging */
752 getPDUprops(&props, boffset, cls, tag, con);
754 tname = props.typename;
756 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
760 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
762 g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
769 ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
775 if (props.flags & OUT_FLAG_noname) {
776 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
777 name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
779 g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
782 /* Set the info column */
783 if(check_col(pinfo->cinfo, COL_INFO)){
784 col_add_str(pinfo->cinfo, COL_INFO, headstr );
788 * If we have a non-null tree (ie we are building the proto_tree
789 * instead of just filling out the columns ), then add a BER
793 /* ignore the tree here, must decode BER to know how to reassemble!! */
796 TRY { /* catch incomplete PDU's */
798 ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
799 def? (int) (offset - boffset + len) : -1,
800 "ASN.1 %s", current_pduname);
802 tree2 = proto_item_add_subtree(ti, ett_asn1);
804 hidden_item = proto_tree_add_item(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
805 def? (int) (offset - boffset + len) : -1, TRUE);
806 PROTO_ITEM_SET_HIDDEN(hidden_item);
808 offset = boffset; /* the first packet */
809 while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
812 /* open BER decoding */
813 asn1_open(&asn1, tvb, offset);
814 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
815 asn1_close(&asn1, &offset);
817 PDUreset(pcount, i+1);
818 getPDUprops(&props, boffset, cls, tag, con);
820 tname = props.typename;
823 len = tvb_length_remaining(tvb, offset);
825 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
829 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
831 g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
834 ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
837 tvb_length_remaining(tvb, offset) );
839 if (props.value_id == -1)
840 ti2 = proto_tree_add_text(tree2, tvb, boffset,
841 def? (int) (offset - boffset + len) : -1,
842 "%s: (%s)%s %d-%d %s", current_pduname,
843 tname, name, pcount, i+1, headstr);
845 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
846 def? (int) (offset - boffset + len) : -1,
847 "%s: (%s)%s %d-%d %s ~", current_pduname,
848 tname, name, pcount, i+1, headstr);
850 if (props.type_id != -1){
851 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
852 def? (int) (offset - boffset + len) : -1, TRUE);
853 PROTO_ITEM_SET_HIDDEN(hidden_item);
858 if (props.flags & OUT_FLAG_noname) {
859 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
860 name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
862 if (props.value_id == -1)
863 ti2 = proto_tree_add_text(tree2, tvb, boffset,
864 def? (int) (offset - boffset + len) : -1,
865 "%s: (%s)%s", current_pduname, tname, name);
867 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
868 def? (int) (offset - boffset + len) : -1,
869 "%s: (%s)%s ~", current_pduname, tname, name);
870 if (props.type_id != -1){
871 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
872 def? (int) (offset - boffset + len) : -1, TRUE);
873 PROTO_ITEM_SET_HIDDEN(hidden_item);
877 asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
880 taglist[0].cls = cls;
881 taglist[0].tag = tag;
884 if (!def) len++; /* make sure we get an exception if we run off the end! */
886 offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
888 proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
890 i++; /* one more full message handled */
892 if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
893 proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
895 if(check_col(pinfo->cinfo, COL_INFO))
896 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
898 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
903 CATCH(ReportedBoundsError) {
904 if(check_col(pinfo->cinfo, COL_INFO))
905 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
907 proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
909 proto_item_append_text(ti2, " (incomplete)");
910 if (asn1_desegment) {
911 pinfo->desegment_offset = boffset;
912 pinfo->desegment_len = 1;
914 g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
915 boffset, 1, pinfo->can_desegment);
923 g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
924 pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
927 /* decode an ASN.1 sequence, until we have consumed the specified length */
929 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
932 guint ret, cls, con, tag, len, boffset, soffset, eos;
935 const char *clsstr, *constr, *tagstr;
939 proto_tree *ti, *pt2;
940 proto_item *hidden_item;
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 g_sprintf(fieldname, "%s[%s]", props.name, props.fullname);
978 clsstr = asn1_cls[cls];
979 constr = asn1_con[con];
980 if ((cls == BER_CLASS_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 */
1009 cls = BER_CLASS_UNI;
1010 tag = BER_UNI_TAG_GeneralString;
1011 oname = g_malloc(strlen(name) + 32);
1012 g_sprintf(oname, "%s ** nesting cut off **", name);
1016 case BER_CLASS_UNI: /* fprintf(stderr, "Universal\n"); */
1018 case BER_UNI_TAG_INTEGER:
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 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1036 boffset, offset - boffset, value);
1037 PROTO_ITEM_SET_HIDDEN(hidden_item);
1041 if ( (props.value_id == -1) ||
1042 (tbl_types_wireshark[props.type] != FT_UINT32) )
1043 /* unknown or unexpected, just text */
1044 proto_tree_add_text(pt, tvb, boffset,
1046 "(%s)%s: %d", tname, name, value);
1048 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1049 offset - boffset, value,
1050 "(%s)%s: %d ~", tname, name, value);
1051 if (props.type_id != -1){
1052 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1053 boffset, offset - boffset, value);
1054 PROTO_ITEM_SET_HIDDEN(hidden_item);
1060 case BER_UNI_TAG_ENUMERATED:
1061 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1062 asn1_close(&asn1, &offset); /* mark where we are now */
1063 ename = getPDUenum(&props, boffset, cls, tag, value);
1065 if ( (props.value_id == -1) ||
1066 (tbl_types_wireshark[props.type] != FT_UINT32) )
1067 /* unknown or unexpected, just text */
1068 proto_tree_add_text(pt, tvb, boffset,
1070 textfmt_e, boffset, clsstr, constr, tagstr,
1071 tname, name, value, ename, empty);
1073 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1074 offset - boffset, value,
1075 textfmt_e, boffset, clsstr, constr, tagstr,
1076 tname, name, value, ename, matchind);
1077 if (props.type_id != -1){
1078 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1079 boffset, offset - boffset, value);
1080 PROTO_ITEM_SET_HIDDEN(hidden_item);
1084 if ( (props.value_id == -1) ||
1085 (tbl_types_wireshark[props.type] != FT_UINT32) )
1086 /* unknown or unexpected, just text */
1087 proto_tree_add_text(pt, tvb, boffset,
1089 "(%s)%s: %d:%s", tname, name, value, ename);
1091 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1092 offset - boffset, value,
1093 "(%s)%s: %d:%s ~", tname, name, value, ename);
1094 if (props.type_id != -1){
1095 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1096 boffset, offset - boffset, value);
1097 PROTO_ITEM_SET_HIDDEN(hidden_item);
1103 case BER_UNI_TAG_BOOLEAN:
1104 ret = asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1105 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1107 if ( (props.value_id == -1) ||
1108 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1109 /* unknown or unexpected, just text */
1110 proto_tree_add_text(pt, tvb, boffset,
1112 textfmt_s, boffset, clsstr, constr, tagstr,
1113 tname, name, value? "true" : "false", empty);
1115 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1116 offset - boffset, value != 0,
1117 textfmt_s, boffset, clsstr, constr, tagstr,
1118 tname, name, value? "true" : "false", matchind);
1119 if (props.type_id != -1){
1120 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1121 boffset, offset - boffset, value != 0);
1122 PROTO_ITEM_SET_HIDDEN(hidden_item);
1126 if ( (props.value_id == -1) ||
1127 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1128 /* unknown or unexpected, just text */
1129 proto_tree_add_text(pt, tvb, boffset,
1131 "(%s)%s: %s", tname, name,
1132 value? "true" : "false");
1134 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1135 offset - boffset, value != 0,
1136 "(%s)%s: %s ~", tname, name,
1137 value? "true" : "false");
1138 if (props.type_id != -1){
1139 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1140 boffset, offset - boffset, value != 0);
1141 PROTO_ITEM_SET_HIDDEN(hidden_item);
1147 case BER_UNI_TAG_OCTETSTRING:
1148 case BER_UNI_TAG_NumericString:
1149 case BER_UNI_TAG_PrintableString:
1150 case BER_UNI_TAG_TeletexString:
1151 case BER_UNI_TAG_IA5String:
1152 case BER_UNI_TAG_GeneralString:
1153 case BER_UNI_TAG_UTCTime:
1154 case BER_UNI_TAG_GeneralizedTime:
1155 /* read value, \0 terminated */
1156 ret = asn1_string_value_decode(&asn1, len, &octets);
1157 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1158 ename = showoctets(octets, len, (tag == BER_UNI_TAG_OCTETSTRING) ? 4 : 0 );
1160 if ( (props.value_id == -1) ||
1161 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1162 /* unknown or unexpected, just text */
1163 proto_tree_add_text(pt, tvb, boffset,
1165 textfmt_s, boffset, clsstr, constr, tagstr,
1166 tname, name, ename, empty);
1168 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1169 offset - boffset, octets, /* \0 termnated */
1170 textfmt_s, boffset, clsstr, constr, tagstr,
1171 tname, name, ename, matchind);
1172 if (props.type_id != -1){
1173 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1174 boffset, offset - boffset, octets);
1175 PROTO_ITEM_SET_HIDDEN(hidden_item);
1179 if ( (props.value_id == -1) ||
1180 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1181 /* unknown or unexpected, just text */
1182 proto_tree_add_text(pt, tvb, boffset,
1184 "(%s)%s: %s", tname, name, ename);
1186 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1187 offset - boffset, octets, /* \0 terminated */
1188 "(%s)%s: %s ~", tname, name, ename);
1189 if (props.type_id != -1){
1190 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1191 boffset, offset - boffset, octets);
1192 PROTO_ITEM_SET_HIDDEN(hidden_item);
1197 g_free( (gpointer) ename);
1200 case BER_UNI_TAG_BITSTRING:
1201 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1202 asn1_close(&asn1, &offset); /* mark where we are now */
1203 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1205 if ( (props.value_id == -1) ||
1206 (tbl_types_wireshark[props.type] != FT_UINT32) )
1207 /* unknown or unexpected, just text */
1208 proto_tree_add_text(pt, tvb, boffset,
1210 textfmt_b, boffset, clsstr, constr, tagstr,
1212 showbits(bits, (con*8)-unused), ename, empty);
1214 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1215 offset - boffset, *bits, /* XXX length ? XXX */
1216 textfmt_b, boffset, clsstr, constr, tagstr,
1218 showbits(bits, (con*8)-unused),ename, matchind);
1219 if (props.type_id != -1){
1220 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1221 boffset, offset - boffset, *bits);
1222 PROTO_ITEM_SET_HIDDEN(hidden_item);
1227 if ( (props.value_id == -1) ||
1228 (tbl_types_wireshark[props.type] != FT_UINT32) )
1229 /* unknown or unexpected, just text */
1230 proto_tree_add_text(pt, tvb, boffset,
1232 "(%s)%s: %s:%s", tname, name,
1233 showbits(bits, (con*8)-unused), ename);
1235 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1236 offset - boffset, *bits, /* XXX length ? XXX */
1237 "(%s)%s: %s:%s ~", tname, name,
1238 showbits(bits, (con*8)-unused), ename);
1239 if (props.type_id != -1){
1240 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1241 boffset, offset - boffset, *bits);
1242 PROTO_ITEM_SET_HIDDEN(hidden_item);
1249 case BER_UNI_TAG_SET:
1250 case BER_UNI_TAG_SEQUENCE:
1251 /* show full sequence length */
1254 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1256 if ( (props.flags & OUT_FLAG_constructed))
1257 ename = ", unexpected constructed";
1259 if (props.value_id == -1)
1260 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1261 textfmt_c, boffset, clsstr, constr, tagstr,
1262 tname, name, ename, empty);
1264 ti = proto_tree_add_item(pt, props.value_id, tvb,
1266 /* change te text to to what I really want */
1267 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1268 tagstr, tname, name, ename, matchind);
1269 if (props.type_id != -1){
1270 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1272 PROTO_ITEM_SET_HIDDEN(hidden_item);
1276 if (props.value_id == -1) {
1277 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1278 ti = proto_tree_add_text(pt, tvb, boffset,
1279 offset - boffset + len,
1280 "(%s)%s", tname, name);
1282 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1283 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1284 boffset, offset - boffset + len,
1285 "(%s)%s ~", tname, name);
1287 /* don't care about the text */
1288 ti = hidden_item = proto_tree_add_item(pt, props.value_id, tvb,
1290 PROTO_ITEM_SET_HIDDEN(hidden_item);
1292 if (props.type_id != -1){
1293 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1295 PROTO_ITEM_SET_HIDDEN(hidden_item);
1299 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1301 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1302 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1306 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1308 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1309 proto_item_set_len(ti, offset - boffset);
1313 case BER_UNI_TAG_EOC:
1314 if (asn1_debug) { /* don't show if not debugging */
1315 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1316 boffset, clsstr, constr, tagstr, tname, name,
1317 offset - soffset, empty);
1319 getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1322 case BER_UNI_TAG_OID:
1323 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1324 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1325 ename = showoid(oid, con);
1327 if ( (props.value_id == -1) ||
1328 (tbl_types_wireshark[props.type] != FT_BYTES) )
1329 /* unknown or unexpected, just text */
1330 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1331 boffset, clsstr, constr, tagstr, tname, name,
1334 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1335 offset - boffset, ename,/* XXX length?*/
1336 "(%s)%s: %s ~", tname, name, ename);
1337 if (props.type_id != -1){
1338 hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1339 boffset, offset - boffset, ename);
1340 PROTO_ITEM_SET_HIDDEN(hidden_item);
1344 if ( (props.value_id == -1) ||
1345 (tbl_types_wireshark[props.type] != FT_BYTES) )
1346 /* unknown or unexpected, just text */
1347 proto_tree_add_text(pt, tvb, boffset,
1349 "(%s)%s: %s", tname, name, ename);
1351 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1352 offset - boffset, ename, /* XXX length ? */
1353 "(%s)%s: %s ~", tname, name, ename);
1354 if (props.type_id != -1){
1355 hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1356 boffset, offset - boffset, ename);
1357 PROTO_ITEM_SET_HIDDEN(hidden_item);
1364 case BER_UNI_TAG_NULL:
1366 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1367 boffset, clsstr, constr, tagstr, tname, name,
1370 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1371 "(%s)%s: [NULL]", tname, name);
1373 offset += len; /* skip value ... */
1376 case BER_UNI_TAG_ObjectDescriptor:
1378 case BER_UNI_TAG_REAL:
1379 case BER_UNI_TAG_VideotexString:
1380 case BER_UNI_TAG_GraphicString:
1381 case BER_UNI_TAG_VisibleString:
1385 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1386 textfmt_s, boffset, clsstr, constr, tagstr,
1387 tname, name, lenbuf, empty);
1389 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1390 "(%s)%s: %s bytes", tname, name, lenbuf);
1392 proto_item_append_text(ti, " *"); /* indicate default is used */
1393 offset += len; /* skip value ... */
1398 case BER_CLASS_CON: /* fprintf(stderr, "Context\n"); */
1399 case BER_CLASS_APP: /* fprintf(stderr, "Application\n"); */
1400 case BER_CLASS_PRI: /* fprintf(stderr, "Private\n"); */
1403 if (props.value_id == -1) /* type unknown, handle as string */
1405 switch(props.type) {
1406 /* this is via the asn1 description, don't trust the length */
1410 ret = asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
1411 asn1_close(&asn1, &offset); /* mark where we are now */
1413 if ( (props.value_id == -1) ||
1414 (tbl_types_wireshark[props.type] != FT_UINT32) )
1415 /* unknown or unexpected, just text */
1416 proto_tree_add_text(pt, tvb,
1417 boffset, offset - boffset,
1418 textfmt_d, boffset, clsstr, constr,
1419 tagstr, tname, name, value, empty);
1421 proto_tree_add_uint_format(pt, props.value_id, tvb,
1422 boffset, offset - boffset, value,
1423 textfmt_d, boffset, clsstr, constr,
1424 tagstr, tname, name, value, matchind);
1425 if (props.type_id != -1){
1426 hidden_item = proto_tree_add_uint(pt, props.type_id,
1427 tvb, boffset, offset - boffset, value);
1428 PROTO_ITEM_SET_HIDDEN(hidden_item);
1432 if ( (props.value_id == -1) ||
1433 (tbl_types_wireshark[props.type] != FT_UINT32) )
1434 /* unknown or unexpected, just text */
1435 proto_tree_add_text(pt, tvb,
1436 boffset, offset - boffset,
1437 "(%s)%s: %d", tname, name, value);
1439 proto_tree_add_uint_format(pt, props.value_id, tvb,
1440 boffset, offset - boffset, value,
1441 "(%s)%s: %d ~", tname, name, value);
1442 if (props.type_id != -1){
1443 hidden_item = proto_tree_add_uint(pt, props.type_id,
1444 tvb, boffset, offset - boffset, value);
1445 PROTO_ITEM_SET_HIDDEN(hidden_item);
1451 case TBL_ENUMERATED:
1454 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1455 asn1_close(&asn1, &offset); /* mark where we are now */
1456 ename = getPDUenum(&props, boffset, cls, tag, value);
1458 if ( (props.value_id == -1) ||
1459 (tbl_types_wireshark[props.type] != FT_UINT32) )
1460 /* unknown or unexpected, just text */
1461 proto_tree_add_text(pt, tvb,
1462 boffset, offset - boffset,
1463 textfmt_e, boffset, clsstr, constr,
1464 tagstr, tname, name, value, ename, empty);
1466 proto_tree_add_uint_format(pt, props.value_id, tvb,
1467 boffset, offset - boffset, value,
1468 textfmt_e, boffset, clsstr, constr,
1469 tagstr, tname, name, value, ename, matchind);
1470 if (props.type_id != -1){
1471 hidden_item = proto_tree_add_uint(pt, props.type_id,
1472 tvb, boffset, offset - boffset, value);
1473 PROTO_ITEM_SET_HIDDEN(hidden_item);
1477 if ( (props.value_id == -1) ||
1478 (tbl_types_wireshark[props.type] != FT_UINT32) )
1479 /* unknown or unexpected, just text */
1480 proto_tree_add_text(pt, tvb,
1481 boffset, offset - boffset,
1482 "(%s)%s: %d:%s", tname, name, value, ename);
1484 proto_tree_add_uint_format(pt, props.value_id, tvb,
1485 boffset, offset - boffset, value,
1486 "(%s)%s: %d:%s ~", tname, name, value, ename);
1487 if (props.type_id != -1){
1488 hidden_item = proto_tree_add_uint(pt, props.type_id,
1489 tvb, boffset, offset - boffset, value);
1490 PROTO_ITEM_SET_HIDDEN(hidden_item);
1496 if (len > (1+4)) /* max 32 bits ...?.. */
1499 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1500 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1501 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1503 if ( (props.value_id == -1) ||
1504 (tbl_types_wireshark[props.type] != FT_UINT32) )
1505 /* unknown or unexpected, just text */
1506 proto_tree_add_text(pt, tvb,
1507 boffset, offset - boffset,
1508 textfmt_b, boffset, clsstr, constr,
1509 tagstr, tname, name,
1510 showbits(bits, (con*8)-unused), ename,
1513 proto_tree_add_uint_format(pt, props.value_id, tvb,
1514 boffset, offset - boffset, *bits,
1515 textfmt_b, boffset, clsstr, constr,
1516 tagstr, tname, name,
1517 showbits(bits, (con*8)-unused), ename,
1519 if (props.type_id != -1){
1520 hidden_item = proto_tree_add_uint(pt, props.type_id,
1521 tvb, boffset, offset - boffset, *bits);
1522 PROTO_ITEM_SET_HIDDEN(hidden_item);
1526 if ( (props.value_id == -1) ||
1527 (tbl_types_wireshark[props.type] != FT_UINT32) )
1528 /* unknown or unexpected, just text */
1529 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1530 "(%s)%s: %s:%s", tname, name,
1531 showbits(bits, (con*8)-unused), ename);
1533 proto_tree_add_uint_format(pt, props.value_id, tvb,
1534 boffset, offset - boffset, *bits,
1535 "(%s)%s: %s:%s ~", tname, name,
1536 showbits(bits, (con*8)-unused), ename);
1537 if (props.type_id != -1){
1538 hidden_item = proto_tree_add_uint(pt, props.type_id,
1539 tvb, boffset, offset - boffset, *bits);
1540 PROTO_ITEM_SET_HIDDEN(hidden_item);
1549 ret = asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1550 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1552 if ( (props.value_id == -1) ||
1553 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1554 /* unknown or unexpected, just text */
1555 proto_tree_add_text(pt, tvb,
1556 boffset, offset - boffset,
1557 textfmt_s, boffset, clsstr, constr,
1558 tagstr, tname, name,
1559 value? "true" : "false", empty);
1561 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1562 boffset, offset - boffset, value != 0,
1563 textfmt_s, boffset, clsstr, constr,
1564 tagstr, tname, name,
1565 value? "true" : "false", matchind);
1566 if (props.type_id != -1){
1567 hidden_item = proto_tree_add_boolean(pt, props.type_id,
1568 tvb, boffset, offset - boffset, value != 0);
1569 PROTO_ITEM_SET_HIDDEN(hidden_item);
1573 if ( (props.value_id == -1) ||
1574 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1575 /* unknown or unexpected, just text */
1576 proto_tree_add_text(pt, tvb,
1577 boffset, offset - boffset,
1578 "(%s)%s: %s", tname, name,
1579 value? "true" : "false");
1581 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1582 boffset, offset - boffset, value != 0,
1583 "(%s)%s: %s ~", tname, name,
1584 value? "true" : "false");
1585 if (props.type_id != -1){
1586 hidden_item = proto_tree_add_boolean(pt, props.type_id,
1587 tvb, boffset, offset - boffset, value != 0);
1588 PROTO_ITEM_SET_HIDDEN(hidden_item);
1597 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1598 textfmt_s, boffset, clsstr, constr,
1599 tagstr, tname, name, "[NULL]", empty);
1601 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1602 "(%s)%s: [NULL]", tname, name);
1604 offset += len; /* skip value ... */
1608 props.value_id = -1; /* unlikely this is correct, dont use it */
1610 case TBL_OCTETSTRING:
1611 /* defined length, not constructed, must be a string.... */
1612 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1613 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1614 ename = showoctets(octets, len, 2); /* convert octets to printable */
1616 if ( (props.value_id == -1) ||
1617 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1618 /* unknown or unexpected, just text */
1619 proto_tree_add_text(pt, tvb,
1620 boffset, offset - boffset,
1621 textfmt_s, boffset, clsstr, constr,
1622 tagstr, tname, name, ename, empty);
1624 proto_tree_add_string_format(pt, props.value_id, tvb,
1625 boffset, offset - boffset, (gchar *)octets, /* XXX */
1626 textfmt_s, boffset, clsstr, constr,
1627 tagstr, tname, name, ename, matchind);
1628 if (props.type_id != -1){
1629 hidden_item = proto_tree_add_string(pt, props.type_id,
1630 tvb, boffset, offset - boffset, (gchar *)octets);
1631 PROTO_ITEM_SET_HIDDEN(hidden_item);
1635 if ( (props.value_id == -1) ||
1636 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1637 /* unknown or unexpected, just text */
1638 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1639 "(%s)%s: %s", tname, name, ename);
1641 proto_tree_add_string_format(pt, props.value_id, tvb,
1642 boffset, offset - boffset, (gchar *)octets, /* XXX */
1643 "(%s)%s: %s ~", tname, name, ename);
1644 if (props.type_id != -1){
1645 hidden_item = proto_tree_add_string(pt, props.type_id,
1646 tvb, boffset, offset - boffset, (gchar *)octets);
1647 PROTO_ITEM_SET_HIDDEN(hidden_item);
1652 g_free( (gpointer) ename);
1656 /* indefinite length or constructed.... must be a sequence .... */
1657 /* show full sequence length */
1660 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1662 if ( (props.flags & OUT_FLAG_constructed))
1663 ename = ", unexpected constructed";
1665 if (props.value_id == -1)
1666 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1667 textfmt_c, boffset, clsstr, constr,
1668 tagstr, tname, name, ename, empty);
1670 ti = proto_tree_add_item(pt, props.value_id, tvb,
1672 /* change te text to to what I really want */
1674 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1675 tagstr, tname, name, ename, matchind);
1676 if (props.type_id != -1){
1677 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1679 PROTO_ITEM_SET_HIDDEN(hidden_item);
1682 ti = proto_tree_add_text(pt, tvb, boffset,
1683 offset - boffset + len,
1684 textfmt_c, boffset, clsstr, constr,
1685 tagstr, tname, name, ename, empty);
1689 if (props.value_id == -1) {
1690 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1691 ti = proto_tree_add_text(pt, tvb, boffset,
1692 offset - boffset + len, "(%s)%s", tname, name);
1694 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1695 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1697 "(%s)%s ~", tname, name);
1699 /* don't care about the text */
1700 ti = proto_tree_add_item(pt, props.value_id,
1701 tvb, boffset, 1, TRUE);
1702 PROTO_ITEM_SET_HIDDEN(ti);
1704 if (props.type_id != -1){
1705 hidden_item = proto_tree_add_item(pt, props.type_id,
1706 tvb, boffset, 1, TRUE);
1707 PROTO_ITEM_SET_HIDDEN(hidden_item);
1712 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1714 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1715 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1719 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1721 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1722 proto_item_set_len(ti, offset - boffset);
1726 default: /* fprintf(stderr, "Other\n"); */
1728 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1729 textfmt_s, boffset, clsstr, constr, tagstr,
1730 tname, name, lenbuf, empty);
1732 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1733 "(%s)%s: %s bytes %s data", tname, name,
1736 proto_item_append_text(ti, " *"); /* indicate default is used */
1737 offset += len; /* skip value ... */
1740 g_free(oname); /* XXX, memory management ? */
1742 /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1744 getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1751 /************************************************************************************************/
1752 /* search throug the ASN.1 description for appropriate names */
1753 /************************************************************************************************/
1755 guint lev_limit = G_MAXINT;
1757 int icount = 0; /* item counter */
1760 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1763 guint eos, ret, cls, con, tag, len, value;
1765 guchar *octets, *bits, unused;
1767 const char *clsstr, *constr, *tagstr;
1770 GNode *cur_node = 0;
1772 eos = offset + size;
1774 if (level > lev_limit)
1777 while(offset < eos) {
1778 if (ptr) /* build pointer tree to all asn1 enteties */
1779 cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
1781 asn1_open(&asn1, tvb, offset);
1782 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1783 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
1785 clsstr = asn1_cls[cls];
1786 constr = asn1_con[con];
1787 if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
1788 tagstr = asn1_tag[tag];
1790 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1794 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1796 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1797 len = tvb_length_remaining(tvb, offset);
1801 case BER_CLASS_UNI: /* fprintf(stderr, "Universal\n"); */
1803 case BER_UNI_TAG_INTEGER:
1804 case BER_UNI_TAG_ENUMERATED:
1805 ret = asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
1806 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
1809 case BER_UNI_TAG_BOOLEAN:
1810 ret = asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1811 asn1_close(&asn1, &offset); /* mark where we are */
1814 case BER_UNI_TAG_OCTETSTRING:
1815 case BER_UNI_TAG_NumericString:
1816 case BER_UNI_TAG_PrintableString:
1817 case BER_UNI_TAG_TeletexString:
1818 case BER_UNI_TAG_IA5String:
1819 case BER_UNI_TAG_GeneralString:
1820 case BER_UNI_TAG_UTCTime:
1821 case BER_UNI_TAG_GeneralizedTime:
1822 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1823 asn1_close(&asn1, &offset); /* mark where we are */
1827 case BER_UNI_TAG_BITSTRING:
1828 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1829 asn1_close(&asn1, &offset); /* mark where we are */
1833 case BER_UNI_TAG_SET:
1834 case BER_UNI_TAG_SEQUENCE:
1835 if (len == 0) /* don't recurse if offset isn't going to change */
1838 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1841 case BER_UNI_TAG_EOC:
1844 case BER_UNI_TAG_OID:
1845 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1846 asn1_close(&asn1, &offset); /* mark where we are */
1850 case BER_UNI_TAG_NULL:
1854 case BER_UNI_TAG_ObjectDescriptor:
1856 case BER_UNI_TAG_REAL:
1857 case BER_UNI_TAG_VideotexString:
1858 case BER_UNI_TAG_GraphicString:
1859 case BER_UNI_TAG_VisibleString:
1862 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1863 offset += len; /* skip value ... */
1868 case BER_CLASS_CON: /* fprintf(stderr, "Context\n"); */
1870 g_snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
1872 /* defined length, not constructed, must be a string.... */
1873 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1874 asn1_close(&asn1, &offset); /* mark where we are */
1877 /* indefinite length or constructed.... must be a sequence .... */
1878 if (len == 0) /* don't recurse if offset isn't going to change */
1881 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1885 default: /* fprintf(stderr, "Other\n"); */
1886 if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1887 offset += len; /* skip value ... */
1894 static void showGNodes(GNode *p, int n);
1898 myLeaf(GNode *node, gpointer data)
1901 guint ret, cls, con, tag, def, len;
1902 char *clsstr, *constr, *tagstr;
1906 (void) data; /* make a reference */
1907 asn1_open(&asn1, asn1_desc, (int)node->data);
1909 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1911 clsstr = asn1_cls[cls];
1912 constr = asn1_con[con];
1913 if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
1914 tagstr = asn1_tag[tag];
1916 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1920 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1922 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1926 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1934 if (asn1_verbose) g_message("build GNode tree:");
1935 showGNodes(g_node_first_child(asn1_nodes), 0);
1936 if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1937 g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1938 g_node_max_height (asn1_nodes),
1939 g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1940 g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1942 g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1948 tt_build_tree(void) /* build a GNode tree with all offset's to ASN.1 entities */
1951 g_node_destroy(asn1_nodes);
1952 asn1_nodes = g_node_new(0);
1954 parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1958 /*****************************************************************************************************/
1960 static guint anonCount; /* for naming anonymous types */
1962 typedef struct _TBLModule TBLModule;
1963 typedef struct _TBLTypeDef TBLTypeDef;
1964 typedef struct _TBLTag TBLTag;
1965 typedef struct _TBLType TBLType;
1966 typedef struct _TBLTypeRef TBLTypeRef;
1967 typedef struct _TBLNamedNumber TBLNamedNumber;
1968 typedef struct _TBLRange TBLRange;
1976 TBLTYPE_NamedNumber,
1979 typedef enum _tbl_t tbl_t;
1980 /* text for 'tbl_t' type for debugging */
1981 static const char *data_types[] = {
1991 enum _TBLTypeContent_t {
1993 TBLTYPETYPE_Primitive,
1994 TBLTYPETYPE_Elements,
1997 typedef enum _TBLTypeContent_t TBLTypeContent_t;
1999 struct _TBLNamedNumber {
2011 struct _TBLTypeRef {
2027 TBLTypeContent_t content;
2030 gboolean constraint;
2033 struct _TBLTypeDef {
2048 guint totalNumModules;
2049 guint totalNumTypeDefs;
2050 guint totalNumTypes;
2052 guint totalNumStrings;
2053 guint totalLenStrings;
2056 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2059 get_asn1_int(guint want_tag, guint offset)
2062 guint ret, cls, con, tag, len;
2066 /* g_message("%d get_asn1_int", offset); */
2068 asn1_open(&asn1, asn1_desc, offset);
2070 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2071 if (ret == ASN1_ERR_NOERROR) {
2072 /* do not check class, both Unversal and Context are OK */
2073 if (con == ASN1_PRI && tag == want_tag) {
2075 asn1_uint32_value_decode(&asn1, len, &value);
2078 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2080 ret = ASN1_ERR_WRONG_TYPE;
2082 g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2087 static subid_t * /* with prepended length ..... */
2088 get_asn1_oid(guint want_tag, guint offset)
2091 guint ret, cls, con, tag, len;
2095 /* g_message("%d get_asn1_oid", offset); */
2097 asn1_open(&asn1, asn1_desc, offset);
2099 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2100 if (ret == ASN1_ERR_NOERROR) {
2101 /* do not check class, both Unversal and Context are OK */
2102 if ((con == ASN1_PRI) && (tag == want_tag)) {
2104 asn1_oid_value_decode(&asn1, len, &oid, &con);
2105 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2106 memmove(&oid[1], oid, con*sizeof(guint));
2110 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2112 ret = ASN1_ERR_WRONG_TYPE;
2114 g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2119 static guchar * /* 0 terminated string */
2120 get_asn1_string(guint want_tag, guint offset)
2123 guint ret, cls, con, tag, len;
2127 /* g_message("%d get_asn1_string", offset); */
2129 asn1_open(&asn1, asn1_desc, offset);
2131 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2132 if (ret == ASN1_ERR_NOERROR) {
2133 /* do not check class, both Unversal and Context are OK */
2134 if ((con == ASN1_PRI) && (tag == want_tag)) {
2136 asn1_string_value_decode(&asn1, len, &octets);
2137 octets = g_realloc(octets, len+1); /* need space for sentinel */
2141 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2143 ret = ASN1_ERR_WRONG_TYPE;
2145 g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2151 get_asn1_uint(guint offset)
2154 guint ret, len, value;
2156 /* g_message( "%d get_asn1_uint", offset); */
2158 asn1_open(&asn1, asn1_desc, offset);
2160 ret = asn1_uint32_decode(&asn1, &value, &len);
2162 if (ret != ASN1_ERR_NOERROR) {
2163 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2170 check_tag(guint want_tag, guint offset)
2173 guint ret, cls, con, tag, len;
2176 asn1_open(&asn1, asn1_desc, offset);
2178 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2179 if (ret == ASN1_ERR_NOERROR) {
2180 ret = (tag == want_tag) ? TRUE : FALSE;
2181 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2184 g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2191 constructed(guint offset)
2194 guint ret, cls, con, tag, def, len;
2196 /* g_message("%d constructed?", offset); */
2198 asn1_open(&asn1, asn1_desc, offset);
2200 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2201 if (ret == ASN1_ERR_NOERROR) {
2207 /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2214 define_constraint(GNode *p, GNode *q)
2216 TBLRange *range = g_malloc(sizeof(TBLRange));
2217 g_node_append_data(q, range);
2219 range->type = TBLTYPE_Range;
2221 /* g_message("define_constraint %p, %p", p, q); */
2223 p = g_node_first_child(p);
2229 range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2230 p = g_node_next_sibling(p);
2236 range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2241 define_namednumber(GNode *p, GNode *q)
2243 TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2244 g_node_append_data(q, num);
2246 num->type = TBLTYPE_NamedNumber;
2248 /* g_message("define_namednumber %p, %p", p, q); */
2250 p = g_node_first_child(p);
2256 num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2257 p = g_node_next_sibling(p);
2263 num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2267 define_typeref(GNode *p, GNode *q)
2269 TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2270 g_node_append_data(q, ref);
2272 ref->type = TBLTYPE_TypeRef;
2274 /* g_message("define_typeref %p, %p", p, q); */
2276 p = g_node_first_child(p);
2282 ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2283 p = g_node_next_sibling(p);
2289 ref->implicit = get_asn1_int(BER_UNI_TAG_BOOLEAN, GPOINTER_TO_UINT(p->data));
2293 define_tag(GNode *p, GNode *q)
2295 TBLTag *type = g_malloc(sizeof(TBLTag));
2296 g_node_append_data(q, type);
2298 type->type = TBLTYPE_Tag;
2300 /* g_message("define_tag %p, %p", p, q); */
2302 p = g_node_first_child(p);
2308 type->tclass = get_asn1_int(BER_UNI_TAG_ENUMERATED, GPOINTER_TO_UINT(p->data));
2309 p = g_node_next_sibling(p);
2315 type->code = get_asn1_int(BER_UNI_TAG_INTEGER, GPOINTER_TO_UINT(p->data));
2320 define_type(GNode *p, GNode *q)
2323 TBLType *type = g_malloc(sizeof(TBLType));
2325 GNode *t = g_node_append_data(q, type);
2327 type->type = TBLTYPE_Type;
2329 /* g_message("define_type %p, %p", p, q); */
2331 type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2332 p = g_node_next_sibling(p);
2334 type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2335 p = g_node_next_sibling(p);
2337 if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
2338 r = g_node_first_child(p);
2341 r = g_node_next_sibling(r);
2343 p = g_node_next_sibling(p);
2346 if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
2347 g_warning("expect tag 3, ERROR");
2349 r = g_node_first_child(p);
2351 type->content = TBLTYPETYPE_None;
2352 if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
2353 if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
2354 if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
2355 switch(type->content) {
2356 case TBLTYPETYPE_Primitive:
2358 case TBLTYPETYPE_Elements:
2359 r = g_node_first_child(r);
2361 define_type(g_node_first_child(r), t);
2362 r = g_node_next_sibling(r);
2365 case TBLTYPETYPE_TypeRef:
2366 define_typeref(r, t);
2368 case TBLTYPETYPE_None:
2369 g_warning("expected a contents choice, error");
2372 p = g_node_next_sibling(p);
2374 type->fieldName = 0;
2375 type->anonymous = FALSE;
2376 if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
2377 type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
2378 p = g_node_next_sibling(p);
2380 type->anonymous = TRUE;
2383 type->constraint = FALSE;
2384 if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
2385 type->constraint = TRUE;
2386 define_constraint(p, t);
2387 p = g_node_next_sibling(p);
2390 if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
2391 r = g_node_first_child(p);
2393 define_namednumber(r, t);
2394 r = g_node_next_sibling(r);
2400 define_typedef(GNode *p, GNode *q)
2402 TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2404 GNode *t = g_node_append_data(q, type_def);
2406 /* g_message("define_typedef %p, %p", p, q); */
2408 type_def->type = TBLTYPE_TypeDef;
2410 p = g_node_first_child(p);
2416 type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2417 p = g_node_next_sibling(p);
2423 type_def->typeName = get_asn1_string(BER_UNI_TAG_PrintableString, GPOINTER_TO_UINT(p->data));
2424 p = g_node_next_sibling(p);
2430 define_type(g_node_first_child(p), t);
2431 p = g_node_next_sibling(p);
2433 type_def->isPdu = (p != 0); /* true if it exists, value ignored */
2437 define_module(GNode *p, GNode *q)
2439 TBLModule *module = g_malloc(sizeof(TBLModule));
2441 GNode *m = g_node_append_data(q, module);
2443 /* g_message("define_module %p %p", p, q); */
2445 module->type = TBLTYPE_Module;
2447 p = g_node_first_child(p);
2449 module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2450 p = g_node_next_sibling(p);
2453 if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */
2454 module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
2455 p = g_node_next_sibling(p);
2458 module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
2459 p = g_node_next_sibling(p);
2461 p = g_node_first_child(p);
2463 define_typedef(p, m);
2464 p = g_node_next_sibling(p);
2468 typedef struct _SearchDef SearchDef;
2475 is_typedef(GNode *node, gpointer data)
2477 TBLTypeDef *d = (TBLTypeDef *)node->data;
2478 SearchDef *s = (SearchDef *)data;
2480 if (d == 0) return FALSE;
2481 if (d->type != TBLTYPE_TypeDef) return FALSE;
2482 if (strcmp(s->key, d->typeName) == 0) {
2489 typedef struct _TypeRef TypeRef;
2495 GNode *pdu; /* location in PDU descriptor tree */
2496 guint level; /* recursion counter */
2498 GPtrArray *refs; /* pointers to PDUinfo structures teferencing this entry */
2501 typedef struct _NameDefs NameDefs;
2507 #define ALLOC_INCR 4
2508 #define CLASSREF (BER_CLASS_PRI+1)
2511 is_named(GNode *node, gpointer data)
2513 TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2514 NameDefs *n = (NameDefs *)data;
2517 if (num == 0) return FALSE;
2518 if (num->type != TBLTYPE_NamedNumber) return FALSE;
2520 if (num->value >= n->max) { /* need larger array */
2522 n->max = num->value + ALLOC_INCR;
2523 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2524 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2526 if (num->value > n->used) /* track max used value, there may be holes... */
2527 n->used = num->value;
2529 n->info[num->value].name = num->name;
2535 index_typedef(GNode *node, gpointer data)
2537 TBLTypeDef *d = (TBLTypeDef *)node->data;
2538 NameDefs *n = (NameDefs *)data;
2543 if (d == 0) return FALSE;
2544 if (d->type != TBLTYPE_TypeDef) return FALSE;
2546 if (d->typeDefId >= n->max) { /* need larger array */
2548 n->max = d->typeDefId + ALLOC_INCR;
2549 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2550 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2552 if (d->typeDefId > n->used) /* track max used value, there may be holes... */
2553 n->used = d->typeDefId;
2555 t = &(n->info[d->typeDefId]);
2556 t->name = d->typeName;
2558 t->refs = g_ptr_array_new(); /* collect references here */
2559 node = g_node_first_child(node); /* the real type */
2560 tag = (TBLTag *)node->data;
2561 if ((tag->type == TBLTYPE_Type) && (((TBLType *)tag)->typeId == TBL_CHOICE)) {
2562 /* no reasonable default... ! */
2563 t->defclass = 3; /* Private .... */
2564 t->deftag= 9999; /* a random value */
2566 node = g_node_first_child(node); /* the default tag */
2567 tag = (TBLTag *)node->data;
2570 t->defclass = tag->tclass;
2571 t->deftag = tag->code;
2573 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2574 t->defclass = CLASSREF; /* invalid class.. */
2575 t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2578 g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2579 data_types[tag->type]);
2580 t->defclass = 3; /* Private .... */
2581 t->deftag= 9998; /* another random value */
2589 static TypeRef *typeDef_names = 0;
2590 static guint numTypedefs = 0;
2593 free_node_data(GNode *node, gpointer data _U_)
2600 get_values(void) /* collect values from ASN.1 tree */
2601 /* coded according to the tbl.asn1 description of snacc output */
2602 { /* This routine does not leave references to the tvbuff or */
2603 /* to the asn1_nodes, both can be freed by the caller of this.*/
2609 const char *t, *s, *E;
2610 static char missing[] = " **missing** ";
2612 if (asn1_verbose) g_message("interpreting tree");
2613 typeDef_names = 0; /* just forget allocated any data .... */
2616 g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2617 free_node_data, NULL);
2618 g_node_destroy(data_nodes);
2621 data_nodes = g_node_new(0);
2623 p = g_node_first_child(asn1_nodes); /* top of the data tree */
2625 p = g_node_first_child(p);
2626 TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2627 p = g_node_next_sibling(p);
2628 TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2629 p = g_node_next_sibling(p);
2630 TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2631 p = g_node_next_sibling(p);
2632 TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2633 p = g_node_next_sibling(p);
2634 TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2635 p = g_node_next_sibling(p);
2636 TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2637 p = g_node_next_sibling(p);
2639 p = g_node_first_child(p);
2641 define_module(p, data_nodes);
2642 p = g_node_next_sibling(p);
2645 /* g_message("finished with tree"); */
2647 if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2648 sd.key = "TBLTypeId";
2650 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2651 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", (void *)sd.here);
2655 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2656 g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2658 if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, (void *)nd.info);
2660 for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2663 s = nd.info[i].name;
2664 if (s == 0) s = missing;
2665 if (g_strcmp(t, s) == 0) { /* OK ! */
2669 E = ", X with errors X";
2671 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2673 if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2675 tbl_types_verified = TRUE;
2677 /* build table with typedef names */
2680 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2681 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2682 if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, (void *)nd.info);
2684 for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2685 TypeRef *ref = &(nd.info[i]);
2688 t = ref->name = missing;
2689 if (asn1_verbose) g_message(" %3d %s", i, t);
2691 if (asn1_verbose) g_message(" %3d %s, %c%d", i, t,
2692 tag_class[ref->defclass], ref->deftag);
2694 if (ref->pdu) { /* should be 0 */
2695 if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, (void *)ref->pdu);
2698 typeDef_names = nd.info;
2700 if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
2705 showGNode(GNode *p, int n)
2708 const char *fn, *s = empty;
2710 n *=2; /* 2 spaces per level */
2711 if (p->data) { /* show value ... */
2712 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
2713 switch (((TBLTag *)p->data)->type) {
2714 case TBLTYPE_Module: {
2715 TBLModule *m = (TBLModule *)p->data;
2717 g_message("%*smodule %s%s", n, empty, m->name,
2718 m->isUseful ? ", useful" : empty);
2721 case TBLTYPE_TypeDef: {
2722 TBLTypeDef *t = (TBLTypeDef *)p->data;
2724 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
2725 t->isPdu ? ", isPDU" : empty);
2728 case TBLTYPE_Type: {
2729 TBLType *t = (TBLType *)p->data;
2732 /* typeId is a value from enum TBLTypeId */
2733 fn = TBLTYPE(t->typeId);
2734 if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
2735 t->optional ? " opt" : empty, s );
2739 TBLTag *t = (TBLTag *)p->data;
2740 if ((t->tclass == BER_CLASS_UNI) && (t->code < 32))
2741 s = asn1_tag[t->code];
2742 if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
2743 tag_class[t->tclass], t->code, s);
2746 case TBLTYPE_NamedNumber: {
2747 TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
2748 if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
2749 nn->value, nn->name);
2752 case TBLTYPE_Range: {
2753 TBLRange *r = (TBLRange *)p->data;
2754 if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
2758 case TBLTYPE_TypeRef: {
2759 TBLTypeRef *r = (TBLTypeRef *)p->data;
2761 s = typeDef_names[r->typeDefId].name;
2762 if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
2763 r->typeDefId, s, r->implicit ? ", implicit" : empty );
2767 TBLTag *x = (TBLTag *)p->data;
2768 if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
2772 } else { /* just show tree */
2774 g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
2775 n, empty, (void *)p, (void *)p->data, (void *)p->next, (void *)p->prev, (void *)p->parent, (void *)p->children);
2780 showGNodes(GNode *p, int n)
2784 showGNodes(p->children, n+1);
2785 showGNodes(p->next, n);
2789 static void showGenv(GNode *p, int n, int m)
2795 if (asn1_verbose) g_message("%*s.....", n*2, empty);
2799 for(i=0; p && (i < 3); p = p->next, i++) {
2801 showGenv(p->children, n+1, m);
2803 if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
2809 debug_dump_TT(void) /* dump contents of TT struct, for debugging */
2812 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
2814 TT.totalNumTypeDefs,
2818 TT.totalLenStrings);
2822 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
2823 const gchar *message, gpointer user_data)
2825 static FILE* logf = 0;
2826 static char eol[] = "\r\n";
2828 (void) log_domain; (void) log_level; (void) user_data; /* make references */
2830 if (logf == NULL && asn1_logfile) {
2831 logf = ws_fopen(asn1_logfile, "w");
2834 fputs(message, logf);
2836 fflush(logf); /* debugging ... */
2841 read_asn1_type_table(const char *filename)
2847 static guint mylogh = 0;
2849 if ((filename == 0) || (strlen(filename) == 0))
2850 return; /* no filename provided */
2852 f = ws_fopen(filename, "rb");
2855 * Ignore "file not found" errors if it's the old default
2856 * ASN.1 file name, as we never shipped such a file.
2857 * Also, on Win32, ignore the earlier default, which
2858 * had a "/" rather than a "\" as the last pathname
2862 if (strcmp(filename, bad_separator_old_default_asn1_filename) != 0)
2864 if ((strcmp(filename, old_default_asn1_filename) != 0) || errno != ENOENT)
2865 report_open_failure(filename, errno, FALSE);
2868 fstat(fileno(f), &stat);
2869 size = (int)stat.st_size;
2871 if (asn1_verbose) g_message("file %s is empty, ignored", filename);
2875 if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
2877 data = g_malloc(size);
2878 if (fread(data, size, 1, f) < 1) {
2879 g_warning("error reading %s, %s", filename, strerror(errno));
2884 /* ***** from the time when logging was just in a console... *****
2885 * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
2886 * " Sleep 5 sec...");
2891 g_message("logging to file %s", asn1_logfile);
2894 mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2895 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
2899 asn1_desc = tvb_new_real_data(data, size, size);
2902 if (asn1_verbose) g_message("read %d items from %s", icount, filename);
2910 g_node_destroy(asn1_nodes); asn1_nodes = 0;
2911 #ifndef _WIN32 /* tvb_free not yet exported to plugins... */
2912 tvb_free(asn1_desc);
2915 g_free(data); data = 0;
2917 showGNodes(data_nodes, 0);
2923 /* XXX - Shoudn't we make sure we're not dereferencing a NULL pointer here? */
2924 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
2925 g_warning("**** unexpected type %s, want %s, at line %d", \
2926 data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
2930 save_reference(PDUinfo *p)
2937 g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
2941 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex);
2945 /* evaluate typeref, pointer to current pdu node and typedef */
2947 tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
2950 PDUinfo *p = (PDUinfo *)pdu->data, *p1;
2956 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
2957 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
2961 CHECKTYPE(tree, TBLTYPE_TypeDef);
2963 if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
2964 p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2966 p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
2967 p->flags |= PDU_TYPEDEF;
2969 tree = g_node_first_child(tree); /* move to its underlying type */
2970 CHECKTYPE(tree, TBLTYPE_Type);
2971 p->type = ((TBLType *)tree->data)->typeId;
2973 q = g_node_first_child(tree); /* the tag of this type entry ... is optional... */
2974 if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
2975 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
2979 /* XXX -- hack -- hack -- hack -- hack -- hack --
2980 * only change tag when class+tag == EOC,
2981 * or class is a reference,
2982 * or new class is not universal.
2984 if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
2985 (((TBLTag *)q->data)->tclass != BER_CLASS_UNI) ) {
2986 p->tclass = ((TBLTag *)q->data)->tclass;
2987 p->tag = ((TBLTag *)q->data)->code;
2989 g_message("%*s*change typeref tag from %c%d to %c%d",
2993 tag_class[p->tclass],
2997 g_message("%*sNOT changing tag from %c%d to %c%d",
3001 tag_class[((TBLTag *)q->data)->tclass],
3002 ((TBLTag *)q->data)->code);
3009 if (p->tclass==CLASSREF)
3010 g_snprintf(ss, 128, ", CLASSREF %d", p->tag);
3011 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
3013 if (p->tclass==CLASSREF) {
3016 /* CLASSREF....., get it defined using type of the reference */
3018 /* p->basetype may be -1 .... ? XXX */
3021 tr = &typeDef_names[i];
3023 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
3024 p->tag, tr->name, (void *)tr->pdu);
3026 tbl_typeref(n+1, pdu, tr->type, fullindex);
3033 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
3034 p->name, p->typename, (void *)p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
3038 case TBL_ENUMERATED:
3039 /* names do not have a fullname */
3040 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
3041 /* read the enumeration [save min-max somewhere ?] */
3042 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type]; /* XXX change field type... */
3044 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3049 g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3050 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3051 p->name, p->fullname,
3052 tbl_types_wireshark_txt[p->type], p->value_id);
3055 while((q = g_node_next_sibling(q))) {
3056 CHECKTYPE(q, TBLTYPE_NamedNumber);
3057 p = g_malloc0(sizeof(PDUinfo));
3059 p->type = TBL_ENUMERATED;
3060 p->name = (((TBLNamedNumber *)q->data)->name);
3061 p->tag = (((TBLNamedNumber *)q->data)->value);
3062 p->flags = PDU_NAMEDNUM;
3063 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3064 g_node_append_data(pdu, p);
3067 /* list all enum values in the field structure for matching */
3068 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3069 q = g_node_first_child(pdu);
3072 p = (PDUinfo *)q->data;
3073 v[nvals].value = p->tag;
3074 v[nvals].strptr = p->name;
3075 /* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
3077 q = g_node_next_sibling(q);
3079 /* last entry is already initialized to { 0, NULL } */
3084 if (p->value_id == -1) { /* not yet registered ..... */
3085 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3086 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3091 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3092 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3093 p->name, p->fullname,
3094 tbl_types_wireshark_txt[p->type], p->value_id);
3096 tbl_type(n, pdu, q, fullindex);
3100 if (p->value_id == -1) { /* not yet registered ..... */
3101 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3102 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3107 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3108 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3109 p->name, p->fullname,
3110 tbl_types_wireshark_txt[p->type], p->value_id);
3112 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
3117 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
3125 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
3126 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3130 /* showGenv(list, n, n+1); */
3133 pdu1 = pdu; /* save start location for append */
3134 while (list) { /* handle all entries */
3136 g_message("%*s+handle a %s, list=%p", n*2, empty,
3137 data_types[((TBLTag *)list->data)->type], (void *)list);
3139 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
3140 list = g_node_next_sibling(list);
3141 if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
3146 /******* change to positive comparation, but leave comment for reference
3147 * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3148 * CHECKTYPE(list, TBLTYPE_Type);
3151 if (((TBLTag *)list->data)->type == TBLTYPE_Type) {
3152 CHECKTYPE(list, TBLTYPE_Type);
3154 p = g_malloc0(sizeof(PDUinfo));
3155 pdu = g_node_append_data(pdu1, p);
3157 p->type = ((TBLType *)list->data)->typeId;
3158 p->typename = tbl_types_asn1[p->type]; /* the default type */
3161 p->basetype = ((PDUinfo *)pdu1->data)->typenum;
3162 p->flags = PDUinfo_initflags;
3163 p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
3164 p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
3166 if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
3167 /* assign an anonymous name [XXX refer to parent typename...] */
3168 ((TBLType *)list->data)->fieldName =
3169 g_strdup_printf("anon%d", anonCount++);
3171 p->name = ((TBLType *)list->data)->fieldName;
3174 ni += g_snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
3175 p->fullname = g_strdup(fieldname);
3177 /* initialize field info */
3180 p->value_hf.p_id = &(p->value_id);
3181 p->value_hf.hfinfo.name = p->fullname;
3182 p->value_hf.hfinfo.abbrev = p->fullname;
3183 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3184 p->value_hf.hfinfo.display = BASE_DEC;
3185 p->value_hf.hfinfo.blurb = p->fullname;
3186 /* all the other fields are already 0 ! */
3188 if (p->type < TBL__SIMPLE) {
3189 /* only register fields with a value here, postpone others */
3190 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3195 g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3196 p->mytype, p->typenum, p->basetype, p->flags,
3197 p->typename, p->name, p->fullname,
3198 tbl_types_wireshark_txt[p->type], p->value_id);
3201 q = g_node_first_child(list);
3203 p = (PDUinfo *)pdu->data;
3208 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
3213 case TBL_OCTETSTRING:
3217 CHECKTYPE(q, TBLTYPE_Tag);
3218 p->tclass = ((TBLTag *)q->data)->tclass;
3219 p->tag = ((TBLTag *)q->data)->code;
3223 case TBL_ENUMERATED:
3224 CHECKTYPE(q, TBLTYPE_Tag);
3225 p->tclass = ((TBLTag *)q->data)->tclass;
3226 p->tag = ((TBLTag *)q->data)->code;
3227 if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
3228 /* read the enumeration [save min-max somewhere ?] */
3231 while((q = g_node_next_sibling(q))) {
3232 CHECKTYPE(q, TBLTYPE_NamedNumber);
3233 p = g_malloc0(sizeof(PDUinfo));
3235 p->type = TBL_ENUMERATED;
3236 p->name = (gchar *)(((TBLNamedNumber *)q->data)->name);
3237 p->tag = (((TBLNamedNumber *)q->data)->value);
3238 p->flags = PDU_NAMEDNUM;
3239 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3240 g_node_append_data(pdu, p);
3243 /* list all enum values in the field structure for matching */
3244 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3245 q = g_node_first_child(pdu);
3248 p = (PDUinfo *)q->data;
3249 v[nvals].value = p->tag;
3250 v[nvals].strptr = p->name;
3251 /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3253 q = g_node_next_sibling(q);
3255 /* last entry is already initialized to { 0, NULL } */
3261 case TBL_SEQUENCEOF:
3264 CHECKTYPE(q, TBLTYPE_Tag);
3265 q = g_node_first_child(list);
3266 tbl_type(n+1, pdu, q, ni);
3269 case TBL_TYPEREF: { /* may have a tag ... */
3275 if ( ((TBLTag *)q->data)->type == TBLTYPE_Tag) {
3276 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3277 p->tclass = ((TBLTag *)q->data)->tclass;
3278 p->tag = ((TBLTag *)q->data)->code;
3280 g_message("%*s*insert type tag %c%d", n*2, empty,
3281 tag_class[p->tclass], p->tag);
3283 q = g_node_next_sibling(q);
3284 } else { /* use default tag for this type */
3285 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3286 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != BER_CLASS_UNI)) ||
3287 ((p->tclass | p->tag) == 0 )) {
3288 /* not implicit, use this tag */
3289 p->tclass = tr->defclass;
3290 p->tag = tr->deftag;
3291 if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3292 tag_class[p->tclass], p->tag);
3295 CHECKTYPE(q, TBLTYPE_TypeRef);
3296 i = ((TBLTypeRef *)q->data)->typeDefId;
3298 tr = &typeDef_names[i];
3300 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, (void *)tr->pdu);
3301 p->typename = tr->name;
3303 if (tr->defclass == CLASSREF) {
3305 tr->pdu = pdu; /* remember this reference */
3307 tr = &typeDef_names[i];
3309 g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3310 i, tr->name, (void *)tr->pdu);
3312 /* evaluate reference if not done before or when below recursion limit */
3313 if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3316 tr->pdu = pdu; /* save for references we leave */
3318 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3320 g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3322 ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3325 tbl_typeref(n+1, pdu, tr->type, ni);
3329 g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3330 p->name, tr->name, (void *)tr->pdu);
3331 p->flags |= PDU_REFERENCE;
3332 p->reference = tr->pdu;
3337 g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3342 g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3343 n*2, empty, p->name, p->typename, (void *)p, TBLTYPE(p->type),
3344 tag_class[p->tclass], p->tag);
3346 if (p->value_id == -1) { /* not registered before, do it now */
3347 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3352 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3353 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3354 p->name, p->fullname,
3355 tbl_types_wireshark_txt[p->type], p->value_id);
3357 list = g_node_next_sibling(list);
3362 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
3365 const char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3368 tt = TBLTYPE(info->type);
3370 tn = info->typename;
3371 fn = info->fullname;
3372 if (info->flags & PDU_NAMEDNUM)
3373 txt += g_sprintf(txt, "name: %2d %s", info->tag, nn);
3375 if (info->flags & PDU_TYPEDEF)
3376 txt += g_sprintf(txt, "def %d: ", info->typenum);
3378 txt += g_sprintf(txt, " ");
3379 ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3380 txt += g_sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3381 tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3382 txt += g_sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
3383 oo = (info->flags & PDU_OPTIONAL) ? ", optional" : empty;
3384 ii = (info->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3385 nn = (info->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3386 an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3387 txt += g_sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
3388 if (info->flags & PDU_REFERENCE) {
3389 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3390 tt = TBLTYPE(rinfo->type);
3392 tn = rinfo->typename;
3393 fn = rinfo->fullname;
3394 txt += g_sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3395 if (rinfo->flags & PDU_TYPEDEF)
3396 txt += g_sprintf(txt, " T%d", rinfo->typenum);
3397 txt += g_sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3398 oo = (rinfo->flags & PDU_OPTIONAL) ? ", optional" : empty;
3399 ii = (rinfo->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3400 nn = (rinfo->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3401 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3402 tt = (rinfo->flags & PDU_TYPEDEF) ? ", typedef" : empty;
3403 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3404 tr = (rinfo->flags & PDU_TYPETREE) ? ", typetree" : empty;
3405 txt += g_sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3409 strncpy(txt, "no info available", 20);
3417 showPDUtree(GNode *p, int n)
3423 info = (PDUinfo *)p->data;
3425 PDUtext(text, info);
3427 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3429 showPDUtree(g_node_first_child(p), n+1);
3431 p = g_node_next_sibling(p);
3438 build_pdu_tree(const char *pduname)
3441 guint pdudef, i, tcount;
3450 if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3453 if (asn1_verbose) g_message("no data nodes");
3458 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3460 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3461 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, (void *)sd.here, pdudef);
3463 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3467 /* If there's an existing PDU tree, free it */
3469 g_node_traverse(PDUtree, G_POST_ORDER, G_TRAVERSE_ALL, -1,
3470 free_node_data, NULL);
3471 g_node_destroy(PDUtree);
3474 /* initialize the PDU tree, hand craft the root entry */
3476 info = g_malloc0(sizeof(PDUinfo));
3477 info->name = pduname;
3478 info->typename = pduname;
3479 info->type = TBL_SEQUENCEOF;
3480 info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3481 info->flags = PDUinfo_initflags = 0;
3482 info->value_id = -1;
3484 info->basetype = -1;
3485 info->mytype = pdudef;
3487 info->value_hf.p_id = &(info->value_id);
3488 info->value_hf.hfinfo.name = info->fullname;
3489 info->value_hf.hfinfo.abbrev = info->fullname;
3490 info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3491 info->value_hf.hfinfo.display = BASE_DEC;
3492 info->value_hf.hfinfo.blurb = info->fullname;
3494 anonCount = 0; /* anonymous types counter */
3496 PDUtree = g_node_new(info);
3497 pabbrev_pdu_len = g_sprintf(fieldname, "%s.%s.", pabbrev, pduname);
3498 sav_len = pabbrev_pdu_len;
3500 /* Now build the tree for this top level PDU */
3502 g_message("******** Define main type %d, %s", pdudef, pduname);
3503 tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1); /* strip initial . for new names */
3506 g_message("%d anonymous types", anonCount);
3508 /* Now make all types used available for matching */
3510 g_message("Define the types that are actually referenced through the top level PDU");
3511 for (i=0, tcount=0; i<numTypedefs; i++) {
3512 tr = &(typeDef_names[i]);
3514 if (tr->pdu) { /* ignore if not used in main pdu */
3517 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3519 g_message("******** Define type %d, %s", i, tr->name);
3521 /* .... do definition ..... */
3522 info = g_malloc0(sizeof(PDUinfo));
3523 info->name = tr->name;
3524 info->typename = tr->name;
3525 info->tclass = tr->defclass;
3526 info->tag = tr->deftag;
3527 info->type = TBL_TYPEREF;
3528 info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3529 info->flags = PDUinfo_initflags = PDU_TYPETREE;
3530 info->value_id = -1;
3532 info->basetype = -1;
3535 info->value_hf.p_id = &(info->value_id);
3536 info->value_hf.hfinfo.name = info->fullname;
3537 info->value_hf.hfinfo.abbrev = info->fullname;
3538 info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3539 info->value_hf.hfinfo.display = BASE_DEC;
3540 info->value_hf.hfinfo.blurb = info->fullname;
3542 tr->typetree = g_node_new(info);
3543 pabbrev_pdu_len = g_sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
3544 tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3548 g_message("%d types used", tcount);
3550 pabbrev_pdu_len = sav_len;
3552 /* and show the result */
3554 g_message("Type index:");
3555 for (i=0; i<numTypedefs; i++) {
3556 tr = &(typeDef_names[i]);
3558 if (tr->pdu == 0) /* skip if not used */
3562 g_message(" %3d %s, %c%d, refs: %d",
3563 i, tr->name, tag_class[tr->defclass], tr->deftag,
3564 g_ptr_array_len(tr->refs));
3566 /* get defining node for this type */
3569 p = (PDUinfo *)(tr->typetree->data);
3570 defid = p->value_id;
3572 g_message(" -- defining id=%d", defid);
3574 for(j=0; j < g_ptr_array_len(tr->refs); j++) { /* show refs, and set type_id */
3575 p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3576 if (p->mytype == (gint)i)
3577 p->type_id = defid; /* normal reference */
3579 if ((p->flags & PDU_TYPETREE) == 0) {
3580 /* we have a primitive value, find its real type */
3581 for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3582 /* look at all refs */
3583 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3584 if ((q->flags & PDU_TYPETREE) == 0)
3585 continue; /* only type trees are interresting */
3586 if (q->type != p->type)
3587 continue; /* must be same types */
3588 if (strcmp(q->name, p->name) == 0) {
3589 /* OK, take the first we find, not entirely
3590 * correct, it may be from a different
3591 * base-base type...... XXX */
3592 p->type_id = q->value_id;
3601 g_message(" %s", text);
3607 g_message("The resulting PDU tree:");
3608 showPDUtree(PDUtree, 0);
3614 #ifdef DISSECTOR_WITH_GUI
3615 /* This cannot work in tshark.... don't include for now */
3617 #endif /* DISSECTOR_WITH_GUI */
3620 static GtkWidget *window = NULL;
3622 /* the columns in the tree view */
3625 TITLE_COLUMN, /* text in this row */
3626 DEF_COLUMN, /* definition in this row, if any */
3627 REF_COLUMN, /* referennce from this column, if any */
3628 VALUE_COLUMN, /* indicate this is a value */
3629 NAME_COLUMN, /* name of this row */
3633 static FILE *namelist = 0;
3636 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3639 PDUinfo *info, *rinfo;
3646 info = (PDUinfo *)p->data;
3648 gtk_tree_store_append (store, &iter2, iter); /* Acquire iterator */
3650 PDUtext(text, info);
3653 if (info->flags & PDU_TYPEDEF)
3654 def = info->typenum;
3656 if (info->flags & PDU_REFERENCE) {
3657 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3658 ref = rinfo->typenum;
3660 pb = GTK_STOCK_CANCEL;
3661 if (G_NODE_IS_LEAF(p)) {
3662 if (info->flags & PDU_NAMEDNUM)
3663 pb = GTK_STOCK_BOLD;
3667 fprintf(namelist, "%16s %s\n",
3668 &(TBLTYPE(info->type)[4]), info->fullname);
3671 switch (info->type) {
3672 case TBL_ENUMERATED:
3676 fprintf(namelist, "%16s %s\n",
3677 &(TBLTYPE(info->type)[4]), info->fullname);
3684 gtk_tree_store_set (store, &iter2,
3689 NAME_COLUMN, info->fullname,
3692 build_tree_view(store, g_node_first_child(p), &iter2);
3694 p = g_node_next_sibling(p);
3706 #define PATHSTACKMAX 10
3707 static GtkTreePath *pathstack[PATHSTACKMAX];
3708 static gint pathstackp = 0;
3710 static void add_path(GtkTreePath *p)
3712 if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
3713 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
3714 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
3717 pathstack[pathstackp++] = p;
3720 static GtkTreePath *pop_path(void)
3723 return pathstack[--pathstackp];
3728 find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
3732 struct DefFind *df = (struct DefFind *)data;
3734 gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
3736 if (def == df->def) {
3737 df->path = gtk_tree_path_copy (path);
3745 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
3748 GtkTreePath *path, *path2;
3749 gchar *text, *oldpath, *newpath;
3755 path = gtk_tree_path_copy (spath);
3757 gtk_tree_model_get_iter (model, &iter, path);
3758 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
3760 oldpath = gtk_tree_path_to_string(path);
3761 path2 = gtk_tree_path_copy (path);
3763 add_path(gtk_tree_path_copy(path));
3765 if (ref != -1) { /* this is a reference, find matching definition */
3768 gtk_tree_model_foreach (model, find_definition, &df);
3770 gtk_tree_path_free(path);
3773 } else { /* just move to the next entry, if it exists */
3774 gtk_tree_path_next(path2);
3776 if (gtk_tree_model_get_iter (model, &iter, path2)) {
3777 gtk_tree_path_free(path);
3778 path = path2; /* OK */
3780 if (gtk_tree_path_get_depth (path) > 1)
3781 gtk_tree_path_up (path);
3786 gtk_tree_path_free (path2);
3788 gtk_tree_view_expand_to_path (treeview, path);
3789 gtk_tree_view_expand_row (treeview, path, FALSE);
3791 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3793 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3795 newpath = gtk_tree_path_to_string(path);
3798 g_message("my_signal_handler: treeview=%p, moving from %s to %s",
3799 treeview, oldpath, newpath);
3805 /* gtk_tree_path_free(df.path); */
3810 menuitem_cb (gpointer callback_data,
3811 guint callback_action,
3815 GtkTreeModel *model;
3816 GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
3817 GtkTreeSelection *selection;
3822 gchar *oldpath, *newpath;
3823 GtkTreeViewColumn *focus_column;
3825 selection = gtk_tree_view_get_selection(treeview);
3827 model = gtk_tree_view_get_model(treeview);
3828 gtk_tree_view_get_cursor (treeview, &path, &focus_column);
3830 if (gtk_tree_model_get_iter (model, &iter, path)) {
3832 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
3833 NAME_COLUMN, &name, -1);
3834 oldpath = gtk_tree_path_to_string(path);
3837 switch (callback_action) {
3838 case 0: /* Select */
3839 gtk_tree_selection_select_path (selection, path);
3844 gtk_tree_view_expand_to_path (treeview, path);
3845 gtk_tree_view_expand_row (treeview, path, FALSE);
3847 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3849 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3851 newpath = gtk_tree_path_to_string(path);
3853 gtk_tree_path_free(path);
3855 newpath = g_strdup("** no path **");
3857 g_message("menueitem_cb: treeview=%p, moving from %s to %s",
3858 treeview, oldpath, newpath);
3862 /* get all non anonymous names to the root */
3865 dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
3866 GTK_DIALOG_DESTROY_WITH_PARENT,
3869 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
3870 gtk_item_factory_path_from_widget (widget),
3871 callback_action, text, oldpath, newpath, name);
3873 /* Close dialog on user response */
3874 g_signal_connect (dialog,
3876 G_CALLBACK (gtk_widget_destroy),
3879 gtk_widget_show (dialog);
3884 if (newpath != empty)
3888 g_message("menuitem_cb: no iterator...");
3891 static GtkItemFactoryEntry menu_items[] = {
3892 { "/Select", NULL, menuitem_cb, 0, NULL, 0 },
3893 { "/Back", "<control>B", menuitem_cb, 1, NULL, 0 },
3894 { "/Find", "<control>F", menuitem_cb, 2, NULL, 0 },
3895 { "/Save", "<control>S", menuitem_cb, 3, NULL, 0 },
3898 static gint button_press_callback( GtkWidget *widget,
3899 GdkEventButton *event,
3902 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
3904 /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
3905 * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
3908 if (event->button == 3) {
3909 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
3916 return FALSE; /* continue handling this event */
3921 create_message_window(void)
3923 GtkCellRenderer *renderer;
3924 GtkTreeStore *model;
3927 GtkWidget *treeview;
3929 GtkItemFactory *item_factory;
3930 GtkAccelGroup *accel_group;
3931 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3935 /* create window, etc */
3936 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3937 gtk_window_set_title (GTK_WINDOW (window), current_pduname);
3938 g_signal_connect (window, "destroy",
3939 G_CALLBACK (gtk_widget_destroyed), &window);
3941 vbox = gtk_vbox_new (FALSE, 8);
3942 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3943 gtk_container_add (GTK_CONTAINER (window), vbox);
3945 text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
3947 gtk_box_pack_start (GTK_BOX (vbox),
3948 gtk_label_new (text),
3952 sw = gtk_scrolled_window_new (NULL, NULL);
3953 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
3954 GTK_SHADOW_ETCHED_IN);
3955 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
3956 GTK_POLICY_AUTOMATIC,
3957 GTK_POLICY_AUTOMATIC);
3958 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3960 model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3961 G_TYPE_STRING, G_TYPE_STRING);
3963 namelist = ws_fopen("namelist.txt", "w");
3964 build_tree_view(model, PDUtree, NULL);
3968 /* create tree view */
3969 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
3970 g_object_unref (model);
3971 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
3972 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
3973 GTK_SELECTION_MULTIPLE);
3975 renderer = gtk_cell_renderer_text_new ();
3977 #if 0 /* testing pango attributes */
3980 PangoAttrList* attr;
3982 attr = pango_attr_list_new();
3983 bg = pango_attr_background_new(50000,55000,50000);
3984 bg->start_index = 0;
3985 bg->end_index = 10000;
3986 pango_attr_list_insert(attr, bg);
3988 g_object_set(renderer, "attributes", attr, NULL);
3990 #endif /* testing pango attributes */
3992 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3993 TITLE_COLUMN, "asn1 entities", renderer,
3994 "text", TITLE_COLUMN, NULL );
3996 /* renderer = gtk_cell_renderer_text_new ();
3997 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3998 * DEF_COLUMN, "type definition", renderer,
3999 * "text", DEF_COLUMN, NULL );
4001 * renderer = gtk_cell_renderer_text_new ();
4002 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4003 * REF_COLUMN, "reference", renderer,
4004 * "text", REF_COLUMN, NULL );
4006 renderer = gtk_cell_renderer_pixbuf_new ();
4007 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4008 VALUE_COLUMN, "value", renderer,
4009 "stock_id", VALUE_COLUMN, NULL );
4011 renderer = gtk_cell_renderer_text_new ();
4012 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4013 NAME_COLUMN, "fieldname", renderer,
4014 "text", NAME_COLUMN, NULL );
4016 gtk_container_add (GTK_CONTAINER (sw), treeview);
4018 /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
4022 accel_group = gtk_accel_group_new ();
4024 /* This function initializes the item factory.
4025 * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
4026 * or GTK_TYPE_OPTION_MENU.
4027 * Param 2: The path of the menu.
4028 * Param 3: A pointer to a gtk_accel_group. The item factory sets up
4029 * the accelerator table while generating menus.
4032 item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
4034 /* This function generates the menu items. Pass the item factory,
4035 the number of items in the array, the array itself, and any
4036 callback data for the the menu items. */
4037 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
4039 /* Attach the new accelerator group to the window. */
4040 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
4043 /* expand all rows after the treeview widget has been realized */
4044 g_signal_connect (treeview, "realize",
4045 G_CALLBACK (gtk_tree_view_expand_all), NULL);
4046 g_signal_connect (treeview, "row-activated",
4047 G_CALLBACK (my_signal_handler), (gpointer)model);
4049 g_signal_connect (treeview, "button_press_event",
4050 G_CALLBACK (button_press_callback), item_factory);
4052 /* g_signal_connect_swapped (treeview, "event",
4053 * G_CALLBACK (button_press_handler),
4056 gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
4059 if (!GTK_WIDGET_VISIBLE (window))
4060 gtk_widget_show_all (window);
4063 gtk_widget_destroy (window);
4067 #endif /* SHOWPDU */
4069 /************************************************************************************************
4070 * routines to find names to go with the decoded data stream *
4071 ************************************************************************************************/
4072 #define PDUSTATE_STACK_SIZE 1024
4073 typedef struct _statestack statestack;
4074 static struct _statestack {
4079 } PDUstate[PDUSTATE_STACK_SIZE];
4080 static gint PDUstatec = 0;
4082 /* XXX - Shouldn't we do bounds checking here? */
4083 #define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
4084 #define POPSTATE PDUstate[--PDUstatec]
4087 getname(GNode *node) {
4088 if (node == NULL || node->data == NULL)
4089 THROW(ReportedBoundsError);
4091 return ((PDUinfo *)node->data)->name;
4095 gettype(GNode *node) {
4096 if (node == NULL || node->data == NULL)
4097 THROW(ReportedBoundsError);
4099 return ((PDUinfo *)node->data)->type & TBL_TYPEmask;
4103 getinfo(GNode *node) {
4105 THROW(ReportedBoundsError);
4110 #define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
4111 #define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
4112 #define MATCH (info && (class == info->tclass) && (tag == info->tag))
4113 #define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
4114 #define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
4115 #define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
4116 #define ISCHOICE (info && (info->flags & PDU_CHOICE))
4117 #define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
4120 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
4121 pos.node=NULL;PUSHNODE(pos);return ret;}}
4125 showstack(statestack *pos, char *txt, int n)
4128 const char *name, *type, *stype;
4129 const char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
4135 if ( ! asn1_verbose)
4141 g_message("==underflow");
4144 rep = chs = done = ref = pop = chr = rch = sch = con = empty;
4148 name = ((PDUinfo *)g->data)->name;
4149 type = TBLTYPE(((PDUinfo *)g->data)->type);
4151 name = "node<null>";
4155 stype = TBLTYPE(typef);
4156 if (typef & TBL_REPEAT) rep = "[repeat]";
4157 if (typef & TBL_CHOICE_made) chs = "[choice]";
4158 if (typef & TBL_SEQUENCE_done) done = "[done]";
4159 if (typef & TBL_REFERENCE) ref = "[ref]";
4160 if (typef & TBL_REFERENCE_pop) pop = "[ref-pop]";
4161 if (typef & TBL_CHOICE_repeat) chr = "[chs-rep]";
4162 if (typef & TBL_REPEAT_choice) rch = "[rep-chs]";
4163 if (typef & TBL_SEQUENCE_choice)sch = "[seq-chs]";
4164 if (typef & TBL_CONSTRUCTED) con = "[constr]";
4166 i = g_sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
4167 (void *)pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4168 pos->name, pos->offset);
4170 for(j=1, n--; n>0; j++, n--) {
4171 p = &PDUstate[PDUstatec-j];
4173 stype = TBLTYPE(typef);
4174 rep = (typef & TBL_REPEAT) ? "[repeat]" : empty;
4175 chs = (typef & TBL_CHOICE_made) ? "[choice]" : empty;
4176 done = (typef & TBL_SEQUENCE_done) ? "[done]" : empty;
4177 ref = (typef & TBL_REFERENCE) ? "[ref]" : empty;
4178 pop = (typef & TBL_REFERENCE_pop) ? "[ref-pop]" : empty;
4179 chr = (typef & TBL_CHOICE_repeat) ? "[chs-rep]" : empty;
4180 rch = (typef & TBL_REPEAT_choice) ? "[rep-chs]" : empty;
4181 sch = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
4182 con = (typef & TBL_CONSTRUCTED) ? "[constr]" : empty;
4184 i += g_sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
4185 (void *)p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4186 p->name, p->offset);
4188 g_message("%s", buf);
4193 showrefNode(GNode *node, int n)
4195 const char *name = empty, *type = empty, *tname = empty;
4196 int cls = 0, tag = 0;
4201 g_message("%*sstop, nesting too deep", 2*n, empty);
4205 info = (PDUinfo *)(node->data);
4206 type = TBLTYPE(info->type);
4208 tname = info->typename;
4209 ref = info->reference;
4213 g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4214 2*n, empty, tname, type, name, node, node->data,
4215 ref, tag_class[cls], tag);
4218 showrefNode(ref, n+1);
4224 showNode(GNode *node, int n, int m)
4226 const char *name = empty, *type = empty;
4233 type = TBLTYPE(((PDUinfo *)(node->data))->type);
4234 name = ((PDUinfo *)(node->data))->name;
4235 ref = ((PDUinfo *)(node->data))->reference;
4237 g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4238 2*n, empty, type, name, node, node->data, node->next, node->prev,
4239 node->parent, node->children);
4242 g_message("%*sstop, nesting too deep", 2*n, empty);
4246 if (ref) showrefNode(ref, n+2);
4248 if (node->children) showNode(node->children, n+1, m);
4249 if (node->next) showNode(node->next, n, m);
4254 PDUreset(int count, int count2)
4258 if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
4260 PDUstatec = 0; /* stackpointer */
4261 PDUerrcount = 0; /* error counter per asn.1 message */
4263 pos.node = NULL; /* sentinel */
4264 pos.name = "sentinel";
4265 pos.type = TBL_SEQUENCEOF;
4270 pos.node = PDUtree; /* root of the tree */
4271 pos.name = getname(pos.node);
4272 pos.type = gettype(pos.node) | TBL_REPEAT;
4278 static GNode * /* find GNode for a choice element, 0 if none */
4279 makechoice(GNode *p, guint class, guint tag)
4284 p = g_node_first_child(p); /* the list of choices */
4285 info = 0; /* avoid gcc warning */
4288 info = ((PDUinfo *)p->data);
4290 if (info->type == TBL_CHOICE) {
4292 g_message(" using sub choice (%s)%s", info->typename, info->name);
4294 q = makechoice(p, class, tag);
4295 if (q) { /* found it */
4297 info = ((PDUinfo *)p->data);
4299 } /* continue with this level */
4303 g_message(" have %c%d, found %c%d, %s", tag_class[class], tag,
4304 tag_class[info->tclass], info->tag, info->name);
4306 if ((class == info->tclass) && (tag == info->tag))
4307 break; /* found it */
4310 p = g_node_next_sibling(p);
4313 if (p) g_message(" OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
4315 else g_message(" ...no matching choice...");
4320 /* offset is for debugging only, a reference to output on screen */
4322 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
4324 statestack pos, pos2, save_pos;
4326 const char *ret, *tmp;
4327 int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4328 static char namestr[64]; /* enough ? */
4329 static char posstr[40];
4330 static char noname[] = "*noname*";
4331 static PDUprops constructed_save; /* for unexpectedly constructed enteties */
4333 if (PDUstatec > 0) /* don't read from below the stack */
4335 /* pos refers to the last asn1 node handled */
4337 /* a very simple, too simple??, way to handle constructed entities */
4338 if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4339 /* unexpectedly constructed, return same info as last time */
4340 g_sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4341 showstack(&pos, posstr, 3);
4342 pos.offset = offset;
4343 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4344 PUSHNODE(pos); /* push extra, to match with a EOI operation */
4345 PUSHNODE(pos); /* restore the stack */
4346 *out = constructed_save;
4348 g_message(" return for constructed %s (%s)%s",
4349 TBLTYPE(out->type), out->typename, out->name);
4353 save_pos = pos; /* may need it again */
4357 out->typename = "*error*";
4364 if (PDUstatec <= 0) {
4365 if (PDUstatec > -10) {
4367 g_message(">>off=%d stack underflow, return", offset);
4369 if (PDUstatec == -10) {
4371 g_message(">>off=%d stack underflow, return, no more messages", offset);
4373 out->name = "*underflow*";
4374 out->flags |= OUT_FLAG_noname;
4378 g_sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4380 showstack(&pos, posstr, 3);
4384 if (class == ASN1_EOI) { /* end of this input sequence */
4386 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4387 if (asn1_verbose) g_message(" EOI: reference pop");
4390 switch(pos.type & TBL_TYPEmask) {
4392 if (asn1_verbose) g_message(" EOI: pop typeref");
4393 pos = POPSTATE; /* remove typeref */
4395 case TBL_CHOICE_done:
4396 if (asn1_verbose) g_message(" EOI: mark choice");
4398 pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4406 pos = POPSTATE; /* this is pushed back on the stack later */
4407 if (pos.node == NULL) {
4408 if (asn1_verbose) g_message(" EOI, pos.node == NULL");
4409 out->name = "*no-name-EOI*";
4410 out->flags |= OUT_FLAG_noname;
4415 info = getinfo(pos.node);
4417 tmp = TBLTYPE(info->type);
4418 if (offset != pos.offset) {
4420 g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4421 tmp, ret, offset, pos.offset);
4422 while ((offset < pos.offset) && (PDUstatec > 0)) {
4425 g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
4426 offset, pos.offset);
4428 if (offset != pos.offset)
4429 PDUerrcount++; /* only count if still unequal */
4431 if (asn1_verbose) g_message(" EOI %s:%s OK, offset=%d", tmp, ret, offset);
4434 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4435 * indicated by the synthetic EOI call. */
4436 if ((class == BER_CLASS_UNI) && (tag == BER_UNI_TAG_EOC)) { /* explicit EOC never has a name */
4437 PUSHNODE(pos); /* restore stack */
4438 ret = "explicit-EOC";
4439 if (asn1_verbose) g_message(" return '%s', ignore", ret);
4441 out->typename = "ASN1";
4445 /* find appropriate node for this tag */
4447 if (pos.node == NULL) {
4448 if (asn1_verbose) g_message(" pos.node == NULL");
4449 out->name = "*no-name*";
4450 out->flags |= OUT_FLAG_noname;
4455 /* showNode(pos.node, 3, 4); */
4457 switch (pos.type & TBL_TYPEmask) {
4458 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4462 if (pos.type & TBL_CHOICE_made) {
4463 if (asn1_verbose) g_message(" finish choice");
4469 info = getinfo(pos.node);
4471 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4472 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4474 if (asn1_verbose) g_message(" repeating choice"); /* ignore repeat */
4477 if (asn1_verbose) g_message(" seqof: repeat start");
4478 /* decide how to continue, CHILD for next instance of sequence
4479 * or NEXT for end of repeated sequence.
4480 * use the tag to make a descision */
4481 if (asn1_verbose) g_message(" seqof: first got %c%d, found %c%d",
4482 tag_class[class], tag,
4483 tag_class[info->tclass], info->tag);
4485 /* This is the start of repeating */
4487 ret = getname(pos.node);
4488 if (asn1_verbose) g_message(" return for repeat '%s'", ret);
4489 out->type = (pos.type & TBL_TYPEmask);
4490 out->typename = info->typename;
4492 out->value_id = info->value_id;
4493 out->type_id = info->type_id;
4495 if (asn1_verbose) g_message(" anonymous: dontshow");
4497 out->flags |= OUT_FLAG_dontshow;
4503 /* find out where to go .... */
4505 CHILD; /* assume sequence is repeated */
4507 info = getinfo(pos.node); /* needed for MATCH to look ahead */
4509 g_message(" seqof: child: got %c%d, found %c%d",
4510 tag_class[class], tag,
4511 tag_class[info->tclass], info->tag);
4513 if (pos2.type & TBL_CHOICE_repeat) {
4516 g_message(" repeating a choice, %s",
4518 pos.type = TBL_CHOICE_immediate;
4520 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4521 donext = 1; /* move on */
4523 g_message(" seqof: no repeat, force next");
4525 /* following code will take the child again */
4531 } else if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4532 if (asn1_verbose) g_message(" reference pop, donext");
4535 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4536 if (pos.type & TBL_SEQUENCE_choice) {
4537 pos = POPSTATE; /* expect to find a repeat here */
4540 if (asn1_verbose) g_message(" sequence done, donext");
4544 if (pos.type & TBL_REFERENCE) {
4545 if (asn1_verbose) g_message(" reference change ref -> pop");
4546 pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4549 pos.offset = offset;
4551 ret = pos.name; /* for the debug messages */
4554 if (asn1_verbose) g_message(" donext");
4557 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4558 case TBL_SETOF: /* ?? */
4559 case TBL_SEQUENCEOF:
4560 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4561 pos.type |= TBL_REPEAT;
4565 /* remember this is the start of a repeat cycle */
4566 typeflags |= TBL_REPEAT;
4568 g_message(" seqof: set repeat mark [push,child]");
4571 g_message(" seqof: end of repeat loop [next]");
4575 case TBL_SET: /* ?? */
4577 pos.type |= TBL_SEQUENCE_done;
4581 if (asn1_verbose) g_message(" seq [push,child]");
4584 /* no more choice */
4585 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4588 pos.type = 0; /* clear all type flags */
4590 g_message(" choice [push], %c%d, %s",
4591 tag_class[info->tclass], info->tag, getname(pos.node));
4592 pos.node = makechoice(pos.node, class, tag);
4593 if (pos.node == NULL) {
4595 out->flags |= OUT_FLAG_noname;
4598 info = getinfo(pos.node);
4600 ret = getname(pos.node);
4602 g_message(" '%s' %c%d will be used",
4603 ret, tag_class[info->tclass], info->tag);
4605 case TBL_CHOICE_done:
4611 if (asn1_verbose) g_message(" typeref [pop,next]");
4613 case TBL_ENUMERATED:
4615 /* skip named numbers now, call to PDUenum() will retrieve a name */
4618 case TBL_CHOICE_immediate:
4619 if (asn1_verbose) g_message(" immediate choice [no next]");
4628 if (pos.node == NULL) {
4629 ret = "*no-name-2*";
4630 if (asn1_verbose) g_message(" return '%s'", ret);
4632 out->flags |= OUT_FLAG_noname;
4636 ret = pos.name = getname(pos.node);
4637 pos.type = gettype(pos.node) | (pos.type & ~TBL_TYPEmask);
4638 info = getinfo(pos.node);
4640 /* pos now points to the prospective current node, go check it ********************/
4641 if (asn1_verbose) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4642 (ISOPTIONAL)?", optional":empty,
4643 (ISIMPLICIT)?", implicit":empty,
4644 tag_class[info->tclass], info->tag );
4646 if (ISOPTIONAL) { /* must check the tag */
4647 while(! MATCH) { /* check optional here again...? */
4649 g_message(" got %c%d, found %c%d", tag_class[class], tag,
4650 tag_class[info->tclass], info->tag);
4652 if (pos.node == NULL) {
4655 pos = save_pos; /* reset for next time */
4656 pos.type |= TBL_SEQUENCE_done;
4658 pos.type &= ~TBL_SEQUENCE_done;
4660 out->flags |= OUT_FLAG_dontshow;
4662 g_message(" end of optional list, constructed, expect value next time");
4665 out->flags |= OUT_FLAG_noname;
4667 g_message(" *end of optional list...");
4668 info = 0; /* this is not valid any more... */
4670 break; /* end of list */
4672 info = getinfo(pos.node);
4673 if (asn1_verbose) g_message(" optional, %s", getname(pos.node));
4675 if (pos.node && ! cons_handled) {
4676 ret = pos.name = getname(pos.node);
4677 pos.type = gettype(pos.node);
4679 /* pos now refers to node with name we want, optional nodes skipped */
4682 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4683 pos2 = pos; /* save current state */
4687 g_message(" already pushed, skip next push");
4689 typeflags &= ~TBL_CHOICE_made;
4692 if (asn1_verbose && info)
4693 g_message(" immediate choice [push], %c%d, %s",
4694 tag_class[info->tclass], info->tag, getname(pos.node));
4696 pos.node = makechoice(pos.node, class, tag);
4698 if (pos.node == NULL) {
4702 info = getinfo(pos.node);
4703 pos.type = gettype(pos.node);
4704 out->type = (pos.type & TBL_TYPEmask);
4705 out->flags |= OUT_FLAG_type;
4707 g_sprintf(namestr, "%s!%s", ret, getname(pos.node));
4710 g_message(" %s:%s will be used", TBLTYPE(pos.type), ret);
4711 if (typeflags & TBL_REPEAT) {
4712 pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
4714 pos.type |= TBL_SEQUENCE_choice;
4717 g_message(" return from immediate choice [%s] '%s'",
4718 TBLTYPE(pos.type), ret);
4720 out->data = pos.node; /* for access to named numbers... */
4722 out->type = (pos.type & TBL_TYPEmask);
4725 out->typename = info->typename;
4726 out->fullname = info->fullname;
4727 out->value_id = info->value_id;
4728 out->type_id = info->type_id;
4733 typeflags |= TBL_CHOICE_made;
4736 if (asn1_verbose) g_message(" matching choice '%s'", ret);
4738 if ( ! cons ) { /* ISIMPLICIT was not OK for all */
4739 pos = pos2; /* reset for continuation */
4744 g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4745 (ISOPTIONAL)?", optional":empty,
4746 (ISIMPLICIT)?", implicit":empty,
4747 tag_class[info->tclass], info->tag );
4749 g_message(" using: unknown '%s'", ret);
4752 /* must follow references now */
4753 if (pos.type == TBL_TYPEREF && info) {
4754 out->typename = info->typename;
4755 out->type_id = info->typenum;
4756 out->flags |= OUT_FLAG_typename;
4758 PUSHNODE(pos); /* remember where we were */
4759 if (asn1_verbose) g_message(" typeref [push]");
4760 typeflags |= TBL_REFERENCE;
4761 if (info->reference == 0) { /* resolved ref to universal type.... */
4762 /* showNode(pos.node, 3, 4); */
4763 pos.type = gettype(pos.node); /* the resulting type */
4764 info = getinfo(pos.node);
4765 tmp = "inknown tag";
4766 if ((info->tclass == BER_CLASS_UNI) && (info->tag < 31)) {
4767 tmp = asn1_tag[info->tag];
4768 pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
4770 if (asn1_verbose && info)
4771 g_message(" indirect typeref to %s:%s, %s [%c%d]",
4772 TBLTYPE(pos.type), info->typename, tmp,
4773 tag_class[info->tclass], info->tag );
4775 out->fullname = info->fullname;
4776 donext = (ISANONYMOUS); /* refereing entity has no name ? */
4777 pos.node = info->reference;
4778 pos.type = gettype(pos.node);
4779 info = getinfo(pos.node);
4781 g_message(" typeref %s %s", TBLTYPE(pos.type), getname(pos.node));
4782 /* keep name from before going through the reference, unless anonymous */
4783 if (donext) /* refering entity has no name */
4784 ret = getname(pos.node); /* a better name */
4786 /* handle choice here ? !!mm!! */
4788 out->type = (pos.type & TBL_TYPEmask);
4789 out->flags |= OUT_FLAG_type;
4790 /* showNode(pos.node, 3, 4); */
4791 /* ret = getname(pos.node);*/
4793 out->data = pos.node;
4794 out->flags |= OUT_FLAG_data;
4796 g_message(" typeref set named number list node %p", (void *)pos.node);
4800 pos.type = TBL_TYPEREF_nopop;
4801 if (asn1_verbose) g_message(" typeref pop");
4802 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
4803 /* do not enter the named-number list */
4805 pos.type = TBL_TYPEREF_nopop;
4806 if (asn1_verbose) g_message(" typeref [pop]");
4808 typeflags |= TBL_REFERENCE;
4813 if (cons && ! cons_handled) { /* This entity is constructed, expected ? */
4815 case TBL_BOOLEAN: /* these are not expected to be constructed */
4817 case TBL_OCTETSTRING:
4821 case TBL_ENUMERATED:
4823 typeflags |= TBL_CONSTRUCTED;
4824 /* this entry has no extra info, next is the same */
4825 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
4826 if (asn1_verbose) g_message(" dontshow and set constructed flag");
4828 default: /* others, such as sequences, are expected to be constructed */
4835 if (asn1_verbose) g_message(" anonymous: dontshow");
4836 if (asn1_debug) /* this entry has no extra info, next is the same */
4837 out->flags |= OUT_FLAG_dontshow;
4839 out->name = empty; /* show it, but no name */
4842 if (out->name != empty)
4845 if ( ! (out->flags & OUT_FLAG_data))
4846 out->data = pos.node; /* for access to named numbers... */
4848 pos.type |= typeflags;
4851 if ( ! (out->flags & OUT_FLAG_type))
4852 out->type = pos.type;
4854 out->type &= TBL_TYPEmask;
4856 if (ret == noname) {
4858 out->flags |= OUT_FLAG_noname;
4861 if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
4862 out->typename = info->typename;
4863 out->type_id = info->typenum;
4866 if (info && (out->value_id == -1)) {
4867 out->value_id = info->value_id;
4868 out->type_id = info->type_id;
4871 if ((out->fullname == 0) && info)
4872 out->fullname = info->fullname;
4874 if (typeflags & TBL_CONSTRUCTED)
4875 constructed_save = *out;
4878 g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
4879 out->value_id, out->type_id);
4885 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
4889 const char *ret, *name;
4890 static char unnamed[] = "*unnamed*";
4892 (void) cls; (void) tag; /* make a reference */
4894 if (props->flags & OUT_FLAG_noname)
4898 list = (GNode *)props->data;
4901 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
4903 return "*list-still-0*";
4906 if ((PDUinfo *)list->data)
4907 name = ((PDUinfo *)list->data)->name;
4911 for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
4912 info = (PDUinfo *)list->data;
4913 if (value == info->tag) {
4922 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
4926 #endif /* READSYNTAX */
4929 proto_register_asn1(void) {
4931 static const enum_val_t type_recursion_opts[] = {
4945 gint *ett[1+MAX_NEST+MAXPDU];
4947 module_t *asn1_module;
4950 asn1_logfile = get_tempfile_path(ASN1LOGFILE);
4952 current_asn1 = g_strdup("");
4953 asn1_filename = g_strdup(current_asn1);
4955 current_pduname = g_strdup("ASN1");
4956 asn1_pduname = g_strdup(current_pduname);
4958 proto_asn1 = proto_register_protocol("ASN.1 decoding",
4962 for (i=0, j=1; i<MAX_NEST; i++, j++) {
4963 ett[j] = &ett_seq[i];
4966 for(i=0; i<MAXPDU; i++, j++) {
4967 ett[j] = &ett_pdu[i];
4971 proto_register_subtree_array(ett, array_length(ett));
4973 asn1_module = prefs_register_protocol(proto_asn1,
4974 proto_reg_handoff_asn1);
4975 #ifdef JUST_ONE_PORT
4976 prefs_register_uint_preference(asn1_module, "tcp_port",
4978 "The TCP port on which "
4979 "ASN.1 messages will be read",
4980 10, &global_tcp_port_asn1);
4981 prefs_register_uint_preference(asn1_module, "udp_port",
4983 "The UDP port on which "
4984 "ASN.1 messages will be read",
4985 10, &global_udp_port_asn1);
4986 prefs_register_uint_preference(asn1_module, "sctp_port",
4988 "The SCTP port on which "
4989 "ASN.1 messages will be read",
4990 10, &global_sctp_port_asn1);
4992 range_convert_str(&global_tcp_ports_asn1, ep_strdup_printf("%u", TCP_PORT_ASN1), 65535);
4993 range_convert_str(&global_udp_ports_asn1, ep_strdup_printf("%u", UDP_PORT_ASN1), 65535);
4994 range_convert_str(&global_sctp_ports_asn1, ep_strdup_printf("%u", SCTP_PORT_ASN1), 65535);
4996 prefs_register_range_preference(asn1_module, "tcp_ports",
4998 "The TCP ports on which "
4999 "ASN.1 messages will be read",
5000 &global_tcp_ports_asn1, 65535);
5001 prefs_register_range_preference(asn1_module, "udp_ports",
5003 "The UDP ports on which "
5004 "ASN.1 messages will be read",
5005 &global_udp_ports_asn1, 65535);
5006 prefs_register_range_preference(asn1_module, "sctp_ports",
5008 "The SCTP ports on which "
5009 "ASN.1 messages will be read",
5010 &global_sctp_ports_asn1, 65535);
5011 #endif /* JUST_ONE_PORT */
5013 prefs_register_bool_preference(asn1_module, "desegment_messages",
5015 "Desegment ASN.1 messages that span TCP segments",
5018 old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
5020 bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
5023 prefs_register_string_preference(asn1_module, "file",
5024 "ASN.1 type table file",
5025 "Compiled ASN.1 description of ASN.1 types",
5027 prefs_register_string_preference(asn1_module, "pdu_name",
5029 "Name of top level PDU",
5031 prefs_register_uint_preference(asn1_module, "first_pdu_offset",
5032 "Offset to first PDU in first tcp packet",
5033 "Offset for non-reassembled packets, "
5034 "wrong if this happens on other than the first packet!",
5035 10, &first_pdu_offset);
5036 prefs_register_bool_preference(asn1_module, "flat",
5038 "Show full names for all values",
5040 prefs_register_enum_preference(asn1_module, "type_recursion",
5041 "Eliminate references to level",
5042 "Allow this recursion level for eliminated type references",
5043 &type_recursion_level,
5044 type_recursion_opts, FALSE);
5045 prefs_register_bool_preference(asn1_module, "debug",
5047 "Extra output useful for debugging",
5050 prefs_register_bool_preference(asn1_module, "message_win",
5052 "show full message description",
5055 prefs_register_obsolete_preference(asn1_module, "message_win");
5057 prefs_register_bool_preference(asn1_module, "verbose_log",
5058 "Write very verbose log",
5059 "log to file $TMP/" ASN1LOGFILE,
5063 /* The registration hand-off routing */
5065 static dissector_handle_t asn1_handle;
5068 register_tcp_port(guint32 port)
5071 dissector_add("tcp.port", port, asn1_handle);
5075 unregister_tcp_port(guint32 port)
5078 dissector_delete("tcp.port", port, asn1_handle);
5082 register_udp_port(guint32 port)
5085 dissector_add("udp.port", port, asn1_handle);
5089 unregister_udp_port(guint32 port)
5092 dissector_delete("udp.port", port, asn1_handle);
5096 register_sctp_port(guint32 port)
5099 dissector_add("sctp.port", port, asn1_handle);
5103 unregister_sctp_port(guint32 port)
5106 dissector_delete("sctp.port", port, asn1_handle);
5110 proto_reg_handoff_asn1(void) {
5111 static gboolean asn1_initialized = FALSE;
5112 /* XXX: Note that the "saved" ports [or port ranges] will not be initialized the first time */
5113 /* thru pro_reg_handoff_asn1 if no PDUtree is built; So: we init with the definition. */
5114 #ifdef JUST_ONE_PORT
5115 static guint tcp_port_asn1 = 0;
5116 static guint udp_port_asn1 = 0;
5117 static guint sctp_port_asn1 = 0;
5119 static range_t *tcp_ports_asn1 = NULL;
5120 static range_t *udp_ports_asn1 = NULL;
5121 static range_t *sctp_ports_asn1 = NULL;
5126 #ifdef JUST_ONE_PORT
5127 if (asn1_verbose) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegnment=%d, "
5128 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5129 global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
5130 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5133 char *tcp_ports_asn1_string, *udp_ports_asn1_string, *sctp_ports_asn1_string;
5134 tcp_ports_asn1_string = range_convert_range(global_tcp_ports_asn1);
5135 udp_ports_asn1_string = range_convert_range(global_udp_ports_asn1);
5136 sctp_ports_asn1_string = range_convert_range(global_sctp_ports_asn1);
5137 g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegnment=%d, "
5138 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5139 tcp_ports_asn1_string, udp_ports_asn1_string, sctp_ports_asn1_string, asn1_desegment,
5140 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5142 #endif /* JUST_ONE_PORT */
5144 if(!asn1_initialized) {
5145 asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
5146 asn1_initialized = TRUE;
5147 } else { /* clean up ports and their lists */
5148 #ifdef JUST_ONE_PORT
5149 unregister_tcp_port(tcp_port_asn1);
5150 unregister_udp_port(udp_port_asn1);
5151 unregister_sctp_port(sctp_port_asn1);
5153 if (tcp_ports_asn1 != NULL) {
5154 range_foreach(tcp_ports_asn1, unregister_tcp_port);
5155 g_free(tcp_ports_asn1);
5158 if (udp_ports_asn1 != NULL) {
5159 range_foreach(udp_ports_asn1, unregister_udp_port);
5160 g_free(udp_ports_asn1);
5163 if (sctp_ports_asn1 != NULL) {
5164 range_foreach(sctp_ports_asn1, unregister_sctp_port);
5165 g_free(sctp_ports_asn1);
5167 #endif /* JUST_ONE_PORT */
5170 if (strcmp(asn1_filename, current_asn1) != 0) {
5171 /* new definitions, parse the file if we have one */
5172 /* !!! should be postponed until we really need it !!! */
5174 read_asn1_type_table(asn1_filename);
5175 #endif /* READSYNTAX */
5176 g_free(current_asn1);
5177 current_asn1 = g_strdup(asn1_filename);
5179 if (!PDUtree || /* no tree built yet for PDU type */
5180 strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
5181 if (build_pdu_tree(asn1_pduname)) {
5182 g_free(current_pduname);
5183 current_pduname = g_strdup(asn1_pduname);
5187 if (asn1_message_win) { /* show what we are prepared to recognize */
5189 gtk_widget_destroy (window);
5192 create_message_window();
5194 #endif /* SHOWPDU */
5196 /* If we now have a PDU tree, register for the port or ports we have */
5198 #ifdef JUST_ONE_PORT
5199 tcp_port_asn1 = global_tcp_port_asn1;
5200 udp_port_asn1 = global_udp_port_asn1;
5201 sctp_port_asn1 = global_sctp_port_asn1;
5203 register_tcp_port(tcp_port_asn1);
5204 register_udp_port(udp_port_asn1);
5205 register_sctp_port(sctp_port_asn1);
5207 tcp_ports_asn1 = range_copy(global_tcp_ports_asn1);
5208 udp_ports_asn1 = range_copy(global_udp_ports_asn1);
5209 sctp_ports_asn1 = range_copy(global_sctp_ports_asn1);
5211 range_foreach(tcp_ports_asn1, register_tcp_port);
5212 range_foreach(udp_ports_asn1, register_udp_port);
5213 range_foreach(sctp_ports_asn1, register_sctp_port);
5214 #endif /* JUST_ONE_PORT */