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 /* conversion from snacc type to appropriate wireshark display type */
329 static guint tbl_display_wireshark[] = {
330 /* 0 */ BASE_DEC, /* TBL_BOOLEAN */
331 /* 1 */ BASE_DEC_HEX, /* TBL_INTEGER */
332 /* 2 */ BASE_HEX, /* TBL_BITSTRING */
333 /* 2 */ BASE_NONE, /* TBL_OCTETSTRING */
334 /* 4 */ BASE_NONE, /* TBL_NULL */
335 /* 5 */ BASE_DEC, /* TBL_OID */
336 /* 6 */ BASE_DEC, /* TBL_REAL */
337 /* 7 */ BASE_DEC, /* TBL_ENUMERATED */
338 /* 8 */ BASE_NONE, /* TBL_SEQUENCE */
339 /* 9 */ BASE_NONE, /* TBL_SET */
340 /* 10 */ BASE_NONE, /* TBL_SEQUENCEOF */
341 /* 11 */ BASE_NONE, /* TBL_SETOF */
342 /* 12 */ BASE_NONE, /* TBL_CHOICE */
343 /* 13 */ BASE_NONE, /* TBL_TYPEREF */
345 /* 14 */ BASE_NONE, /* TBL_SEQUENCEOF_start */
346 /* 15 */ BASE_NONE, /* TBL_TYPEREF_nopop */
347 /* 16 */ BASE_NONE, /* TBL_CHOICE_done */
348 /* 17 */ BASE_NONE, /* TBL_reserved */
349 /* 18 */ BASE_NONE, /* TBL_CHOICE_immediate */
351 /* 19 */ BASE_NONE, /* TBL_INVALID */
354 static const char *tbl_types_wireshark_txt[] = {
355 /* 0 */ "FT_BOOLEAN", /* TBL_BOOLEAN */
356 /* 1 */ "FT_UINT32", /* TBL_INTEGER */
357 /* 2 */ "FT_UINT32", /* TBL_BITSTRING */
358 /* 2 */ "FT_STRINGZ", /* TBL_OCTETSTRING */
359 /* 4 */ "FT_NONE", /* TBL_NULL */
360 /* 5 */ "FT_BYTES", /* TBL_OID */
361 /* 6 */ "FT_DOUBLE", /* TBL_REAL */
362 /* 7 */ "FT_UINT32", /* TBL_ENUMERATED */
363 /* 8 */ "FT_NONE", /* TBL_SEQUENCE */
364 /* 9 */ "FT_NONE", /* TBL_SET */
365 /* 10 */ "FT_NONE", /* TBL_SEQUENCEOF */
366 /* 11 */ "FT_NONE", /* TBL_SETOF */
367 /* 12 */ "FT_NONE", /* TBL_CHOICE */
368 /* 13 */ "FT_NONE", /* TBL_TYPEREF */
370 /* 14 */ "FT_NONE", /* TBL_SEQUENCEOF_start */
371 /* 15 */ "FT_NONE", /* TBL_TYPEREF_nopop */
372 /* 16 */ "FT_NONE", /* TBL_CHOICE_done */
373 /* 17 */ "FT_NONE", /* TBL_reserved */
374 /* 18 */ "FT_NONE", /* TBL_CHOICE_immediate */
376 /* 19 */ "FT_NONE", /* TBL_INVALID */
379 typedef struct _PDUinfo PDUinfo;
383 const char *typename;
384 const char *fullname;
390 gint basetype; /* parent type */
391 gint mytype; /* original type number, typenum may have gone through a reference */
392 gint value_id; /* wireshark field id for the value in this PDU */
393 gint type_id; /* wireshark field id for the type of this PDU */
394 hf_register_info value_hf; /* wireshark field info for this value */
398 /* bits in the flags collection */
399 #define PDU_OPTIONAL 1
400 #define PDU_IMPLICIT 2
401 #define PDU_NAMEDNUM 4
402 #define PDU_REFERENCE 8
403 #define PDU_TYPEDEF 0x10
404 #define PDU_ANONYMOUS 0x20
405 #define PDU_TYPETREE 0x40
407 #define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
409 static guint PDUinfo_initflags = 0; /* default flags for newly allocated PDUinfo structs */
411 /* description of PDU properties as passed from the matching routine
412 * to the decoder and GUI.
414 typedef struct _PDUprops PDUprops;
416 guint type; /* value from enum TBLTypeId */
418 const char *typename;
419 const char *fullname;
425 /* flags defined in PDUprops.flags */
426 #define OUT_FLAG_type 1
427 #define OUT_FLAG_data 2
428 #define OUT_FLAG_typename 4
429 #define OUT_FLAG_dontshow 8
430 #define OUT_FLAG_noname 0x10
431 #define OUT_FLAG_constructed 0x20
433 static PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
434 static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
436 static const char empty[] = ""; /* address of the empt string, avoids many tests for NULL */
437 #define MAX_OTSLEN 256 /* max printed size for an octet string */
440 #undef NEST /* show nesting of asn.1 enties */
442 #ifdef NEST /* only for debugging */
443 /* show nesting, only for debugging... */
444 #define MAXTAGS MAX_NEST
450 static char *showtaglist(guint level)
452 static char tagtxt[BUFLM];
457 for(i=0; i<= level; i++) {
458 switch(taglist[i].cls) {
459 case BER_CLASS_UNI: *p++ = 'U'; break;
460 case BER_CLASS_APP: *p++ = 'A'; break;
461 case BER_CLASS_CON: *p++ = 'C'; break;
462 case BER_CLASS_PRI: *p++ = 'P'; break;
463 default: *p++ = 'x'; break;
465 p += g_sprintf(p, "%d.", taglist[i].tag);
467 #else /* only context tags */
469 for(i=0; i<= level; i++) {
470 if (taglist[i].cls == BER_CLASS_CON) {
471 p += g_sprintf(p, "%d.", taglist[i].tag);
475 *--p = 0; /* remove trailing '.' */
480 get_context(guint level)
485 for(i=0; i<=level; i++) {
486 if (taglist[i].cls == BER_CLASS_CON)
487 ctx = (ctx << 8) | taglist[i].tag;
491 #endif /* NEST, only for debugging */
494 /* Convert a bit string to an ascii representation for printing
495 * -- not thread safe ...
497 static const char *showbits(guchar *val, guint count)
499 static char str[BUFLM];
504 return "*too many bits*";
507 for(i=0; i<count; i++) {
508 if (i && ((i & 7) == 0)) *p++ = ' ';
509 *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
516 /* get bitnames string for bits set */
518 showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
520 static char str[BUFLL];
524 if (props->flags & OUT_FLAG_noname)
528 return "*too many bits, no names...*";
531 for(i=0; i<count; i++) {
532 if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
533 p += g_sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
537 --p; /* remove terminating , */
545 /* Convert an oid to its conventional text representation
546 * -- not thread safe...
548 static char *showoid(subid_t *oid, guint len)
550 static char str[BUFLM];
555 for(i=0; i<len; i++) {
557 p += g_sprintf(p, "%lu", (unsigned long)oid[i]);
564 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
566 showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
571 const char *endstr = empty;
577 for (i=0; i<len; i++) {
578 if (!isprint(octets[i])) /* maybe isblank() as well ... */
581 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
583 endstr = "...."; /* this is 5 bytes !! */
586 str = p = g_malloc(len*2 + 5);
587 for (i=0; i<len; i++) {
588 p += g_sprintf(p, "%2.2X", octets[i]);
590 strncpy(p, endstr, 5);
592 if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
593 str = p = g_malloc(len*3+2);
594 for (i=0; i<len; i++) {
595 p += g_sprintf(p, "%2.2X", octets[i]);
597 *p++ = ' '; /* insert space */
598 strncpy(p, octets, len);
601 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
602 str = g_malloc(len+5);
603 strncpy(str, octets, len);
604 strncpy(&str[len], endstr, 5);
611 /* allow NULL pointers in strcmp, handle them as empty strings */
613 g_strcmp(gconstpointer a, gconstpointer b)
615 if (a == 0) a = empty;
616 if (b == 0) b = empty;
620 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
621 /* WARNING WARNING WARNING WARNING WARNING WARNING */
623 /* Most of the following routine is guesswork in order to */
624 /* speed up resynchronisation if the dissector lost the */
625 /* encoding due to incomplete captures, or a capture that */
626 /* starts in the middle of a fragmented ip packet */
627 /* If this poses to many problems, these settings can be */
628 /* made part of the protocol settings in the user interface */
629 /*************************************************************/
631 /* check length for a reasonable value, return a corrected value */
633 checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
638 g_snprintf(lenstr, strmax, "indefinite");
642 if (len < 0) /* negative ..... */
645 if (cls != BER_CLASS_UNI) { /* don't know about the tags */
650 case BER_UNI_TAG_EOC: /* End Of Contents */
651 case BER_UNI_TAG_NULL: /* Null */
654 case BER_UNI_TAG_BOOLEAN: /* Boolean */
657 case BER_UNI_TAG_INTEGER: /* Integer */
658 case BER_UNI_TAG_ENUMERATED: /* Enumerated */
662 case BER_UNI_TAG_BITSTRING: /* Bit String */
666 case BER_UNI_TAG_OCTETSTRING: /* Octet String */
667 case BER_UNI_TAG_NumericString: /* Numerical String */
668 case BER_UNI_TAG_PrintableString: /* Printable String */
669 case BER_UNI_TAG_TeletexString: /* Teletext String */
670 case BER_UNI_TAG_VideotexString: /* Video String */
671 case BER_UNI_TAG_IA5String: /* IA5 String */
672 case BER_UNI_TAG_GraphicString: /* Graphical String */
673 case BER_UNI_TAG_VisibleString: /* Visible String */
674 case BER_UNI_TAG_GeneralString: /* General String */
678 case BER_UNI_TAG_OID: /* Object Identifier */
679 case BER_UNI_TAG_ObjectDescriptor: /* Description */
680 case ASN1_EXT: /* External */
684 case BER_UNI_TAG_REAL: /* Real */
688 case BER_UNI_TAG_SEQUENCE: /* Sequence */
689 case BER_UNI_TAG_SET: /* Set */
693 case BER_UNI_TAG_UTCTime: /* Universal Time */
694 case BER_UNI_TAG_GeneralizedTime: /* General Time */
707 /* a change was needed.... */
708 g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
710 g_snprintf(lenstr, strmax, "%d", len);
715 static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
716 static void PDUreset(int count, int counr2);
719 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
722 guint cls, con, tag, len, offset, reassembled;
728 const char *name, *tname;
729 volatile guint boffset;
730 volatile int i = 0; /* PDU counter */
731 proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
732 proto_item *hidden_item;
734 static guint lastseq;
735 struct tcpinfo *info;
741 reassembled = 1; /* UDP is not a stream, and thus always reassembled .... */
742 if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
743 info = (struct tcpinfo *)pinfo->private_data;
744 delta = info->seq - lastseq;
745 reassembled = info->is_reassembled;
749 g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
750 info->seq, delta, reassembled);
753 g_message("dissect_asn1: udp");
756 /* Set the protocol column */
757 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
759 col_clear(pinfo->cinfo, COL_INFO);
763 if ((first_pdu_offset > 0) && !reassembled) {
764 boffset = first_pdu_offset;
765 g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
768 /* open BER decoding */
769 asn1_open(&asn1, tvb, boffset);
771 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
773 asn1_close(&asn1, &offset);
775 PDUreset(pcount, 0); /* arguments are just for debugging */
776 getPDUprops(&props, boffset, cls, tag, con);
778 tname = props.typename;
780 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
784 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
786 g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
793 ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
799 if (props.flags & OUT_FLAG_noname) {
800 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
801 name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
803 g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
806 /* Set the info column */
807 col_add_str(pinfo->cinfo, COL_INFO, headstr );
810 * If we have a non-null tree (ie we are building the proto_tree
811 * instead of just filling out the columns ), then add a BER
815 /* ignore the tree here, must decode BER to know how to reassemble!! */
818 TRY { /* catch incomplete PDU's */
820 ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
821 def? (int) (offset - boffset + len) : -1,
822 "ASN.1 %s", current_pduname);
824 tree2 = proto_item_add_subtree(ti, ett_asn1);
826 hidden_item = proto_tree_add_item(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
827 def? (int) (offset - boffset + len) : -1, TRUE);
828 PROTO_ITEM_SET_HIDDEN(hidden_item);
830 offset = boffset; /* the first packet */
831 while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
834 /* open BER decoding */
835 asn1_open(&asn1, tvb, offset);
836 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
837 asn1_close(&asn1, &offset);
839 PDUreset(pcount, i+1);
840 getPDUprops(&props, boffset, cls, tag, con);
842 tname = props.typename;
845 len = tvb_length_remaining(tvb, offset);
847 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
851 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
853 g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
856 ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
859 tvb_length_remaining(tvb, offset) );
861 if (props.value_id == -1)
862 ti2 = proto_tree_add_text(tree2, tvb, boffset,
863 def? (int) (offset - boffset + len) : -1,
864 "%s: (%s)%s %d-%d %s", current_pduname,
865 tname, name, pcount, i+1, headstr);
867 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
868 def? (int) (offset - boffset + len) : -1,
869 "%s: (%s)%s %d-%d %s ~", current_pduname,
870 tname, name, pcount, i+1, headstr);
872 if (props.type_id != -1){
873 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
874 def? (int) (offset - boffset + len) : -1, TRUE);
875 PROTO_ITEM_SET_HIDDEN(hidden_item);
880 if (props.flags & OUT_FLAG_noname) {
881 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
882 name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
884 if (props.value_id == -1)
885 ti2 = proto_tree_add_text(tree2, tvb, boffset,
886 def? (int) (offset - boffset + len) : -1,
887 "%s: (%s)%s", current_pduname, tname, name);
889 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
890 def? (int) (offset - boffset + len) : -1,
891 "%s: (%s)%s ~", current_pduname, tname, name);
892 if (props.type_id != -1){
893 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
894 def? (int) (offset - boffset + len) : -1, TRUE);
895 PROTO_ITEM_SET_HIDDEN(hidden_item);
899 asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
902 taglist[0].cls = cls;
903 taglist[0].tag = tag;
906 if (!def) len++; /* make sure we get an exception if we run off the end! */
908 offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
910 proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
912 i++; /* one more full message handled */
914 if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
915 proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
917 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
919 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
924 CATCH(ReportedBoundsError) {
925 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
927 proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
929 proto_item_append_text(ti2, " (incomplete)");
930 if (asn1_desegment) {
931 pinfo->desegment_offset = boffset;
932 pinfo->desegment_len = 1;
934 g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
935 boffset, 1, pinfo->can_desegment);
943 g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
944 pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
947 /* decode an ASN.1 sequence, until we have consumed the specified length */
949 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
952 guint ret, cls, con, tag, len, boffset, soffset, eos;
955 const char *clsstr, *constr, *tagstr;
959 proto_tree *ti, *pt2;
960 proto_item *hidden_item;
961 guchar *octets, *bits, unused;
963 /* the debugging formats */
964 static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s"; /* decimal */
965 static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s"; /* enum */
966 static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s"; /* octet string */
967 static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s"; /* bit field */
968 static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s"; /* constructed */
969 static char matchind[] = " ~"; /* indication of possible match */
970 const char *name, *ename, *tname;
974 ti = 0; /* suppress gcc warning */
976 soffset = offset; /* where this sequence starts */
978 while (offset < eos) { /* while this entity has not ended... */
980 asn1_open(&asn1, tvb, offset);
981 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
982 asn1_close(&asn1, &offset); /* mark current position */
983 if (ret != ASN1_ERR_NOERROR) {
984 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
988 getPDUprops(&props, boffset, cls, tag, con);
990 tname = props.typename;
992 name = &props.fullname[pabbrev_pdu_len]; /* no abbrev.pduname */
993 if (asn1_debug) { /* show both names */
994 g_sprintf(fieldname, "%s[%s]", props.name, props.fullname);
998 clsstr = asn1_cls[cls];
999 constr = asn1_con[con];
1000 if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
1001 tagstr = asn1_tag[tag];
1003 g_snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
1007 len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
1010 g_snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
1012 strncpy(nnbuf, "NN-", sizeof(nnbuf));
1013 /* make sure we get an exception if we run off the end! */
1014 len = tvb_length_remaining(tvb, offset) + 1;
1016 if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
1017 /* just give type name if we don't know any better */
1019 name = nnbuf; /* this is better than just empty.... */
1023 taglist[level].cls = cls;
1024 taglist[level].tag = tag;
1028 if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
1029 cls = BER_CLASS_UNI;
1030 tag = BER_UNI_TAG_GeneralString;
1031 oname = g_malloc(strlen(name) + 32);
1032 g_sprintf(oname, "%s ** nesting cut off **", name);
1036 case BER_CLASS_UNI: /* fprintf(stderr, "Universal\n"); */
1038 case BER_UNI_TAG_INTEGER:
1039 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1040 asn1_close(&asn1, &offset); /* mark where we are now */
1042 if ( (props.value_id == -1) ||
1043 (tbl_types_wireshark[props.type] != FT_UINT32) )
1044 /* unknown or unexpected: just text */
1045 proto_tree_add_text(pt, tvb, boffset,
1046 offset - boffset, textfmt_d, boffset,
1047 clsstr, constr, tagstr, tname, name, value,
1050 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1051 offset - boffset, value, textfmt_d, boffset,
1052 clsstr, constr, tagstr, tname, name, value,
1054 if (props.type_id != -1) {
1055 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1056 boffset, offset - boffset, value);
1057 PROTO_ITEM_SET_HIDDEN(hidden_item);
1061 if ( (props.value_id == -1) ||
1062 (tbl_types_wireshark[props.type] != FT_UINT32) )
1063 /* unknown or unexpected, just text */
1064 proto_tree_add_text(pt, tvb, boffset,
1066 "(%s)%s: %d", tname, name, value);
1068 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1069 offset - boffset, value,
1070 "(%s)%s: %d ~", tname, name, value);
1071 if (props.type_id != -1){
1072 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1073 boffset, offset - boffset, value);
1074 PROTO_ITEM_SET_HIDDEN(hidden_item);
1080 case BER_UNI_TAG_ENUMERATED:
1081 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1082 asn1_close(&asn1, &offset); /* mark where we are now */
1083 ename = getPDUenum(&props, boffset, cls, tag, value);
1085 if ( (props.value_id == -1) ||
1086 (tbl_types_wireshark[props.type] != FT_UINT32) )
1087 /* unknown or unexpected, just text */
1088 proto_tree_add_text(pt, tvb, boffset,
1090 textfmt_e, boffset, clsstr, constr, tagstr,
1091 tname, name, value, ename, empty);
1093 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1094 offset - boffset, value,
1095 textfmt_e, boffset, clsstr, constr, tagstr,
1096 tname, name, value, ename, matchind);
1097 if (props.type_id != -1){
1098 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1099 boffset, offset - boffset, value);
1100 PROTO_ITEM_SET_HIDDEN(hidden_item);
1104 if ( (props.value_id == -1) ||
1105 (tbl_types_wireshark[props.type] != FT_UINT32) )
1106 /* unknown or unexpected, just text */
1107 proto_tree_add_text(pt, tvb, boffset,
1109 "(%s)%s: %d:%s", tname, name, value, ename);
1111 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1112 offset - boffset, value,
1113 "(%s)%s: %d:%s ~", tname, name, value, ename);
1114 if (props.type_id != -1){
1115 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1116 boffset, offset - boffset, value);
1117 PROTO_ITEM_SET_HIDDEN(hidden_item);
1123 case BER_UNI_TAG_BOOLEAN:
1124 ret = asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1125 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1127 if ( (props.value_id == -1) ||
1128 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1129 /* unknown or unexpected, just text */
1130 proto_tree_add_text(pt, tvb, boffset,
1132 textfmt_s, boffset, clsstr, constr, tagstr,
1133 tname, name, value? "true" : "false", empty);
1135 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1136 offset - boffset, value != 0,
1137 textfmt_s, boffset, clsstr, constr, tagstr,
1138 tname, name, value? "true" : "false", matchind);
1139 if (props.type_id != -1){
1140 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1141 boffset, offset - boffset, value != 0);
1142 PROTO_ITEM_SET_HIDDEN(hidden_item);
1146 if ( (props.value_id == -1) ||
1147 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1148 /* unknown or unexpected, just text */
1149 proto_tree_add_text(pt, tvb, boffset,
1151 "(%s)%s: %s", tname, name,
1152 value? "true" : "false");
1154 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1155 offset - boffset, value != 0,
1156 "(%s)%s: %s ~", tname, name,
1157 value? "true" : "false");
1158 if (props.type_id != -1){
1159 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1160 boffset, offset - boffset, value != 0);
1161 PROTO_ITEM_SET_HIDDEN(hidden_item);
1167 case BER_UNI_TAG_OCTETSTRING:
1168 case BER_UNI_TAG_NumericString:
1169 case BER_UNI_TAG_PrintableString:
1170 case BER_UNI_TAG_TeletexString:
1171 case BER_UNI_TAG_IA5String:
1172 case BER_UNI_TAG_GeneralString:
1173 case BER_UNI_TAG_UTCTime:
1174 case BER_UNI_TAG_GeneralizedTime:
1175 /* read value, \0 terminated */
1176 ret = asn1_string_value_decode(&asn1, len, &octets);
1177 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1178 ename = showoctets(octets, len, (tag == BER_UNI_TAG_OCTETSTRING) ? 4 : 0 );
1180 if ( (props.value_id == -1) ||
1181 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1182 /* unknown or unexpected, just text */
1183 proto_tree_add_text(pt, tvb, boffset,
1185 textfmt_s, boffset, clsstr, constr, tagstr,
1186 tname, name, ename, empty);
1188 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1189 offset - boffset, octets, /* \0 termnated */
1190 textfmt_s, boffset, clsstr, constr, tagstr,
1191 tname, name, ename, matchind);
1192 if (props.type_id != -1){
1193 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1194 boffset, offset - boffset, octets);
1195 PROTO_ITEM_SET_HIDDEN(hidden_item);
1199 if ( (props.value_id == -1) ||
1200 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1201 /* unknown or unexpected, just text */
1202 proto_tree_add_text(pt, tvb, boffset,
1204 "(%s)%s: %s", tname, name, ename);
1206 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1207 offset - boffset, octets, /* \0 terminated */
1208 "(%s)%s: %s ~", tname, name, ename);
1209 if (props.type_id != -1){
1210 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1211 boffset, offset - boffset, octets);
1212 PROTO_ITEM_SET_HIDDEN(hidden_item);
1217 g_free( (gpointer) ename);
1220 case BER_UNI_TAG_BITSTRING:
1221 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1222 asn1_close(&asn1, &offset); /* mark where we are now */
1223 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1225 if ( (props.value_id == -1) ||
1226 (tbl_types_wireshark[props.type] != FT_UINT32) )
1227 /* unknown or unexpected, just text */
1228 proto_tree_add_text(pt, tvb, boffset,
1230 textfmt_b, boffset, clsstr, constr, tagstr,
1232 showbits(bits, (con*8)-unused), ename, empty);
1234 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1235 offset - boffset, *bits, /* XXX length ? XXX */
1236 textfmt_b, boffset, clsstr, constr, tagstr,
1238 showbits(bits, (con*8)-unused),ename, matchind);
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);
1247 if ( (props.value_id == -1) ||
1248 (tbl_types_wireshark[props.type] != FT_UINT32) )
1249 /* unknown or unexpected, just text */
1250 proto_tree_add_text(pt, tvb, boffset,
1252 "(%s)%s: %s:%s", tname, name,
1253 showbits(bits, (con*8)-unused), ename);
1255 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1256 offset - boffset, *bits, /* XXX length ? XXX */
1257 "(%s)%s: %s:%s ~", tname, name,
1258 showbits(bits, (con*8)-unused), ename);
1259 if (props.type_id != -1){
1260 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1261 boffset, offset - boffset, *bits);
1262 PROTO_ITEM_SET_HIDDEN(hidden_item);
1269 case BER_UNI_TAG_SET:
1270 case BER_UNI_TAG_SEQUENCE:
1271 /* show full sequence length */
1274 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1276 if ( (props.flags & OUT_FLAG_constructed))
1277 ename = ", unexpected constructed";
1279 if (props.value_id == -1)
1280 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1281 textfmt_c, boffset, clsstr, constr, tagstr,
1282 tname, name, ename, empty);
1284 ti = proto_tree_add_item(pt, props.value_id, tvb,
1286 /* change te text to to what I really want */
1287 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1288 tagstr, tname, name, ename, matchind);
1289 if (props.type_id != -1){
1290 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1292 PROTO_ITEM_SET_HIDDEN(hidden_item);
1296 if (props.value_id == -1) {
1297 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1298 ti = proto_tree_add_text(pt, tvb, boffset,
1299 offset - boffset + len,
1300 "(%s)%s", tname, name);
1302 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1303 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1304 boffset, offset - boffset + len,
1305 "(%s)%s ~", tname, name);
1307 /* don't care about the text */
1308 ti = hidden_item = proto_tree_add_item(pt, props.value_id, tvb,
1310 PROTO_ITEM_SET_HIDDEN(hidden_item);
1312 if (props.type_id != -1){
1313 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1315 PROTO_ITEM_SET_HIDDEN(hidden_item);
1319 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1321 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1322 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1326 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1328 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1329 proto_item_set_len(ti, offset - boffset);
1333 case BER_UNI_TAG_EOC:
1334 if (asn1_debug) { /* don't show if not debugging */
1335 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1336 boffset, clsstr, constr, tagstr, tname, name,
1337 offset - soffset, empty);
1339 getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1342 case BER_UNI_TAG_OID:
1343 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1344 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1345 ename = showoid(oid, con);
1347 if ( (props.value_id == -1) ||
1348 (tbl_types_wireshark[props.type] != FT_BYTES) )
1349 /* unknown or unexpected, just text */
1350 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1351 boffset, clsstr, constr, tagstr, tname, name,
1354 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1355 offset - boffset, ename,/* XXX length?*/
1356 "(%s)%s: %s ~", tname, name, ename);
1357 if (props.type_id != -1){
1358 hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1359 boffset, offset - boffset, ename);
1360 PROTO_ITEM_SET_HIDDEN(hidden_item);
1364 if ( (props.value_id == -1) ||
1365 (tbl_types_wireshark[props.type] != FT_BYTES) )
1366 /* unknown or unexpected, just text */
1367 proto_tree_add_text(pt, tvb, boffset,
1369 "(%s)%s: %s", tname, name, ename);
1371 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1372 offset - boffset, ename, /* XXX length ? */
1373 "(%s)%s: %s ~", tname, name, ename);
1374 if (props.type_id != -1){
1375 hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1376 boffset, offset - boffset, ename);
1377 PROTO_ITEM_SET_HIDDEN(hidden_item);
1384 case BER_UNI_TAG_NULL:
1386 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1387 boffset, clsstr, constr, tagstr, tname, name,
1390 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1391 "(%s)%s: [NULL]", tname, name);
1393 offset += len; /* skip value ... */
1396 case BER_UNI_TAG_ObjectDescriptor:
1398 case BER_UNI_TAG_REAL:
1399 case BER_UNI_TAG_VideotexString:
1400 case BER_UNI_TAG_GraphicString:
1401 case BER_UNI_TAG_VisibleString:
1405 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1406 textfmt_s, boffset, clsstr, constr, tagstr,
1407 tname, name, lenbuf, empty);
1409 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1410 "(%s)%s: %s bytes", tname, name, lenbuf);
1412 proto_item_append_text(ti, " *"); /* indicate default is used */
1413 offset += len; /* skip value ... */
1418 case BER_CLASS_CON: /* fprintf(stderr, "Context\n"); */
1419 case BER_CLASS_APP: /* fprintf(stderr, "Application\n"); */
1420 case BER_CLASS_PRI: /* fprintf(stderr, "Private\n"); */
1423 if (props.value_id == -1) /* type unknown, handle as string */
1425 switch(props.type) {
1426 /* this is via the asn1 description, don't trust the length */
1430 ret = asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
1431 asn1_close(&asn1, &offset); /* mark where we are now */
1433 if ( (props.value_id == -1) ||
1434 (tbl_types_wireshark[props.type] != FT_UINT32) )
1435 /* unknown or unexpected, just text */
1436 proto_tree_add_text(pt, tvb,
1437 boffset, offset - boffset,
1438 textfmt_d, boffset, clsstr, constr,
1439 tagstr, tname, name, value, empty);
1441 proto_tree_add_uint_format(pt, props.value_id, tvb,
1442 boffset, offset - boffset, value,
1443 textfmt_d, boffset, clsstr, constr,
1444 tagstr, tname, name, value, matchind);
1445 if (props.type_id != -1){
1446 hidden_item = proto_tree_add_uint(pt, props.type_id,
1447 tvb, boffset, offset - boffset, value);
1448 PROTO_ITEM_SET_HIDDEN(hidden_item);
1452 if ( (props.value_id == -1) ||
1453 (tbl_types_wireshark[props.type] != FT_UINT32) )
1454 /* unknown or unexpected, just text */
1455 proto_tree_add_text(pt, tvb,
1456 boffset, offset - boffset,
1457 "(%s)%s: %d", tname, name, value);
1459 proto_tree_add_uint_format(pt, props.value_id, tvb,
1460 boffset, offset - boffset, value,
1461 "(%s)%s: %d ~", tname, name, value);
1462 if (props.type_id != -1){
1463 hidden_item = proto_tree_add_uint(pt, props.type_id,
1464 tvb, boffset, offset - boffset, value);
1465 PROTO_ITEM_SET_HIDDEN(hidden_item);
1471 case TBL_ENUMERATED:
1474 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1475 asn1_close(&asn1, &offset); /* mark where we are now */
1476 ename = getPDUenum(&props, boffset, cls, tag, value);
1478 if ( (props.value_id == -1) ||
1479 (tbl_types_wireshark[props.type] != FT_UINT32) )
1480 /* unknown or unexpected, just text */
1481 proto_tree_add_text(pt, tvb,
1482 boffset, offset - boffset,
1483 textfmt_e, boffset, clsstr, constr,
1484 tagstr, tname, name, value, ename, empty);
1486 proto_tree_add_uint_format(pt, props.value_id, tvb,
1487 boffset, offset - boffset, value,
1488 textfmt_e, boffset, clsstr, constr,
1489 tagstr, tname, name, value, ename, matchind);
1490 if (props.type_id != -1){
1491 hidden_item = proto_tree_add_uint(pt, props.type_id,
1492 tvb, boffset, offset - boffset, value);
1493 PROTO_ITEM_SET_HIDDEN(hidden_item);
1497 if ( (props.value_id == -1) ||
1498 (tbl_types_wireshark[props.type] != FT_UINT32) )
1499 /* unknown or unexpected, just text */
1500 proto_tree_add_text(pt, tvb,
1501 boffset, offset - boffset,
1502 "(%s)%s: %d:%s", tname, name, value, ename);
1504 proto_tree_add_uint_format(pt, props.value_id, tvb,
1505 boffset, offset - boffset, value,
1506 "(%s)%s: %d:%s ~", tname, name, value, ename);
1507 if (props.type_id != -1){
1508 hidden_item = proto_tree_add_uint(pt, props.type_id,
1509 tvb, boffset, offset - boffset, value);
1510 PROTO_ITEM_SET_HIDDEN(hidden_item);
1516 if (len > (1+4)) /* max 32 bits ...?.. */
1519 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1520 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1521 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1523 if ( (props.value_id == -1) ||
1524 (tbl_types_wireshark[props.type] != FT_UINT32) )
1525 /* unknown or unexpected, just text */
1526 proto_tree_add_text(pt, tvb,
1527 boffset, offset - boffset,
1528 textfmt_b, boffset, clsstr, constr,
1529 tagstr, tname, name,
1530 showbits(bits, (con*8)-unused), ename,
1533 proto_tree_add_uint_format(pt, props.value_id, tvb,
1534 boffset, offset - boffset, *bits,
1535 textfmt_b, boffset, clsstr, constr,
1536 tagstr, tname, name,
1537 showbits(bits, (con*8)-unused), ename,
1539 if (props.type_id != -1){
1540 hidden_item = proto_tree_add_uint(pt, props.type_id,
1541 tvb, boffset, offset - boffset, *bits);
1542 PROTO_ITEM_SET_HIDDEN(hidden_item);
1546 if ( (props.value_id == -1) ||
1547 (tbl_types_wireshark[props.type] != FT_UINT32) )
1548 /* unknown or unexpected, just text */
1549 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1550 "(%s)%s: %s:%s", tname, name,
1551 showbits(bits, (con*8)-unused), ename);
1553 proto_tree_add_uint_format(pt, props.value_id, tvb,
1554 boffset, offset - boffset, *bits,
1555 "(%s)%s: %s:%s ~", tname, name,
1556 showbits(bits, (con*8)-unused), ename);
1557 if (props.type_id != -1){
1558 hidden_item = proto_tree_add_uint(pt, props.type_id,
1559 tvb, boffset, offset - boffset, *bits);
1560 PROTO_ITEM_SET_HIDDEN(hidden_item);
1569 ret = asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1570 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1572 if ( (props.value_id == -1) ||
1573 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1574 /* unknown or unexpected, just text */
1575 proto_tree_add_text(pt, tvb,
1576 boffset, offset - boffset,
1577 textfmt_s, boffset, clsstr, constr,
1578 tagstr, tname, name,
1579 value? "true" : "false", empty);
1581 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1582 boffset, offset - boffset, value != 0,
1583 textfmt_s, boffset, clsstr, constr,
1584 tagstr, tname, name,
1585 value? "true" : "false", matchind);
1586 if (props.type_id != -1){
1587 hidden_item = proto_tree_add_boolean(pt, props.type_id,
1588 tvb, boffset, offset - boffset, value != 0);
1589 PROTO_ITEM_SET_HIDDEN(hidden_item);
1593 if ( (props.value_id == -1) ||
1594 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1595 /* unknown or unexpected, just text */
1596 proto_tree_add_text(pt, tvb,
1597 boffset, offset - boffset,
1598 "(%s)%s: %s", tname, name,
1599 value? "true" : "false");
1601 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1602 boffset, offset - boffset, value != 0,
1603 "(%s)%s: %s ~", tname, name,
1604 value? "true" : "false");
1605 if (props.type_id != -1){
1606 hidden_item = proto_tree_add_boolean(pt, props.type_id,
1607 tvb, boffset, offset - boffset, value != 0);
1608 PROTO_ITEM_SET_HIDDEN(hidden_item);
1617 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1618 textfmt_s, boffset, clsstr, constr,
1619 tagstr, tname, name, "[NULL]", empty);
1621 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1622 "(%s)%s: [NULL]", tname, name);
1624 offset += len; /* skip value ... */
1628 props.value_id = -1; /* unlikely this is correct, dont use it */
1630 case TBL_OCTETSTRING:
1631 /* defined length, not constructed, must be a string.... */
1632 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1633 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1634 ename = showoctets(octets, len, 2); /* convert octets to printable */
1636 if ( (props.value_id == -1) ||
1637 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1638 /* unknown or unexpected, just text */
1639 proto_tree_add_text(pt, tvb,
1640 boffset, offset - boffset,
1641 textfmt_s, boffset, clsstr, constr,
1642 tagstr, tname, name, ename, empty);
1644 proto_tree_add_string_format(pt, props.value_id, tvb,
1645 boffset, offset - boffset, (gchar *)octets, /* XXX */
1646 textfmt_s, boffset, clsstr, constr,
1647 tagstr, tname, name, ename, matchind);
1648 if (props.type_id != -1){
1649 hidden_item = proto_tree_add_string(pt, props.type_id,
1650 tvb, boffset, offset - boffset, (gchar *)octets);
1651 PROTO_ITEM_SET_HIDDEN(hidden_item);
1655 if ( (props.value_id == -1) ||
1656 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1657 /* unknown or unexpected, just text */
1658 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1659 "(%s)%s: %s", tname, name, ename);
1661 proto_tree_add_string_format(pt, props.value_id, tvb,
1662 boffset, offset - boffset, (gchar *)octets, /* XXX */
1663 "(%s)%s: %s ~", tname, name, ename);
1664 if (props.type_id != -1){
1665 hidden_item = proto_tree_add_string(pt, props.type_id,
1666 tvb, boffset, offset - boffset, (gchar *)octets);
1667 PROTO_ITEM_SET_HIDDEN(hidden_item);
1672 g_free( (gpointer) ename);
1676 /* indefinite length or constructed.... must be a sequence .... */
1677 /* show full sequence length */
1680 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1682 if ( (props.flags & OUT_FLAG_constructed))
1683 ename = ", unexpected constructed";
1685 if (props.value_id == -1)
1686 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1687 textfmt_c, boffset, clsstr, constr,
1688 tagstr, tname, name, ename, empty);
1690 ti = proto_tree_add_item(pt, props.value_id, tvb,
1692 /* change te text to to what I really want */
1694 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1695 tagstr, tname, name, ename, matchind);
1696 if (props.type_id != -1){
1697 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1699 PROTO_ITEM_SET_HIDDEN(hidden_item);
1702 ti = proto_tree_add_text(pt, tvb, boffset,
1703 offset - boffset + len,
1704 textfmt_c, boffset, clsstr, constr,
1705 tagstr, tname, name, ename, empty);
1709 if (props.value_id == -1) {
1710 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1711 ti = proto_tree_add_text(pt, tvb, boffset,
1712 offset - boffset + len, "(%s)%s", tname, name);
1714 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1715 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1717 "(%s)%s ~", tname, name);
1719 /* don't care about the text */
1720 ti = proto_tree_add_item(pt, props.value_id,
1721 tvb, boffset, 1, TRUE);
1722 PROTO_ITEM_SET_HIDDEN(ti);
1724 if (props.type_id != -1){
1725 hidden_item = proto_tree_add_item(pt, props.type_id,
1726 tvb, boffset, 1, TRUE);
1727 PROTO_ITEM_SET_HIDDEN(hidden_item);
1732 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1734 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1735 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1739 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1741 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1742 proto_item_set_len(ti, offset - boffset);
1746 default: /* fprintf(stderr, "Other\n"); */
1748 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1749 textfmt_s, boffset, clsstr, constr, tagstr,
1750 tname, name, lenbuf, empty);
1752 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1753 "(%s)%s: %s bytes %s data", tname, name,
1756 proto_item_append_text(ti, " *"); /* indicate default is used */
1757 offset += len; /* skip value ... */
1760 g_free(oname); /* XXX, memory management ? */
1762 /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1764 getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1771 /************************************************************************************************/
1772 /* search throug the ASN.1 description for appropriate names */
1773 /************************************************************************************************/
1775 guint lev_limit = G_MAXINT;
1777 int icount = 0; /* item counter */
1780 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1783 guint eos, cls, con, tag, len, value;
1785 guchar *octets, *bits, unused;
1787 GNode *cur_node = 0;
1789 eos = offset + size;
1791 if (level > lev_limit)
1794 while(offset < eos) {
1795 if (ptr) /* build pointer tree to all asn1 entities */
1796 cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
1798 asn1_open(&asn1, tvb, offset);
1799 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1800 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
1803 len = tvb_length_remaining(tvb, offset);
1807 case BER_CLASS_UNI: /* fprintf(stderr, "Universal\n"); */
1809 case BER_UNI_TAG_INTEGER:
1810 case BER_UNI_TAG_ENUMERATED:
1811 asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
1812 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
1815 case BER_UNI_TAG_BOOLEAN:
1816 asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1817 asn1_close(&asn1, &offset); /* mark where we are */
1820 case BER_UNI_TAG_OCTETSTRING:
1821 case BER_UNI_TAG_NumericString:
1822 case BER_UNI_TAG_PrintableString:
1823 case BER_UNI_TAG_TeletexString:
1824 case BER_UNI_TAG_IA5String:
1825 case BER_UNI_TAG_GeneralString:
1826 case BER_UNI_TAG_UTCTime:
1827 case BER_UNI_TAG_GeneralizedTime:
1828 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1829 asn1_close(&asn1, &offset); /* mark where we are */
1833 case BER_UNI_TAG_BITSTRING:
1834 asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1835 asn1_close(&asn1, &offset); /* mark where we are */
1839 case BER_UNI_TAG_SET:
1840 case BER_UNI_TAG_SEQUENCE:
1841 if (len == 0) /* don't recurse if offset isn't going to change */
1844 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1847 case BER_UNI_TAG_EOC:
1850 case BER_UNI_TAG_OID:
1851 asn1_oid_value_decode(&asn1, len, &oid, &con);
1852 asn1_close(&asn1, &offset); /* mark where we are */
1856 case BER_UNI_TAG_NULL:
1860 case BER_UNI_TAG_ObjectDescriptor:
1862 case BER_UNI_TAG_REAL:
1863 case BER_UNI_TAG_VideotexString:
1864 case BER_UNI_TAG_GraphicString:
1865 case BER_UNI_TAG_VisibleString:
1868 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1869 offset += len; /* skip value ... */
1874 case BER_CLASS_CON: /* fprintf(stderr, "Context\n"); */
1876 /* defined length, not constructed, must be a string.... */
1877 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1878 asn1_close(&asn1, &offset); /* mark where we are */
1881 /* indefinite length or constructed.... must be a sequence .... */
1882 if (len == 0) /* don't recurse if offset isn't going to change */
1885 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1889 default: /* fprintf(stderr, "Other\n"); */
1890 if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1891 offset += len; /* skip value ... */
1898 static void showGNodes(GNode *p, int n);
1902 myLeaf(GNode *node, gpointer data)
1905 guint ret, cls, con, tag, def, len;
1906 char *clsstr, *constr, *tagstr;
1910 (void) data; /* make a reference */
1911 asn1_open(&asn1, asn1_desc, (int)node->data);
1913 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1915 clsstr = asn1_cls[cls];
1916 constr = asn1_con[con];
1917 if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
1918 tagstr = asn1_tag[tag];
1920 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1924 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1926 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1930 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1938 if (asn1_verbose) g_message("build GNode tree:");
1939 showGNodes(g_node_first_child(asn1_nodes), 0);
1940 if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1941 g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1942 g_node_max_height (asn1_nodes),
1943 g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1944 g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1946 g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1952 tt_build_tree(void) /* build a GNode tree with all offset's to ASN.1 entities */
1955 g_node_destroy(asn1_nodes);
1956 asn1_nodes = g_node_new(0);
1958 parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1962 /*****************************************************************************************************/
1964 static guint anonCount; /* for naming anonymous types */
1966 typedef struct _TBLModule TBLModule;
1967 typedef struct _TBLTypeDef TBLTypeDef;
1968 typedef struct _TBLTag TBLTag;
1969 typedef struct _TBLType TBLType;
1970 typedef struct _TBLTypeRef TBLTypeRef;
1971 typedef struct _TBLNamedNumber TBLNamedNumber;
1972 typedef struct _TBLRange TBLRange;
1980 TBLTYPE_NamedNumber,
1983 typedef enum _tbl_t tbl_t;
1984 /* text for 'tbl_t' type for debugging */
1985 static const char *data_types[] = {
1995 enum _TBLTypeContent_t {
1997 TBLTYPETYPE_Primitive,
1998 TBLTYPETYPE_Elements,
2001 typedef enum _TBLTypeContent_t TBLTypeContent_t;
2003 struct _TBLNamedNumber {
2015 struct _TBLTypeRef {
2031 TBLTypeContent_t content;
2034 gboolean constraint;
2037 struct _TBLTypeDef {
2052 guint totalNumModules;
2053 guint totalNumTypeDefs;
2054 guint totalNumTypes;
2056 guint totalNumStrings;
2057 guint totalLenStrings;
2060 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2063 get_asn1_int(guint want_tag, guint offset)
2066 guint ret, cls, con, tag, len;
2070 /* g_message("%d get_asn1_int", offset); */
2072 asn1_open(&asn1, asn1_desc, offset);
2074 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2075 if (ret == ASN1_ERR_NOERROR) {
2076 /* do not check class, both Unversal and Context are OK */
2077 if (con == ASN1_PRI && tag == want_tag) {
2079 asn1_uint32_value_decode(&asn1, len, &value);
2082 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2084 ret = ASN1_ERR_WRONG_TYPE;
2086 g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2091 static subid_t * /* with prepended length ..... */
2092 get_asn1_oid(guint want_tag, guint offset)
2095 guint ret, cls, con, tag, len;
2099 /* g_message("%d get_asn1_oid", offset); */
2101 asn1_open(&asn1, asn1_desc, offset);
2103 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2104 if (ret == ASN1_ERR_NOERROR) {
2105 /* do not check class, both Unversal and Context are OK */
2106 if ((con == ASN1_PRI) && (tag == want_tag)) {
2108 asn1_oid_value_decode(&asn1, len, &oid, &con);
2109 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2110 memmove(&oid[1], oid, con*sizeof(guint));
2114 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2116 ret = ASN1_ERR_WRONG_TYPE;
2118 g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2123 static guchar * /* 0 terminated string */
2124 get_asn1_string(guint want_tag, guint offset)
2127 guint ret, cls, con, tag, len;
2131 /* g_message("%d get_asn1_string", offset); */
2133 asn1_open(&asn1, asn1_desc, offset);
2135 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2136 if (ret == ASN1_ERR_NOERROR) {
2137 /* do not check class, both Unversal and Context are OK */
2138 if ((con == ASN1_PRI) && (tag == want_tag)) {
2140 asn1_string_value_decode(&asn1, len, &octets);
2141 octets = g_realloc(octets, len+1); /* need space for sentinel */
2145 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2147 ret = ASN1_ERR_WRONG_TYPE;
2149 g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2155 get_asn1_uint(guint offset)
2158 guint ret, len, value;
2160 /* g_message( "%d get_asn1_uint", offset); */
2162 asn1_open(&asn1, asn1_desc, offset);
2164 ret = asn1_uint32_decode(&asn1, &value, &len);
2166 if (ret != ASN1_ERR_NOERROR) {
2167 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2174 check_tag(guint want_tag, guint offset)
2177 guint ret, cls, con, tag, len;
2180 asn1_open(&asn1, asn1_desc, offset);
2182 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2183 if (ret == ASN1_ERR_NOERROR) {
2184 ret = (tag == want_tag) ? TRUE : FALSE;
2185 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2188 g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2195 constructed(guint offset)
2198 guint ret, cls, con, tag, def, len;
2200 /* g_message("%d constructed?", offset); */
2202 asn1_open(&asn1, asn1_desc, offset);
2204 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2205 if (ret == ASN1_ERR_NOERROR) {
2211 /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2218 define_constraint(GNode *p, GNode *q)
2220 TBLRange *range = g_malloc(sizeof(TBLRange));
2221 g_node_append_data(q, range);
2223 range->type = TBLTYPE_Range;
2225 /* g_message("define_constraint %p, %p", p, q); */
2227 p = g_node_first_child(p);
2233 range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2234 p = g_node_next_sibling(p);
2240 range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2245 define_namednumber(GNode *p, GNode *q)
2247 TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2248 g_node_append_data(q, num);
2250 num->type = TBLTYPE_NamedNumber;
2252 /* g_message("define_namednumber %p, %p", p, q); */
2254 p = g_node_first_child(p);
2260 num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2261 p = g_node_next_sibling(p);
2267 num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2271 define_typeref(GNode *p, GNode *q)
2273 TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2274 g_node_append_data(q, ref);
2276 ref->type = TBLTYPE_TypeRef;
2278 /* g_message("define_typeref %p, %p", p, q); */
2280 p = g_node_first_child(p);
2286 ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2287 p = g_node_next_sibling(p);
2293 ref->implicit = get_asn1_int(BER_UNI_TAG_BOOLEAN, GPOINTER_TO_UINT(p->data));
2297 define_tag(GNode *p, GNode *q)
2299 TBLTag *type = g_malloc(sizeof(TBLTag));
2300 g_node_append_data(q, type);
2302 type->type = TBLTYPE_Tag;
2304 /* g_message("define_tag %p, %p", p, q); */
2306 p = g_node_first_child(p);
2312 type->tclass = get_asn1_int(BER_UNI_TAG_ENUMERATED, GPOINTER_TO_UINT(p->data));
2313 p = g_node_next_sibling(p);
2319 type->code = get_asn1_int(BER_UNI_TAG_INTEGER, GPOINTER_TO_UINT(p->data));
2324 define_type(GNode *p, GNode *q)
2327 TBLType *type = g_malloc(sizeof(TBLType));
2329 GNode *t = g_node_append_data(q, type);
2331 type->type = TBLTYPE_Type;
2333 /* g_message("define_type %p, %p", p, q); */
2335 type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2336 p = g_node_next_sibling(p);
2338 type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2339 p = g_node_next_sibling(p);
2341 if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
2342 r = g_node_first_child(p);
2345 r = g_node_next_sibling(r);
2347 p = g_node_next_sibling(p);
2350 if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
2351 g_warning("expect tag 3, ERROR");
2353 r = g_node_first_child(p);
2355 type->content = TBLTYPETYPE_None;
2356 if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
2357 if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
2358 if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
2359 switch(type->content) {
2360 case TBLTYPETYPE_Primitive:
2362 case TBLTYPETYPE_Elements:
2363 r = g_node_first_child(r);
2365 define_type(g_node_first_child(r), t);
2366 r = g_node_next_sibling(r);
2369 case TBLTYPETYPE_TypeRef:
2370 define_typeref(r, t);
2372 case TBLTYPETYPE_None:
2373 g_warning("expected a contents choice, error");
2376 p = g_node_next_sibling(p);
2378 type->fieldName = 0;
2379 type->anonymous = FALSE;
2380 if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
2381 type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
2382 p = g_node_next_sibling(p);
2384 type->anonymous = TRUE;
2387 type->constraint = FALSE;
2388 if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
2389 type->constraint = TRUE;
2390 define_constraint(p, t);
2391 p = g_node_next_sibling(p);
2394 if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
2395 r = g_node_first_child(p);
2397 define_namednumber(r, t);
2398 r = g_node_next_sibling(r);
2404 define_typedef(GNode *p, GNode *q)
2406 TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2408 GNode *t = g_node_append_data(q, type_def);
2410 /* g_message("define_typedef %p, %p", p, q); */
2412 type_def->type = TBLTYPE_TypeDef;
2414 p = g_node_first_child(p);
2420 type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2421 p = g_node_next_sibling(p);
2427 type_def->typeName = get_asn1_string(BER_UNI_TAG_PrintableString, GPOINTER_TO_UINT(p->data));
2428 p = g_node_next_sibling(p);
2434 define_type(g_node_first_child(p), t);
2435 p = g_node_next_sibling(p);
2437 type_def->isPdu = (p != 0); /* true if it exists, value ignored */
2441 define_module(GNode *p, GNode *q)
2443 TBLModule *module = g_malloc(sizeof(TBLModule));
2445 GNode *m = g_node_append_data(q, module);
2447 /* g_message("define_module %p %p", p, q); */
2449 module->type = TBLTYPE_Module;
2451 p = g_node_first_child(p);
2457 module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2458 p = g_node_next_sibling(p);
2461 if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */
2462 module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
2463 p = g_node_next_sibling(p);
2466 module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
2467 p = g_node_next_sibling(p);
2469 p = g_node_first_child(p);
2471 define_typedef(p, m);
2472 p = g_node_next_sibling(p);
2476 typedef struct _SearchDef SearchDef;
2483 is_typedef(GNode *node, gpointer data)
2485 TBLTypeDef *d = (TBLTypeDef *)node->data;
2486 SearchDef *s = (SearchDef *)data;
2488 if (d == 0) return FALSE;
2489 if (d->type != TBLTYPE_TypeDef) return FALSE;
2490 if (strcmp(s->key, d->typeName) == 0) {
2497 typedef struct _TypeRef TypeRef;
2503 GNode *pdu; /* location in PDU descriptor tree */
2504 guint level; /* recursion counter */
2506 GPtrArray *refs; /* pointers to PDUinfo structures teferencing this entry */
2509 typedef struct _NameDefs NameDefs;
2515 #define ALLOC_INCR 4
2516 #define CLASSREF (BER_CLASS_PRI+1)
2519 is_named(GNode *node, gpointer data)
2521 TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2522 NameDefs *n = (NameDefs *)data;
2525 if (num == 0) return FALSE;
2526 if (num->type != TBLTYPE_NamedNumber) return FALSE;
2528 if (num->value >= n->max) { /* need larger array */
2530 n->max = num->value + ALLOC_INCR;
2531 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2532 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2534 if (num->value > n->used) /* track max used value, there may be holes... */
2535 n->used = num->value;
2537 n->info[num->value].name = num->name;
2543 index_typedef(GNode *node, gpointer data)
2545 TBLTypeDef *d = (TBLTypeDef *)node->data;
2546 NameDefs *n = (NameDefs *)data;
2551 if (d == 0) return FALSE;
2552 if (d->type != TBLTYPE_TypeDef) return FALSE;
2554 if (d->typeDefId >= n->max) { /* need larger array */
2556 n->max = d->typeDefId + ALLOC_INCR;
2557 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2558 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2560 if (d->typeDefId > n->used) /* track max used value, there may be holes... */
2561 n->used = d->typeDefId;
2563 t = &(n->info[d->typeDefId]);
2564 t->name = d->typeName;
2566 t->refs = g_ptr_array_new(); /* collect references here */
2567 node = g_node_first_child(node); /* the real type */
2568 tag = (TBLTag *)node->data;
2569 if ((tag->type == TBLTYPE_Type) && (((TBLType *)(void *)tag)->typeId == TBL_CHOICE)) {
2570 /* no reasonable default... ! */
2571 t->defclass = 3; /* Private .... */
2572 t->deftag= 9999; /* a random value */
2574 node = g_node_first_child(node); /* the default tag */
2575 tag = (TBLTag *)node->data;
2578 t->defclass = tag->tclass;
2579 t->deftag = tag->code;
2581 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2582 t->defclass = CLASSREF; /* invalid class.. */
2583 t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2586 g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2587 data_types[tag->type]);
2588 t->defclass = 3; /* Private .... */
2589 t->deftag= 9998; /* another random value */
2597 static TypeRef *typeDef_names = 0;
2598 static guint numTypedefs = 0;
2601 free_node_data(GNode *node, gpointer data _U_)
2608 get_values(void) /* collect values from ASN.1 tree */
2609 /* coded according to the tbl.asn1 description of snacc output */
2610 { /* This routine does not leave references to the tvbuff or */
2611 /* to the asn1_nodes, both can be freed by the caller of this.*/
2617 const char *t, *s, *E;
2618 static char missing[] = " **missing** ";
2620 if (asn1_verbose) g_message("interpreting tree");
2621 typeDef_names = 0; /* just forget allocated any data .... */
2624 g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2625 free_node_data, NULL);
2626 g_node_destroy(data_nodes);
2629 data_nodes = g_node_new(0);
2631 p = g_node_first_child(asn1_nodes); /* top of the data tree */
2633 p = g_node_first_child(p);
2635 TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2636 p = g_node_next_sibling(p);
2638 TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2639 p = g_node_next_sibling(p);
2641 TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2642 p = g_node_next_sibling(p);
2644 TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2645 p = g_node_next_sibling(p);
2647 TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2648 p = g_node_next_sibling(p);
2650 TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2651 p = g_node_next_sibling(p);
2653 p = g_node_first_child(p);
2655 define_module(p, data_nodes);
2656 p = g_node_next_sibling(p);
2659 /* g_message("finished with tree"); */
2661 if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2662 sd.key = "TBLTypeId";
2664 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2665 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", (void *)sd.here);
2669 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2670 g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2672 if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, (void *)nd.info);
2674 for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2677 s = nd.info[i].name;
2678 if (s == 0) s = missing;
2679 if (g_strcmp(t, s) == 0) { /* OK ! */
2683 E = ", X with errors X";
2685 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2687 if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2689 tbl_types_verified = TRUE;
2691 /* build table with typedef names */
2694 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2695 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2696 if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, (void *)nd.info);
2698 for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2699 TypeRef *ref = &(nd.info[i]);
2702 t = ref->name = missing;
2703 if (asn1_verbose) g_message(" %3d %s", i, t);
2705 if (asn1_verbose) g_message(" %3d %s, %c%d", i, t,
2706 tag_class[ref->defclass], ref->deftag);
2708 if (ref->pdu) { /* should be 0 */
2709 if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, (void *)ref->pdu);
2712 typeDef_names = nd.info;
2714 if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
2719 showGNode(GNode *p, int n)
2722 const char *fn, *s = empty;
2724 n *=2; /* 2 spaces per level */
2725 if (p->data) { /* show value ... */
2726 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
2727 switch (((TBLTag *)p->data)->type) {
2728 case TBLTYPE_Module: {
2729 TBLModule *m = (TBLModule *)p->data;
2731 g_message("%*smodule %s%s", n, empty, m->name,
2732 m->isUseful ? ", useful" : empty);
2735 case TBLTYPE_TypeDef: {
2736 TBLTypeDef *t = (TBLTypeDef *)p->data;
2738 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
2739 t->isPdu ? ", isPDU" : empty);
2742 case TBLTYPE_Type: {
2743 TBLType *t = (TBLType *)p->data;
2746 /* typeId is a value from enum TBLTypeId */
2747 fn = TBLTYPE(t->typeId);
2748 if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
2749 t->optional ? " opt" : empty, s );
2753 TBLTag *t = (TBLTag *)p->data;
2754 if ((t->tclass == BER_CLASS_UNI) && (t->code < 32))
2755 s = asn1_tag[t->code];
2756 if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
2757 tag_class[t->tclass], t->code, s);
2760 case TBLTYPE_NamedNumber: {
2761 TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
2762 if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
2763 nn->value, nn->name);
2766 case TBLTYPE_Range: {
2767 TBLRange *r = (TBLRange *)p->data;
2768 if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
2772 case TBLTYPE_TypeRef: {
2773 TBLTypeRef *r = (TBLTypeRef *)p->data;
2775 s = typeDef_names[r->typeDefId].name;
2776 if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
2777 r->typeDefId, s, r->implicit ? ", implicit" : empty );
2781 TBLTag *x = (TBLTag *)p->data;
2782 if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
2786 } else { /* just show tree */
2788 g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
2789 n, empty, (void *)p, (void *)p->data, (void *)p->next, (void *)p->prev, (void *)p->parent, (void *)p->children);
2794 showGNodes(GNode *p, int n)
2798 showGNodes(p->children, n+1);
2799 showGNodes(p->next, n);
2803 static void showGenv(GNode *p, int n, int m)
2809 if (asn1_verbose) g_message("%*s.....", n*2, empty);
2813 for(i=0; p && (i < 3); p = p->next, i++) {
2815 showGenv(p->children, n+1, m);
2817 if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
2823 debug_dump_TT(void) /* dump contents of TT struct, for debugging */
2826 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
2828 TT.totalNumTypeDefs,
2832 TT.totalLenStrings);
2836 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
2837 const gchar *message, gpointer user_data)
2839 static FILE* logf = 0;
2840 static char eol[] = "\r\n";
2842 (void) log_domain; (void) log_level; (void) user_data; /* make references */
2844 if (logf == NULL && asn1_logfile) {
2845 logf = ws_fopen(asn1_logfile, "w");
2848 fputs(message, logf);
2850 fflush(logf); /* debugging ... */
2855 read_asn1_type_table(const char *filename)
2860 struct stat file_stat;
2861 static guint mylogh = 0;
2863 if ((filename == 0) || (strlen(filename) == 0))
2864 return; /* no filename provided */
2866 f = ws_fopen(filename, "rb");
2869 * Ignore "file not found" errors if it's the old default
2870 * ASN.1 file name, as we never shipped such a file.
2871 * Also, on Win32, ignore the earlier default, which
2872 * had a "/" rather than a "\" as the last pathname
2876 if (strcmp(filename, bad_separator_old_default_asn1_filename) != 0)
2878 if ((strcmp(filename, old_default_asn1_filename) != 0) || errno != ENOENT)
2879 report_open_failure(filename, errno, FALSE);
2882 fstat(fileno(f), &file_stat);
2883 size = (int)file_stat.st_size;
2885 if (asn1_verbose) g_message("file %s is empty, ignored", filename);
2889 if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
2891 data = g_malloc(size);
2892 if (fread(data, size, 1, f) < 1) {
2893 g_warning("error reading %s, %s", filename, g_strerror(errno));
2898 /* ***** from the time when logging was just in a console... *****
2899 * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
2900 * " Sleep 5 sec...");
2905 g_message("logging to file %s", asn1_logfile);
2908 mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2909 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
2913 asn1_desc = tvb_new_real_data(data, size, size);
2916 if (asn1_verbose) g_message("read %d items from %s", icount, filename);
2924 g_node_destroy(asn1_nodes);
2927 tvb_free(asn1_desc);
2933 showGNodes(data_nodes, 0);
2939 /* XXX - Shoudn't we make sure we're not dereferencing a NULL pointer here? */
2940 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
2941 g_warning("**** unexpected type %s, want %s, at line %d", \
2942 data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
2946 save_reference(PDUinfo *p)
2953 g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
2957 tbl_type(gint n, GNode *pdu, GNode *list, guint fullindex);
2961 /* evaluate typeref, pointer to current pdu node and typedef */
2963 tbl_typeref(gint n, GNode *pdu, GNode *tree, guint fullindex)
2966 PDUinfo *p = (PDUinfo *)pdu->data, *p1;
2972 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
2973 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
2977 CHECKTYPE(tree, TBLTYPE_TypeDef);
2979 if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
2980 p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2982 p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
2983 p->flags |= PDU_TYPEDEF;
2985 tree = g_node_first_child(tree); /* move to its underlying type */
2986 CHECKTYPE(tree, TBLTYPE_Type);
2987 p->type = ((TBLType *)tree->data)->typeId;
2989 q = g_node_first_child(tree); /* the tag of this type entry ... is optional... */
2990 if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
2991 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
2995 /* XXX -- hack -- hack -- hack -- hack -- hack --
2996 * only change tag when class+tag == EOC,
2997 * or class is a reference,
2998 * or new class is not universal.
3000 if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
3001 (((TBLTag *)q->data)->tclass != BER_CLASS_UNI) ) {
3002 p->tclass = ((TBLTag *)q->data)->tclass;
3003 p->tag = ((TBLTag *)q->data)->code;
3005 g_message("%*s*change typeref tag from %c%d to %c%d",
3009 tag_class[p->tclass],
3013 g_message("%*sNOT changing tag from %c%d to %c%d",
3017 tag_class[((TBLTag *)q->data)->tclass],
3018 ((TBLTag *)q->data)->code);
3025 if (p->tclass==CLASSREF)
3026 g_snprintf(ss, 128, ", CLASSREF %d", p->tag);
3027 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
3029 if (p->tclass==CLASSREF) {
3032 /* CLASSREF....., get it defined using type of the reference */
3034 /* p->basetype may be -1 .... ? XXX */
3037 tr = &typeDef_names[i];
3039 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
3040 p->tag, tr->name, (void *)tr->pdu);
3042 tbl_typeref(n+1, pdu, tr->type, fullindex);
3049 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
3050 p->name, p->typename, (void *)p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
3054 case TBL_ENUMERATED:
3055 /* names do not have a fullname */
3056 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
3057 /* read the enumeration [save min-max somewhere ?] */
3058 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type]; /* XXX change field type... */
3059 p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3061 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3066 g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3067 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3068 p->name, p->fullname,
3069 tbl_types_wireshark_txt[p->type], p->value_id);
3072 while((q = g_node_next_sibling(q))) {
3073 CHECKTYPE(q, TBLTYPE_NamedNumber);
3074 p = g_malloc0(sizeof(PDUinfo));
3076 p->type = TBL_ENUMERATED;
3077 p->name = (((TBLNamedNumber *)q->data)->name);
3078 p->tag = (((TBLNamedNumber *)q->data)->value);
3079 p->flags = PDU_NAMEDNUM;
3080 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3081 g_node_append_data(pdu, p);
3084 /* list all enum values in the field structure for matching */
3085 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3086 q = g_node_first_child(pdu);
3089 p = (PDUinfo *)q->data;
3090 v[nvals].value = p->tag;
3091 v[nvals].strptr = p->name;
3092 /* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
3094 q = g_node_next_sibling(q);
3096 /* last entry is already initialized to { 0, NULL } */
3101 if (p->value_id == -1) { /* not yet registered ..... */
3102 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3103 p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3104 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3109 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3110 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3111 p->name, p->fullname,
3112 tbl_types_wireshark_txt[p->type], p->value_id);
3114 tbl_type(n, pdu, q, fullindex);
3118 if (p->value_id == -1) { /* not yet registered ..... */
3119 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3120 p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3121 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3126 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3127 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3128 p->name, p->fullname,
3129 tbl_types_wireshark_txt[p->type], p->value_id);
3131 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
3136 tbl_type(gint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
3144 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
3145 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3149 /* showGenv(list, n, n+1); */
3152 pdu1 = pdu; /* save start location for append */
3153 while (list) { /* handle all entries */
3155 g_message("%*s+handle a %s, list=%p", n*2, empty,
3156 data_types[((TBLTag *)list->data)->type], (void *)list);
3158 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
3159 list = g_node_next_sibling(list);
3160 if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
3165 /******* change to positive comparation, but leave comment for reference
3166 * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3167 * CHECKTYPE(list, TBLTYPE_Type);
3170 if (((TBLTag *)list->data)->type == TBLTYPE_Type) {
3171 CHECKTYPE(list, TBLTYPE_Type);
3173 p = g_malloc0(sizeof(PDUinfo));
3174 pdu = g_node_append_data(pdu1, p);
3176 p->type = ((TBLType *)list->data)->typeId;
3177 p->typename = tbl_types_asn1[p->type]; /* the default type */
3180 p->basetype = ((PDUinfo *)pdu1->data)->typenum;
3181 p->flags = PDUinfo_initflags;
3182 p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
3183 p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
3185 if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
3186 /* assign an anonymous name [XXX refer to parent typename...] */
3187 ((TBLType *)list->data)->fieldName =
3188 g_strdup_printf("anon%d", anonCount++);
3190 p->name = ((TBLType *)list->data)->fieldName;
3193 ni += g_snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
3194 p->fullname = g_strdup(fieldname);
3196 /* initialize field info */
3199 p->value_hf.p_id = &(p->value_id);
3200 p->value_hf.hfinfo.name = p->fullname;
3201 p->value_hf.hfinfo.abbrev = p->fullname;
3202 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3203 p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3204 p->value_hf.hfinfo.blurb = p->fullname;
3205 /* all the other fields are already 0 ! */
3207 if (p->type < TBL__SIMPLE) {
3208 /* only register fields with a value here, postpone others */
3209 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3214 g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3215 p->mytype, p->typenum, p->basetype, p->flags,
3216 p->typename, p->name, p->fullname,
3217 tbl_types_wireshark_txt[p->type], p->value_id);
3220 q = g_node_first_child(list);
3222 p = (PDUinfo *)pdu->data;
3227 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
3232 case TBL_OCTETSTRING:
3236 CHECKTYPE(q, TBLTYPE_Tag);
3237 p->tclass = ((TBLTag *)q->data)->tclass;
3238 p->tag = ((TBLTag *)q->data)->code;
3242 case TBL_ENUMERATED:
3243 CHECKTYPE(q, TBLTYPE_Tag);
3244 p->tclass = ((TBLTag *)q->data)->tclass;
3245 p->tag = ((TBLTag *)q->data)->code;
3246 if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
3247 /* read the enumeration [save min-max somewhere ?] */
3250 while((q = g_node_next_sibling(q))) {
3251 CHECKTYPE(q, TBLTYPE_NamedNumber);
3252 p = g_malloc0(sizeof(PDUinfo));
3254 p->type = TBL_ENUMERATED;
3255 p->name = (gchar *)(((TBLNamedNumber *)q->data)->name);
3256 p->tag = (((TBLNamedNumber *)q->data)->value);
3257 p->flags = PDU_NAMEDNUM;
3258 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3259 g_node_append_data(pdu, p);
3262 /* list all enum values in the field structure for matching */
3263 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3264 q = g_node_first_child(pdu);
3267 p = (PDUinfo *)q->data;
3268 v[nvals].value = p->tag;
3269 v[nvals].strptr = p->name;
3270 /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3272 q = g_node_next_sibling(q);
3274 /* last entry is already initialized to { 0, NULL } */
3280 case TBL_SEQUENCEOF:
3283 CHECKTYPE(q, TBLTYPE_Tag);
3284 q = g_node_first_child(list);
3285 tbl_type(n+1, pdu, q, ni);
3288 case TBL_TYPEREF: { /* may have a tag ... */
3294 if ( ((TBLTag *)q->data)->type == TBLTYPE_Tag) {
3295 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3296 p->tclass = ((TBLTag *)q->data)->tclass;
3297 p->tag = ((TBLTag *)q->data)->code;
3299 g_message("%*s*insert type tag %c%d", n*2, empty,
3300 tag_class[p->tclass], p->tag);
3302 q = g_node_next_sibling(q);
3303 } else { /* use default tag for this type */
3304 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3305 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != BER_CLASS_UNI)) ||
3306 ((p->tclass | p->tag) == 0 )) {
3307 /* not implicit, use this tag */
3308 p->tclass = tr->defclass;
3309 p->tag = tr->deftag;
3310 if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3311 tag_class[p->tclass], p->tag);
3314 CHECKTYPE(q, TBLTYPE_TypeRef);
3315 i = ((TBLTypeRef *)q->data)->typeDefId;
3317 tr = &typeDef_names[i];
3319 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, (void *)tr->pdu);
3320 p->typename = tr->name;
3322 if (tr->defclass == CLASSREF) {
3324 tr->pdu = pdu; /* remember this reference */
3326 tr = &typeDef_names[i];
3328 g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3329 i, tr->name, (void *)tr->pdu);
3331 /* evaluate reference if not done before or when below recursion limit */
3332 if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3335 tr->pdu = pdu; /* save for references we leave */
3337 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3339 g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3341 ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3344 tbl_typeref(n+1, pdu, tr->type, ni);
3348 g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3349 p->name, tr->name, (void *)tr->pdu);
3350 p->flags |= PDU_REFERENCE;
3351 p->reference = tr->pdu;
3356 g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3361 g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3362 n*2, empty, p->name, p->typename, (void *)p, TBLTYPE(p->type),
3363 tag_class[p->tclass], p->tag);
3365 if (p->value_id == -1) { /* not registered before, do it now */
3366 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3371 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3372 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3373 p->name, p->fullname,
3374 tbl_types_wireshark_txt[p->type], p->value_id);
3376 list = g_node_next_sibling(list);
3381 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
3384 const char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3387 tt = TBLTYPE(info->type);
3389 tn = info->typename;
3390 fn = info->fullname;
3391 if (info->flags & PDU_NAMEDNUM)
3392 txt += g_sprintf(txt, "name: %2d %s", info->tag, nn);
3394 if (info->flags & PDU_TYPEDEF)
3395 txt += g_sprintf(txt, "def %d: ", info->typenum);
3397 txt += g_sprintf(txt, " ");
3398 ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3399 txt += g_sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3400 tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3401 txt += g_sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
3402 oo = (info->flags & PDU_OPTIONAL) ? ", optional" : empty;
3403 ii = (info->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3404 nn = (info->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3405 an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3406 txt += g_sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
3407 if (info->flags & PDU_REFERENCE) {
3408 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3409 tt = TBLTYPE(rinfo->type);
3411 tn = rinfo->typename;
3412 fn = rinfo->fullname;
3413 txt += g_sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3414 if (rinfo->flags & PDU_TYPEDEF)
3415 txt += g_sprintf(txt, " T%d", rinfo->typenum);
3416 txt += g_sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3417 oo = (rinfo->flags & PDU_OPTIONAL) ? ", optional" : empty;
3418 ii = (rinfo->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3419 nn = (rinfo->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3420 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3421 tt = (rinfo->flags & PDU_TYPEDEF) ? ", typedef" : empty;
3422 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3423 tr = (rinfo->flags & PDU_TYPETREE) ? ", typetree" : empty;
3424 txt += g_sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3428 strncpy(txt, "no info available", 20);
3436 showPDUtree(GNode *p, int n)
3442 info = (PDUinfo *)p->data;
3444 PDUtext(text, info);
3446 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3448 showPDUtree(g_node_first_child(p), n+1);
3450 p = g_node_next_sibling(p);
3457 build_pdu_tree(const char *pduname)
3460 guint pdudef, i, tcount;
3469 if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3472 if (asn1_verbose) g_message("no data nodes");
3477 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3479 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3480 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, (void *)sd.here, pdudef);
3482 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3486 /* If there's an existing PDU tree, free it */
3488 g_node_traverse(PDUtree, G_POST_ORDER, G_TRAVERSE_ALL, -1,
3489 free_node_data, NULL);
3490 g_node_destroy(PDUtree);
3493 /* initialize the PDU tree, hand craft the root entry */
3495 info = g_malloc0(sizeof(PDUinfo));
3496 info->name = pduname;
3497 info->typename = pduname;
3498 info->type = TBL_SEQUENCEOF;
3499 info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3500 info->flags = PDUinfo_initflags = 0;
3501 info->value_id = -1;
3503 info->basetype = -1;
3504 info->mytype = pdudef;
3506 info->value_hf.p_id = &(info->value_id);
3507 info->value_hf.hfinfo.name = info->fullname;
3508 info->value_hf.hfinfo.abbrev = info->fullname;
3509 info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3510 info->value_hf.hfinfo.display = tbl_display_wireshark[info->type];
3511 info->value_hf.hfinfo.blurb = info->fullname;
3513 anonCount = 0; /* anonymous types counter */
3515 PDUtree = g_node_new(info);
3516 pabbrev_pdu_len = g_sprintf(fieldname, "%s.%s.", pabbrev, pduname);
3517 sav_len = pabbrev_pdu_len;
3519 /* Now build the tree for this top level PDU */
3521 g_message("******** Define main type %d, %s", pdudef, pduname);
3522 tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1); /* strip initial . for new names */
3525 g_message("%d anonymous types", anonCount);
3527 /* Now make all types used available for matching */
3529 g_message("Define the types that are actually referenced through the top level PDU");
3530 for (i=0, tcount=0; i<numTypedefs; i++) {
3531 tr = &(typeDef_names[i]);
3533 if (tr->pdu) { /* ignore if not used in main pdu */
3536 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3538 g_message("******** Define type %d, %s", i, tr->name);
3540 /* .... do definition ..... */
3541 info = g_malloc0(sizeof(PDUinfo));
3542 info->name = tr->name;
3543 info->typename = tr->name;
3544 info->tclass = tr->defclass;
3545 info->tag = tr->deftag;
3546 info->type = TBL_TYPEREF;
3547 info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3548 info->flags = PDUinfo_initflags = PDU_TYPETREE;
3549 info->value_id = -1;
3551 info->basetype = -1;
3554 info->value_hf.p_id = &(info->value_id);
3555 info->value_hf.hfinfo.name = info->fullname;
3556 info->value_hf.hfinfo.abbrev = info->fullname;
3557 info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3558 info->value_hf.hfinfo.display = tbl_display_wireshark[info->type];
3559 info->value_hf.hfinfo.blurb = info->fullname;
3561 tr->typetree = g_node_new(info);
3562 pabbrev_pdu_len = g_sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
3563 tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3567 g_message("%d types used", tcount);
3569 pabbrev_pdu_len = sav_len;
3571 /* and show the result */
3573 g_message("Type index:");
3574 for (i=0; i<numTypedefs; i++) {
3575 tr = &(typeDef_names[i]);
3577 if (tr->pdu == 0) /* skip if not used */
3581 g_message(" %3d %s, %c%d, refs: %d",
3582 i, tr->name, tag_class[tr->defclass], tr->deftag,
3583 g_ptr_array_len(tr->refs));
3585 /* get defining node for this type */
3588 p = (PDUinfo *)(tr->typetree->data);
3589 defid = p->value_id;
3591 g_message(" -- defining id=%d", defid);
3593 for(j=0; j < g_ptr_array_len(tr->refs); j++) { /* show refs, and set type_id */
3594 p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3595 if (p->mytype == (gint)i)
3596 p->type_id = defid; /* normal reference */
3598 if ((p->flags & PDU_TYPETREE) == 0) {
3599 /* we have a primitive value, find its real type */
3600 for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3601 /* look at all refs */
3602 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3603 if ((q->flags & PDU_TYPETREE) == 0)
3604 continue; /* only type trees are interresting */
3605 if (q->type != p->type)
3606 continue; /* must be same types */
3607 if (strcmp(q->name, p->name) == 0) {
3608 /* OK, take the first we find, not entirely
3609 * correct, it may be from a different
3610 * base-base type...... XXX */
3611 p->type_id = q->value_id;
3620 g_message(" %s", text);
3626 g_message("The resulting PDU tree:");
3627 showPDUtree(PDUtree, 0);
3633 #ifdef DISSECTOR_WITH_GUI
3634 /* This cannot work in tshark.... don't include for now */
3636 #endif /* DISSECTOR_WITH_GUI */
3639 static GtkWidget *window = NULL;
3641 /* the columns in the tree view */
3644 TITLE_COLUMN, /* text in this row */
3645 DEF_COLUMN, /* definition in this row, if any */
3646 REF_COLUMN, /* referennce from this column, if any */
3647 VALUE_COLUMN, /* indicate this is a value */
3648 NAME_COLUMN, /* name of this row */
3652 static FILE *namelist = 0;
3655 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3658 PDUinfo *info, *rinfo;
3665 info = (PDUinfo *)p->data;
3667 gtk_tree_store_append (store, &iter2, iter); /* Acquire iterator */
3669 PDUtext(text, info);
3672 if (info->flags & PDU_TYPEDEF)
3673 def = info->typenum;
3675 if (info->flags & PDU_REFERENCE) {
3676 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3677 ref = rinfo->typenum;
3679 pb = GTK_STOCK_CANCEL;
3680 if (G_NODE_IS_LEAF(p)) {
3681 if (info->flags & PDU_NAMEDNUM)
3682 pb = GTK_STOCK_BOLD;
3686 fprintf(namelist, "%16s %s\n",
3687 &(TBLTYPE(info->type)[4]), info->fullname);
3690 switch (info->type) {
3691 case TBL_ENUMERATED:
3695 fprintf(namelist, "%16s %s\n",
3696 &(TBLTYPE(info->type)[4]), info->fullname);
3703 gtk_tree_store_set (store, &iter2,
3708 NAME_COLUMN, info->fullname,
3711 build_tree_view(store, g_node_first_child(p), &iter2);
3713 p = g_node_next_sibling(p);
3725 #define PATHSTACKMAX 10
3726 static GtkTreePath *pathstack[PATHSTACKMAX];
3727 static gint pathstackp = 0;
3729 static void add_path(GtkTreePath *p)
3731 if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
3732 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
3733 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
3736 pathstack[pathstackp++] = p;
3739 static GtkTreePath *pop_path(void)
3742 return pathstack[--pathstackp];
3747 find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
3751 struct DefFind *df = (struct DefFind *)data;
3753 gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
3755 if (def == df->def) {
3756 df->path = gtk_tree_path_copy (path);
3764 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
3767 GtkTreePath *path, *path2;
3768 gchar *text, *oldpath, *newpath;
3774 path = gtk_tree_path_copy (spath);
3776 gtk_tree_model_get_iter (model, &iter, path);
3777 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
3779 oldpath = gtk_tree_path_to_string(path);
3780 path2 = gtk_tree_path_copy (path);
3782 add_path(gtk_tree_path_copy(path));
3784 if (ref != -1) { /* this is a reference, find matching definition */
3787 gtk_tree_model_foreach (model, find_definition, &df);
3789 gtk_tree_path_free(path);
3792 } else { /* just move to the next entry, if it exists */
3793 gtk_tree_path_next(path2);
3795 if (gtk_tree_model_get_iter (model, &iter, path2)) {
3796 gtk_tree_path_free(path);
3797 path = path2; /* OK */
3799 if (gtk_tree_path_get_depth (path) > 1)
3800 gtk_tree_path_up (path);
3805 gtk_tree_path_free (path2);
3807 gtk_tree_view_expand_to_path (treeview, path);
3808 gtk_tree_view_expand_row (treeview, path, FALSE);
3810 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3812 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3814 newpath = gtk_tree_path_to_string(path);
3817 g_message("my_signal_handler: treeview=%p, moving from %s to %s",
3818 treeview, oldpath, newpath);
3824 /* gtk_tree_path_free(df.path); */
3829 menuitem_cb (gpointer callback_data,
3830 guint callback_action,
3834 GtkTreeModel *model;
3835 GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
3836 GtkTreeSelection *selection;
3841 gchar *oldpath, *newpath;
3842 GtkTreeViewColumn *focus_column;
3844 selection = gtk_tree_view_get_selection(treeview);
3846 model = gtk_tree_view_get_model(treeview);
3847 gtk_tree_view_get_cursor (treeview, &path, &focus_column);
3849 if (gtk_tree_model_get_iter (model, &iter, path)) {
3851 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
3852 NAME_COLUMN, &name, -1);
3853 oldpath = gtk_tree_path_to_string(path);
3856 switch (callback_action) {
3857 case 0: /* Select */
3858 gtk_tree_selection_select_path (selection, path);
3863 gtk_tree_view_expand_to_path (treeview, path);
3864 gtk_tree_view_expand_row (treeview, path, FALSE);
3866 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3868 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3870 newpath = gtk_tree_path_to_string(path);
3872 gtk_tree_path_free(path);
3874 newpath = g_strdup("** no path **");
3876 g_message("menueitem_cb: treeview=%p, moving from %s to %s",
3877 treeview, oldpath, newpath);
3881 /* get all non anonymous names to the root */
3884 dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
3885 GTK_DIALOG_DESTROY_WITH_PARENT,
3888 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
3889 gtk_item_factory_path_from_widget (widget),
3890 callback_action, text, oldpath, newpath, name);
3892 /* Close dialog on user response */
3893 g_signal_connect (dialog,
3895 G_CALLBACK (gtk_widget_destroy),
3898 gtk_widget_show (dialog);
3903 if (newpath != empty)
3907 g_message("menuitem_cb: no iterator...");
3910 static GtkItemFactoryEntry menu_items[] = {
3911 { "/Select", NULL, menuitem_cb, 0, NULL, 0 },
3912 { "/Back", "<control>B", menuitem_cb, 1, NULL, 0 },
3913 { "/Find", "<control>F", menuitem_cb, 2, NULL, 0 },
3914 { "/Save", "<control>S", menuitem_cb, 3, NULL, 0 },
3917 static gint button_press_callback( GtkWidget *widget,
3918 GdkEventButton *event,
3921 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
3923 /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
3924 * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
3927 if (event->button == 3) {
3928 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
3935 return FALSE; /* continue handling this event */
3940 create_message_window(void)
3942 GtkCellRenderer *renderer;
3943 GtkTreeStore *model;
3946 GtkWidget *treeview;
3948 GtkItemFactory *item_factory;
3949 GtkAccelGroup *accel_group;
3950 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3954 /* create window, etc */
3955 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3956 gtk_window_set_title (GTK_WINDOW (window), current_pduname);
3957 g_signal_connect (window, "destroy",
3958 G_CALLBACK (gtk_widget_destroyed), &window);
3960 vbox = gtk_vbox_new (FALSE, 8);
3961 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3962 gtk_container_add (GTK_CONTAINER (window), vbox);
3964 text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
3966 gtk_box_pack_start (GTK_BOX (vbox),
3967 gtk_label_new (text),
3971 sw = gtk_scrolled_window_new (NULL, NULL);
3972 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
3973 GTK_SHADOW_ETCHED_IN);
3974 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
3975 GTK_POLICY_AUTOMATIC,
3976 GTK_POLICY_AUTOMATIC);
3977 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3979 model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3980 G_TYPE_STRING, G_TYPE_STRING);
3982 namelist = ws_fopen("namelist.txt", "w");
3983 build_tree_view(model, PDUtree, NULL);
3987 /* create tree view */
3988 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
3989 g_object_unref (model);
3990 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
3991 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
3992 GTK_SELECTION_MULTIPLE);
3994 renderer = gtk_cell_renderer_text_new ();
3996 #if 0 /* testing pango attributes */
3999 PangoAttrList* attr;
4001 attr = pango_attr_list_new();
4002 bg = pango_attr_background_new(50000,55000,50000);
4003 bg->start_index = 0;
4004 bg->end_index = 10000;
4005 pango_attr_list_insert(attr, bg);
4007 g_object_set(renderer, "attributes", attr, NULL);
4009 #endif /* testing pango attributes */
4011 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4012 TITLE_COLUMN, "asn1 entities", renderer,
4013 "text", TITLE_COLUMN, NULL );
4015 /* renderer = gtk_cell_renderer_text_new ();
4016 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4017 * DEF_COLUMN, "type definition", renderer,
4018 * "text", DEF_COLUMN, NULL );
4020 * renderer = gtk_cell_renderer_text_new ();
4021 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4022 * REF_COLUMN, "reference", renderer,
4023 * "text", REF_COLUMN, NULL );
4025 renderer = gtk_cell_renderer_pixbuf_new ();
4026 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4027 VALUE_COLUMN, "value", renderer,
4028 "stock_id", VALUE_COLUMN, NULL );
4030 renderer = gtk_cell_renderer_text_new ();
4031 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4032 NAME_COLUMN, "fieldname", renderer,
4033 "text", NAME_COLUMN, NULL );
4035 gtk_container_add (GTK_CONTAINER (sw), treeview);
4037 /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
4041 accel_group = gtk_accel_group_new ();
4043 /* This function initializes the item factory.
4044 * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
4045 * or GTK_TYPE_OPTION_MENU.
4046 * Param 2: The path of the menu.
4047 * Param 3: A pointer to a gtk_accel_group. The item factory sets up
4048 * the accelerator table while generating menus.
4051 item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
4053 /* This function generates the menu items. Pass the item factory,
4054 the number of items in the array, the array itself, and any
4055 callback data for the the menu items. */
4056 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
4058 /* Attach the new accelerator group to the window. */
4059 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
4062 /* expand all rows after the treeview widget has been realized */
4063 g_signal_connect (treeview, "realize",
4064 G_CALLBACK (gtk_tree_view_expand_all), NULL);
4065 g_signal_connect (treeview, "row-activated",
4066 G_CALLBACK (my_signal_handler), (gpointer)model);
4068 g_signal_connect (treeview, "button_press_event",
4069 G_CALLBACK (button_press_callback), item_factory);
4071 /* g_signal_connect_swapped (treeview, "event",
4072 * G_CALLBACK (button_press_handler),
4075 gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
4078 if (!GTK_WIDGET_VISIBLE (window))
4079 gtk_widget_show_all (window);
4082 gtk_widget_destroy (window);
4086 #endif /* SHOWPDU */
4088 /************************************************************************************************
4089 * routines to find names to go with the decoded data stream *
4090 ************************************************************************************************/
4091 #define PDUSTATE_STACK_SIZE 1024
4092 typedef struct _statestack statestack;
4093 static struct _statestack {
4098 } PDUstate[PDUSTATE_STACK_SIZE];
4099 static gint PDUstatec = 0;
4101 /* XXX - Shouldn't we do bounds checking here? */
4102 #define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
4103 #define POPSTATE PDUstate[--PDUstatec]
4106 getname(GNode *node) {
4107 if (node == NULL || node->data == NULL)
4108 THROW(ReportedBoundsError);
4110 return ((PDUinfo *)node->data)->name;
4114 gettype(GNode *node) {
4115 if (node == NULL || node->data == NULL)
4116 THROW(ReportedBoundsError);
4118 return ((PDUinfo *)node->data)->type & TBL_TYPEmask;
4122 getinfo(GNode *node) {
4124 THROW(ReportedBoundsError);
4129 #define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
4130 #define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
4131 #define MATCH (info && (class == info->tclass) && (tag == info->tag))
4132 #define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
4133 #define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
4134 #define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
4135 #define ISCHOICE (info && (info->flags & PDU_CHOICE))
4136 #define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
4139 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
4140 pos.node=NULL;PUSHNODE(pos);return ret;}}
4144 showstack(statestack *pos, char *txt, int n)
4147 const char /* *name, *type,*/ *stype;
4148 const char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
4154 if ( ! asn1_verbose)
4160 g_message("==underflow");
4163 rep = chs = done = ref = pop = chr = rch = sch = con = empty;
4165 #if 0 /* XXX: not used ??? */
4168 name = ((PDUinfo *)g->data)->name;
4169 type = TBLTYPE(((PDUinfo *)g->data)->type);
4171 name = "node<null>";
4176 stype = TBLTYPE(typef);
4177 if (typef & TBL_REPEAT) rep = "[repeat]";
4178 if (typef & TBL_CHOICE_made) chs = "[choice]";
4179 if (typef & TBL_SEQUENCE_done) done = "[done]";
4180 if (typef & TBL_REFERENCE) ref = "[ref]";
4181 if (typef & TBL_REFERENCE_pop) pop = "[ref-pop]";
4182 if (typef & TBL_CHOICE_repeat) chr = "[chs-rep]";
4183 if (typef & TBL_REPEAT_choice) rch = "[rep-chs]";
4184 if (typef & TBL_SEQUENCE_choice)sch = "[seq-chs]";
4185 if (typef & TBL_CONSTRUCTED) con = "[constr]";
4187 i = g_sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
4188 (void *)pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4189 pos->name, pos->offset);
4191 for(j=1, n--; n>0; j++, n--) {
4192 p = &PDUstate[PDUstatec-j];
4194 stype = TBLTYPE(typef);
4195 rep = (typef & TBL_REPEAT) ? "[repeat]" : empty;
4196 chs = (typef & TBL_CHOICE_made) ? "[choice]" : empty;
4197 done = (typef & TBL_SEQUENCE_done) ? "[done]" : empty;
4198 ref = (typef & TBL_REFERENCE) ? "[ref]" : empty;
4199 pop = (typef & TBL_REFERENCE_pop) ? "[ref-pop]" : empty;
4200 chr = (typef & TBL_CHOICE_repeat) ? "[chs-rep]" : empty;
4201 rch = (typef & TBL_REPEAT_choice) ? "[rep-chs]" : empty;
4202 sch = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
4203 con = (typef & TBL_CONSTRUCTED) ? "[constr]" : empty;
4205 i += g_sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
4206 (void *)p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4207 p->name, p->offset);
4209 g_message("%s", buf);
4214 showrefNode(GNode *node, int n)
4216 const char *name = empty, *type = empty, *tname = empty;
4217 int cls = 0, tag = 0;
4222 g_message("%*sstop, nesting too deep", 2*n, empty);
4226 info = (PDUinfo *)(node->data);
4227 type = TBLTYPE(info->type);
4229 tname = info->typename;
4230 ref = info->reference;
4234 g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4235 2*n, empty, tname, type, name, node, node->data,
4236 ref, tag_class[cls], tag);
4239 showrefNode(ref, n+1);
4245 showNode(GNode *node, int n, int m)
4247 const char *name = empty, *type = empty;
4254 type = TBLTYPE(((PDUinfo *)(node->data))->type);
4255 name = ((PDUinfo *)(node->data))->name;
4256 ref = ((PDUinfo *)(node->data))->reference;
4258 g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4259 2*n, empty, type, name, node, node->data, node->next, node->prev,
4260 node->parent, node->children);
4263 g_message("%*sstop, nesting too deep", 2*n, empty);
4267 if (ref) showrefNode(ref, n+2);
4269 if (node->children) showNode(node->children, n+1, m);
4270 if (node->next) showNode(node->next, n, m);
4275 PDUreset(int count, int count2)
4279 if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
4281 PDUstatec = 0; /* stackpointer */
4282 PDUerrcount = 0; /* error counter per asn.1 message */
4284 pos.node = NULL; /* sentinel */
4285 pos.name = "sentinel";
4286 pos.type = TBL_SEQUENCEOF;
4291 pos.node = PDUtree; /* root of the tree */
4292 pos.name = getname(pos.node);
4293 pos.type = gettype(pos.node) | TBL_REPEAT;
4299 static GNode * /* find GNode for a choice element, 0 if none */
4300 makechoice(GNode *p, guint class, guint tag)
4305 p = g_node_first_child(p); /* the list of choices */
4306 info = 0; /* avoid gcc warning */
4309 info = ((PDUinfo *)p->data);
4311 if (info->type == TBL_CHOICE) {
4313 g_message(" using sub choice (%s)%s", info->typename, info->name);
4315 q = makechoice(p, class, tag);
4316 if (q) { /* found it */
4318 info = ((PDUinfo *)p->data);
4320 } /* continue with this level */
4324 g_message(" have %c%d, found %c%d, %s", tag_class[class], tag,
4325 tag_class[info->tclass], info->tag, info->name);
4327 if ((class == info->tclass) && (tag == info->tag))
4328 break; /* found it */
4331 p = g_node_next_sibling(p);
4334 if (p) g_message(" OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
4336 else g_message(" ...no matching choice...");
4341 /* offset is for debugging only, a reference to output on screen */
4343 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
4345 statestack pos, pos2, save_pos;
4347 const char *ret, *tmp;
4348 int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4349 static char namestr[64]; /* enough ? */
4350 static char posstr[40];
4351 static char noname[] = "*noname*";
4352 static PDUprops constructed_save; /* for unexpectedly constructed entities */
4354 if (PDUstatec > 0) /* don't read from below the stack */
4356 /* pos refers to the last asn1 node handled */
4358 /* a very simple, too simple??, way to handle constructed entities */
4359 if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4360 /* unexpectedly constructed, return same info as last time */
4361 g_sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4362 showstack(&pos, posstr, 3);
4363 pos.offset = offset;
4364 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4365 PUSHNODE(pos); /* push extra, to match with a EOI operation */
4366 PUSHNODE(pos); /* restore the stack */
4367 *out = constructed_save;
4369 g_message(" return for constructed %s (%s)%s",
4370 TBLTYPE(out->type), out->typename, out->name);
4374 save_pos = pos; /* may need it again */
4378 out->typename = "*error*";
4385 if (PDUstatec <= 0) {
4386 if (PDUstatec > -10) {
4388 g_message(">>off=%d stack underflow, return", offset);
4390 if (PDUstatec == -10) {
4392 g_message(">>off=%d stack underflow, return, no more messages", offset);
4394 out->name = "*underflow*";
4395 out->flags |= OUT_FLAG_noname;
4399 g_sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4401 showstack(&pos, posstr, 3);
4405 if (class == ASN1_EOI) { /* end of this input sequence */
4407 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4408 if (asn1_verbose) g_message(" EOI: reference pop");
4411 switch(pos.type & TBL_TYPEmask) {
4413 if (asn1_verbose) g_message(" EOI: pop typeref");
4414 pos = POPSTATE; /* remove typeref */
4416 case TBL_CHOICE_done:
4417 if (asn1_verbose) g_message(" EOI: mark choice");
4419 pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4427 pos = POPSTATE; /* this is pushed back on the stack later */
4428 if (pos.node == NULL) {
4429 if (asn1_verbose) g_message(" EOI, pos.node == NULL");
4430 out->name = "*no-name-EOI*";
4431 out->flags |= OUT_FLAG_noname;
4436 info = getinfo(pos.node);
4438 tmp = TBLTYPE(info->type);
4439 if (offset != pos.offset) {
4441 g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4442 tmp, ret, offset, pos.offset);
4443 while ((offset < pos.offset) && (PDUstatec > 0)) {
4446 g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
4447 offset, pos.offset);
4449 if (offset != pos.offset)
4450 PDUerrcount++; /* only count if still unequal */
4452 if (asn1_verbose) g_message(" EOI %s:%s OK, offset=%d", tmp, ret, offset);
4455 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4456 * indicated by the synthetic EOI call. */
4457 if ((class == BER_CLASS_UNI) && (tag == BER_UNI_TAG_EOC)) { /* explicit EOC never has a name */
4458 PUSHNODE(pos); /* restore stack */
4459 ret = "explicit-EOC";
4460 if (asn1_verbose) g_message(" return '%s', ignore", ret);
4462 out->typename = "ASN1";
4466 /* find appropriate node for this tag */
4468 if (pos.node == NULL) {
4469 if (asn1_verbose) g_message(" pos.node == NULL");
4470 out->name = "*no-name*";
4471 out->flags |= OUT_FLAG_noname;
4476 /* showNode(pos.node, 3, 4); */
4478 switch (pos.type & TBL_TYPEmask) {
4479 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4483 if (pos.type & TBL_CHOICE_made) {
4484 if (asn1_verbose) g_message(" finish choice");
4490 info = getinfo(pos.node);
4492 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4493 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4495 if (asn1_verbose) g_message(" repeating choice"); /* ignore repeat */
4498 if (asn1_verbose) g_message(" seqof: repeat start");
4499 /* decide how to continue, CHILD for next instance of sequence
4500 * or NEXT for end of repeated sequence.
4501 * use the tag to make a descision */
4502 if (asn1_verbose) g_message(" seqof: first got %c%d, found %c%d",
4503 tag_class[class], tag,
4504 tag_class[info->tclass], info->tag);
4506 /* This is the start of repeating */
4508 ret = getname(pos.node);
4509 if (asn1_verbose) g_message(" return for repeat '%s'", ret);
4510 out->type = (pos.type & TBL_TYPEmask);
4511 out->typename = info->typename;
4513 out->value_id = info->value_id;
4514 out->type_id = info->type_id;
4516 if (asn1_verbose) g_message(" anonymous: dontshow");
4518 out->flags |= OUT_FLAG_dontshow;
4524 /* find out where to go .... */
4526 CHILD; /* assume sequence is repeated */
4528 info = getinfo(pos.node); /* needed for MATCH to look ahead */
4530 g_message(" seqof: child: got %c%d, found %c%d",
4531 tag_class[class], tag,
4532 tag_class[info->tclass], info->tag);
4534 if (pos2.type & TBL_CHOICE_repeat) {
4537 g_message(" repeating a choice, %s",
4539 pos.type = TBL_CHOICE_immediate;
4541 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4542 donext = 1; /* move on */
4544 g_message(" seqof: no repeat, force next");
4546 /* following code will take the child again */
4552 } else if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4553 if (asn1_verbose) g_message(" reference pop, donext");
4556 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4557 if (pos.type & TBL_SEQUENCE_choice) {
4558 pos = POPSTATE; /* expect to find a repeat here */
4561 if (asn1_verbose) g_message(" sequence done, donext");
4565 if (pos.type & TBL_REFERENCE) {
4566 if (asn1_verbose) g_message(" reference change ref -> pop");
4567 pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4570 pos.offset = offset;
4572 ret = pos.name; /* for the debug messages */
4575 if (asn1_verbose) g_message(" donext");
4578 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4579 case TBL_SETOF: /* ?? */
4580 case TBL_SEQUENCEOF:
4581 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4582 pos.type |= TBL_REPEAT;
4586 /* remember this is the start of a repeat cycle */
4587 typeflags |= TBL_REPEAT;
4589 g_message(" seqof: set repeat mark [push,child]");
4592 g_message(" seqof: end of repeat loop [next]");
4596 case TBL_SET: /* ?? */
4598 pos.type |= TBL_SEQUENCE_done;
4602 if (asn1_verbose) g_message(" seq [push,child]");
4605 /* no more choice */
4606 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4609 pos.type = 0; /* clear all type flags */
4611 g_message(" choice [push], %c%d, %s",
4612 tag_class[info->tclass], info->tag, getname(pos.node));
4613 pos.node = makechoice(pos.node, class, tag);
4614 if (pos.node == NULL) {
4616 out->flags |= OUT_FLAG_noname;
4619 info = getinfo(pos.node);
4621 ret = getname(pos.node);
4623 g_message(" '%s' %c%d will be used",
4624 ret, tag_class[info->tclass], info->tag);
4626 case TBL_CHOICE_done:
4632 if (asn1_verbose) g_message(" typeref [pop,next]");
4634 case TBL_ENUMERATED:
4636 /* skip named numbers now, call to PDUenum() will retrieve a name */
4639 case TBL_CHOICE_immediate:
4640 if (asn1_verbose) g_message(" immediate choice [no next]");
4649 if (pos.node == NULL) {
4650 ret = "*no-name-2*";
4651 if (asn1_verbose) g_message(" return '%s'", ret);
4653 out->flags |= OUT_FLAG_noname;
4657 ret = pos.name = getname(pos.node);
4658 pos.type = gettype(pos.node) | (pos.type & ~TBL_TYPEmask);
4659 info = getinfo(pos.node);
4661 /* pos now points to the prospective current node, go check it ********************/
4662 if (asn1_verbose && info) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4663 (ISOPTIONAL)?", optional":empty,
4664 (ISIMPLICIT)?", implicit":empty,
4665 tag_class[info->tclass], info->tag );
4667 if (ISOPTIONAL) { /* must check the tag */
4668 while(! MATCH) { /* check optional here again...? */
4670 g_message(" got %c%d, found %c%d", tag_class[class], tag,
4671 tag_class[info->tclass], info->tag);
4673 if (pos.node == NULL) {
4676 pos = save_pos; /* reset for next time */
4677 pos.type |= TBL_SEQUENCE_done;
4679 pos.type &= ~TBL_SEQUENCE_done;
4681 out->flags |= OUT_FLAG_dontshow;
4683 g_message(" end of optional list, constructed, expect value next time");
4686 out->flags |= OUT_FLAG_noname;
4688 g_message(" *end of optional list...");
4689 info = 0; /* this is not valid any more... */
4691 break; /* end of list */
4693 info = getinfo(pos.node);
4694 if (asn1_verbose) g_message(" optional, %s", getname(pos.node));
4696 if (pos.node && ! cons_handled) {
4697 ret = pos.name = getname(pos.node);
4698 pos.type = gettype(pos.node);
4700 /* pos now refers to node with name we want, optional nodes skipped */
4703 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4704 pos2 = pos; /* save current state */
4708 g_message(" already pushed, skip next push");
4710 typeflags &= ~TBL_CHOICE_made;
4713 if (asn1_verbose && info)
4714 g_message(" immediate choice [push], %c%d, %s",
4715 tag_class[info->tclass], info->tag, getname(pos.node));
4717 pos.node = makechoice(pos.node, class, tag);
4719 if (pos.node == NULL) {
4723 info = getinfo(pos.node);
4724 pos.type = gettype(pos.node);
4725 out->type = (pos.type & TBL_TYPEmask);
4726 out->flags |= OUT_FLAG_type;
4728 g_sprintf(namestr, "%s!%s", ret, getname(pos.node));
4731 g_message(" %s:%s will be used", TBLTYPE(pos.type), ret);
4732 if (typeflags & TBL_REPEAT) {
4733 pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
4735 pos.type |= TBL_SEQUENCE_choice;
4738 g_message(" return from immediate choice [%s] '%s'",
4739 TBLTYPE(pos.type), ret);
4741 out->data = pos.node; /* for access to named numbers... */
4743 out->type = (pos.type & TBL_TYPEmask);
4746 out->typename = info->typename;
4747 out->fullname = info->fullname;
4748 out->value_id = info->value_id;
4749 out->type_id = info->type_id;
4754 typeflags |= TBL_CHOICE_made;
4757 if (asn1_verbose) g_message(" matching choice '%s'", ret);
4759 if ( ! cons ) { /* ISIMPLICIT was not OK for all */
4760 pos = pos2; /* reset for continuation */
4765 g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4766 (ISOPTIONAL)?", optional":empty,
4767 (ISIMPLICIT)?", implicit":empty,
4768 tag_class[info->tclass], info->tag );
4770 g_message(" using: unknown '%s'", ret);
4773 /* must follow references now */
4774 if (pos.type == TBL_TYPEREF && info) {
4775 out->typename = info->typename;
4776 out->type_id = info->typenum;
4777 out->flags |= OUT_FLAG_typename;
4779 PUSHNODE(pos); /* remember where we were */
4780 if (asn1_verbose) g_message(" typeref [push]");
4781 typeflags |= TBL_REFERENCE;
4782 if (info->reference == 0) { /* resolved ref to universal type.... */
4783 /* showNode(pos.node, 3, 4); */
4784 pos.type = gettype(pos.node); /* the resulting type */
4785 info = getinfo(pos.node);
4786 tmp = "inknown tag";
4787 if ((info->tclass == BER_CLASS_UNI) && (info->tag < 31)) {
4788 tmp = asn1_tag[info->tag];
4789 pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
4791 if (asn1_verbose && info)
4792 g_message(" indirect typeref to %s:%s, %s [%c%d]",
4793 TBLTYPE(pos.type), info->typename, tmp,
4794 tag_class[info->tclass], info->tag );
4796 out->fullname = info->fullname;
4797 donext = (ISANONYMOUS); /* refereing entity has no name ? */
4798 pos.node = info->reference;
4799 pos.type = gettype(pos.node);
4800 info = getinfo(pos.node);
4802 g_message(" typeref %s %s", TBLTYPE(pos.type), getname(pos.node));
4803 /* keep name from before going through the reference, unless anonymous */
4804 if (donext) /* refering entity has no name */
4805 ret = getname(pos.node); /* a better name */
4807 /* handle choice here ? !!mm!! */
4809 out->type = (pos.type & TBL_TYPEmask);
4810 out->flags |= OUT_FLAG_type;
4811 /* showNode(pos.node, 3, 4); */
4812 /* ret = getname(pos.node);*/
4814 out->data = pos.node;
4815 out->flags |= OUT_FLAG_data;
4817 g_message(" typeref set named number list node %p", (void *)pos.node);
4821 pos.type = TBL_TYPEREF_nopop;
4822 if (asn1_verbose) g_message(" typeref pop");
4823 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
4824 /* do not enter the named-number list */
4826 pos.type = TBL_TYPEREF_nopop;
4827 if (asn1_verbose) g_message(" typeref [pop]");
4829 typeflags |= TBL_REFERENCE;
4834 if (cons && ! cons_handled) { /* This entity is constructed, expected ? */
4836 case TBL_BOOLEAN: /* these are not expected to be constructed */
4838 case TBL_OCTETSTRING:
4842 case TBL_ENUMERATED:
4844 typeflags |= TBL_CONSTRUCTED;
4845 /* this entry has no extra info, next is the same */
4846 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
4847 if (asn1_verbose) g_message(" dontshow and set constructed flag");
4849 default: /* others, such as sequences, are expected to be constructed */
4856 if (asn1_verbose) g_message(" anonymous: dontshow");
4857 if (asn1_debug) /* this entry has no extra info, next is the same */
4858 out->flags |= OUT_FLAG_dontshow;
4860 out->name = empty; /* show it, but no name */
4863 if (out->name != empty)
4866 if ( ! (out->flags & OUT_FLAG_data))
4867 out->data = pos.node; /* for access to named numbers... */
4869 pos.type |= typeflags;
4872 if ( ! (out->flags & OUT_FLAG_type))
4873 out->type = pos.type;
4875 out->type &= TBL_TYPEmask;
4877 if (ret == noname) {
4879 out->flags |= OUT_FLAG_noname;
4882 if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
4883 out->typename = info->typename;
4884 out->type_id = info->typenum;
4887 if (info && (out->value_id == -1)) {
4888 out->value_id = info->value_id;
4889 out->type_id = info->type_id;
4892 if ((out->fullname == 0) && info)
4893 out->fullname = info->fullname;
4895 if (typeflags & TBL_CONSTRUCTED)
4896 constructed_save = *out;
4899 g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
4900 out->value_id, out->type_id);
4906 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
4910 const char *ret, *name;
4911 static char unnamed[] = "*unnamed*";
4913 (void) cls; (void) tag; /* make a reference */
4915 if (props->flags & OUT_FLAG_noname)
4919 list = (GNode *)props->data;
4922 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
4924 return "*list-still-0*";
4927 if ((PDUinfo *)list->data)
4928 name = ((PDUinfo *)list->data)->name;
4932 for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
4933 info = (PDUinfo *)list->data;
4934 if (value == info->tag) {
4943 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
4947 #endif /* READSYNTAX */
4950 proto_register_asn1(void) {
4952 static const enum_val_t type_recursion_opts[] = {
4966 gint *ett[1+MAX_NEST+MAXPDU];
4968 module_t *asn1_module;
4970 const char *orig_ptr;
4972 asn1_logfile = get_tempfile_path(ASN1LOGFILE);
4974 current_asn1 = g_strdup("");
4975 asn1_filename = g_strdup(current_asn1);
4977 current_pduname = g_strdup("ASN1");
4978 asn1_pduname = g_strdup(current_pduname);
4980 proto_asn1 = proto_register_protocol("ASN.1 decoding",
4984 for (i=0, j=1; i<MAX_NEST; i++, j++) {
4985 ett[j] = &ett_seq[i];
4988 for(i=0; i<MAXPDU; i++, j++) {
4989 ett[j] = &ett_pdu[i];
4993 proto_register_subtree_array(ett, array_length(ett));
4995 asn1_module = prefs_register_protocol(proto_asn1,
4996 proto_reg_handoff_asn1);
4997 #ifdef JUST_ONE_PORT
4998 prefs_register_uint_preference(asn1_module, "tcp_port",
5000 "The TCP port on which "
5001 "ASN.1 messages will be read",
5002 10, &global_tcp_port_asn1);
5003 prefs_register_uint_preference(asn1_module, "udp_port",
5005 "The UDP port on which "
5006 "ASN.1 messages will be read",
5007 10, &global_udp_port_asn1);
5008 prefs_register_uint_preference(asn1_module, "sctp_port",
5010 "The SCTP port on which "
5011 "ASN.1 messages will be read",
5012 10, &global_sctp_port_asn1);
5014 range_convert_str(&global_tcp_ports_asn1, ep_strdup_printf("%u", TCP_PORT_ASN1), 65535);
5015 range_convert_str(&global_udp_ports_asn1, ep_strdup_printf("%u", UDP_PORT_ASN1), 65535);
5016 range_convert_str(&global_sctp_ports_asn1, ep_strdup_printf("%u", SCTP_PORT_ASN1), 65535);
5018 prefs_register_range_preference(asn1_module, "tcp_ports",
5020 "The TCP ports on which "
5021 "ASN.1 messages will be read",
5022 &global_tcp_ports_asn1, 65535);
5023 prefs_register_range_preference(asn1_module, "udp_ports",
5025 "The UDP ports on which "
5026 "ASN.1 messages will be read",
5027 &global_udp_ports_asn1, 65535);
5028 prefs_register_range_preference(asn1_module, "sctp_ports",
5030 "The SCTP ports on which "
5031 "ASN.1 messages will be read",
5032 &global_sctp_ports_asn1, 65535);
5033 #endif /* JUST_ONE_PORT */
5035 prefs_register_bool_preference(asn1_module, "desegment_messages",
5037 "Desegment ASN.1 messages that span TCP segments",
5040 old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
5042 bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
5045 orig_ptr = asn1_filename;
5046 prefs_register_string_preference(asn1_module, "file",
5047 "ASN.1 type table file",
5048 "Compiled ASN.1 description of ASN.1 types",
5050 /* prefs_register_string_preference just overwrite our pointer with a pointer
5051 * to a _copy_ of our string. Free the original string.
5053 g_free((char *)orig_ptr);
5055 orig_ptr = asn1_pduname;
5056 prefs_register_string_preference(asn1_module, "pdu_name",
5058 "Name of top level PDU",
5060 g_free((char *)orig_ptr);
5062 prefs_register_uint_preference(asn1_module, "first_pdu_offset",
5063 "Offset to first PDU in first tcp packet",
5064 "Offset for non-reassembled packets, "
5065 "wrong if this happens on other than the first packet!",
5066 10, &first_pdu_offset);
5067 prefs_register_bool_preference(asn1_module, "flat",
5069 "Show full names for all values",
5071 prefs_register_enum_preference(asn1_module, "type_recursion",
5072 "Eliminate references to level",
5073 "Allow this recursion level for eliminated type references",
5074 &type_recursion_level,
5075 type_recursion_opts, FALSE);
5076 prefs_register_bool_preference(asn1_module, "debug",
5078 "Extra output useful for debugging",
5081 prefs_register_bool_preference(asn1_module, "message_win",
5083 "show full message description",
5086 prefs_register_obsolete_preference(asn1_module, "message_win");
5088 prefs_register_bool_preference(asn1_module, "verbose_log",
5089 "Write very verbose log",
5090 "log to file $TMP/" ASN1LOGFILE,
5094 /* The registration hand-off routing */
5096 static dissector_handle_t asn1_handle;
5099 register_tcp_port(guint32 port)
5102 dissector_add_uint("tcp.port", port, asn1_handle);
5106 unregister_tcp_port(guint32 port)
5109 dissector_delete_uint("tcp.port", port, asn1_handle);
5113 register_udp_port(guint32 port)
5116 dissector_add_uint("udp.port", port, asn1_handle);
5120 unregister_udp_port(guint32 port)
5123 dissector_delete_uint("udp.port", port, asn1_handle);
5127 register_sctp_port(guint32 port)
5130 dissector_add_uint("sctp.port", port, asn1_handle);
5134 unregister_sctp_port(guint32 port)
5137 dissector_delete_uint("sctp.port", port, asn1_handle);
5141 proto_reg_handoff_asn1(void) {
5142 static gboolean asn1_initialized = FALSE;
5143 /* XXX: Note that the "saved" ports [or port ranges] will not be initialized the first time */
5144 /* thru pro_reg_handoff_asn1 if no PDUtree is built; So: we init with the definition. */
5145 #ifdef JUST_ONE_PORT
5146 static guint tcp_port_asn1 = 0;
5147 static guint udp_port_asn1 = 0;
5148 static guint sctp_port_asn1 = 0;
5150 static range_t *tcp_ports_asn1 = NULL;
5151 static range_t *udp_ports_asn1 = NULL;
5152 static range_t *sctp_ports_asn1 = NULL;
5157 #ifdef JUST_ONE_PORT
5158 if (asn1_verbose) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegnment=%d, "
5159 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5160 global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
5161 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5164 char *tcp_ports_asn1_string, *udp_ports_asn1_string, *sctp_ports_asn1_string;
5165 tcp_ports_asn1_string = range_convert_range(global_tcp_ports_asn1);
5166 udp_ports_asn1_string = range_convert_range(global_udp_ports_asn1);
5167 sctp_ports_asn1_string = range_convert_range(global_sctp_ports_asn1);
5168 g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegnment=%d, "
5169 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5170 tcp_ports_asn1_string, udp_ports_asn1_string, sctp_ports_asn1_string, asn1_desegment,
5171 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5173 #endif /* JUST_ONE_PORT */
5175 if(!asn1_initialized) {
5176 asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
5177 asn1_initialized = TRUE;
5178 } else { /* clean up ports and their lists */
5179 #ifdef JUST_ONE_PORT
5180 unregister_tcp_port(tcp_port_asn1);
5181 unregister_udp_port(udp_port_asn1);
5182 unregister_sctp_port(sctp_port_asn1);
5184 if (tcp_ports_asn1 != NULL) {
5185 range_foreach(tcp_ports_asn1, unregister_tcp_port);
5186 g_free(tcp_ports_asn1);
5189 if (udp_ports_asn1 != NULL) {
5190 range_foreach(udp_ports_asn1, unregister_udp_port);
5191 g_free(udp_ports_asn1);
5194 if (sctp_ports_asn1 != NULL) {
5195 range_foreach(sctp_ports_asn1, unregister_sctp_port);
5196 g_free(sctp_ports_asn1);
5198 #endif /* JUST_ONE_PORT */
5201 if (strcmp(asn1_filename, current_asn1) != 0) {
5202 /* new definitions, parse the file if we have one */
5203 /* !!! should be postponed until we really need it !!! */
5205 read_asn1_type_table(asn1_filename);
5206 #endif /* READSYNTAX */
5207 g_free(current_asn1);
5208 current_asn1 = g_strdup(asn1_filename);
5210 if (!PDUtree || /* no tree built yet for PDU type */
5211 strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
5212 if (build_pdu_tree(asn1_pduname)) {
5213 g_free(current_pduname);
5214 current_pduname = g_strdup(asn1_pduname);
5218 if (asn1_message_win) { /* show what we are prepared to recognize */
5220 gtk_widget_destroy (window);
5223 create_message_window();
5225 #endif /* SHOWPDU */
5227 /* If we now have a PDU tree, register for the port or ports we have */
5229 #ifdef JUST_ONE_PORT
5230 tcp_port_asn1 = global_tcp_port_asn1;
5231 udp_port_asn1 = global_udp_port_asn1;
5232 sctp_port_asn1 = global_sctp_port_asn1;
5234 register_tcp_port(tcp_port_asn1);
5235 register_udp_port(udp_port_asn1);
5236 register_sctp_port(sctp_port_asn1);
5238 tcp_ports_asn1 = range_copy(global_tcp_ports_asn1);
5239 udp_ports_asn1 = range_copy(global_udp_ports_asn1);
5240 sctp_ports_asn1 = range_copy(global_sctp_ports_asn1);
5242 range_foreach(tcp_ports_asn1, register_tcp_port);
5243 range_foreach(udp_ports_asn1, register_udp_port);
5244 range_foreach(sctp_ports_asn1, register_sctp_port);
5245 #endif /* JUST_ONE_PORT */