1 /******************************************************************************************************/
4 * Copyright (c) 2003 by Matthijs Melchior <matthijs.melchior@xs4all.nl>
10 * Ethereal - Network traffic analyzer
11 * By Gerald Combs <gerald@ethereal.com>
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 ethereal 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 * - ethereal tbl.tt.pcap
51 * GUI: Edit->Preferences->Protocols->ASN1
52 * type table file: /tmp/tbl.tt
55 * you can now browse the tbl.tt definition.
66 #include <sys/types.h>
77 #include <epan/packet.h>
78 #include <epan/addr_resolv.h>
79 #include <epan/prefs.h>
80 #include <epan/strutil.h>
81 #include <epan/filesystem.h>
82 #include <epan/report_err.h>
83 #include <epan/emem.h>
84 #include <epan/dissectors/packet-tcp.h>
85 #include <epan/asn1.h>
86 #include <wiretap/file_util.h>
88 #ifdef DISSECTOR_WITH_GUI
92 #include <epan/ipproto.h>
99 /* Define default ports */
101 #define TCP_PORT_ASN1 801
102 #define UDP_PORT_ASN1 801
103 #define SCTP_PORT_ASN1 801
105 void proto_reg_handoff_asn1(void);
107 /* Define the asn1 proto */
109 static int proto_asn1 = -1;
111 /* Define the tree for asn1*/
113 static int ett_asn1 = -1;
115 #define MAXPDU 64 /* max # PDU's in one packet */
116 static int ett_pdu[MAXPDU];
118 #define MAX_NEST 32 /* max nesting level for ASN.1 elements */
119 static int ett_seq[MAX_NEST];
122 * Global variables associated with the preferences for asn1
126 static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
127 static guint global_udp_port_asn1 = UDP_PORT_ASN1;
128 static guint global_sctp_port_asn1 = SCTP_PORT_ASN1;
129 static guint tcp_port_asn1 = TCP_PORT_ASN1;
130 static guint udp_port_asn1 = UDP_PORT_ASN1;
131 static guint sctp_port_asn1 = SCTP_PORT_ASN1;
133 static range_t *global_tcp_ports_asn1;
134 static range_t *global_udp_ports_asn1;
135 static range_t *global_sctp_ports_asn1;
137 static range_t *tcp_ports_asn1;
138 static range_t *udp_ports_asn1;
139 static range_t *sctp_ports_asn1;
140 #endif /* JUST_ONE_PORT */
142 static gboolean asn1_desegment = TRUE;
143 static const char *asn1_filename = NULL;
144 static char *old_default_asn1_filename = NULL;
145 #define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
147 #define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
148 static char *bad_separator_old_default_asn1_filename = NULL;
150 static char *current_asn1 = NULL;
151 static const char *asn1_pduname = NULL;
152 static char *current_pduname = NULL;
153 static gboolean asn1_debug = FALSE;
154 static guint first_pdu_offset = 0;
155 static gboolean asn1_message_win = FALSE;
156 static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
157 static gboolean asn1_full = FALSE; /* show full names */
158 static guint type_recursion_level = 1; /* eliminate 1 level of references */
159 static char *asn1_logfile = NULL;
161 #define ASN1LOGFILE "ethereal.log"
163 /* PDU counter, for correlation between GUI display and log file in debug mode */
164 static int pcount = 0;
166 static tvbuff_t *asn1_desc; /* the PDU description */
167 static GNode *asn1_nodes = NULL; /* GNode tree pointing to every asn1 data element */
168 static GNode *data_nodes = NULL; /* GNode tree describing the syntax data */
169 static GNode *PDUtree = NULL; /* GNode tree describing the expected PDU format */
171 static guint PDUerrcount = 0; /* count of parse errors in one ASN.1 message */
173 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
176 static char pabbrev[] = "asn1"; /* field prefix */
178 static char fieldname[512]; /* for constructing full names */
179 static guint pabbrev_pdu_len; /* length initial part of fieldname with 'abbrev.asn1pdu.' */
182 * Text strings describing the standard, universal, ASN.1 names.
185 #define ASN1_EOI 4 /* this is in the class number space... */
186 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
188 static const char tag_class[] = "UACPX";
190 static const char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
192 static const char *asn1_con[] = { "Primitive", "Constructed" };
194 static const char *asn1_tag[] = {
195 /* 0 */ "EOC", "Boolean", "Integer", "BitString",
196 /* 4 */ "OctetString", "Null", "ObjectIdentifier", "ObjectDescriptor",
197 /* 8 */ "External", "Real", "Enumerated", "tag11",
198 /* 12 */ "UTF8String", "tag13", "tag14", "tag15",
199 /* 16 */ "Sequence", "Set", "NumericString", "PrintableString",
200 /* 20 */ "TeletexString", "VideotexString", "IA5String", "UTCTime",
201 /* 24 */ "GeneralTime", "GraphicString", "ISO646String", "GeneralString",
202 /* 28 */ "UniversalString", "tag29", "BMPString", "Long tag prefix"
203 /* TT61 == TELETEX */
204 /* ISO646 == VISIBLE*/
207 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
208 static gboolean tbl_types_verified = FALSE;
210 typedef enum { /* copied from .../snacc/c-lib/boot/tbl.h */
219 TBL__SIMPLE = 8, /* values smaller than this can have a value */
227 TBL_SEQUENCEOF_start, /* to mark potential sequence-of repeat */
228 TBL_TYPEREF_nopop, /* typeref has been handled immediately */
229 TBL_CHOICE_done, /* choice is finished */
230 TBL_reserved, /* this sequence has been visited */
231 TBL_CHOICE_immediate, /* immediate choice, no next */
233 TBL_INVALID /* incorrect value for this enum */
236 /* Universal tags mapped to snacc ASN.1 table types */
237 static int asn1_uni_type[] = {
238 /* 0 */ TBL_INVALID, TBL_BOOLEAN, TBL_INTEGER, TBL_BITSTRING,
239 /* 4 */ TBL_OCTETSTRING, TBL_NULL, TBL_OID, TBL_INVALID,
240 /* 8 */ TBL_INVALID, TBL_REAL, TBL_ENUMERATED, TBL_INVALID,
241 /* 12 */ TBL_OCTETSTRING, TBL_INVALID, TBL_INVALID, TBL_INVALID,
242 /* 16 */ TBL_SEQUENCE, TBL_SET, TBL_OCTETSTRING, TBL_OCTETSTRING,
243 /* 20 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
244 /* 24 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
245 /* 28 */ TBL_OCTETSTRING, TBL_INVALID, TBL_OCTETSTRING, TBL_INVALID,
249 #define TBL_REPEAT 0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
250 #define TBL_REPEAT_choice 0x00020000 /* repeating a choice */
251 #define TBL_CHOICE_made 0x00040000 /* This was a choice entry */
252 #define TBL_SEQUENCE_done 0x00080000 /* children have been processed */
253 #define TBL_CHOICE_repeat 0x00100000 /* a repeating choice */
254 #define TBL_REFERENCE 0x00200000 /* This entry is result of a typeref */
255 #define TBL_REFERENCE_pop 0x00400000 /* reference handled, do pop i.s.o. next */
256 #define TBL_SEQUENCE_choice 0x00800000 /* this sequence is a first of a repeating choice */
257 #define TBL_CONSTRUCTED 0x01000000 /* unexpectedly constructed entry */
258 #define TBL_TYPEmask 0x0000FFFF /* Mask just the type */
260 /* XXX - Should we use val_to_str here? */
261 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
263 /* text tables for debugging and GUI */
264 static const char *tbl_types[] = {
265 /* 0 */ "tbl-boolean",
266 /* 1 */ "tbl-integer",
267 /* 2 */ "tbl-bitstring",
268 /* 2 */ "tbl-octetstring",
272 /* 7 */ "tbl-enumerated",
273 /* 8 */ "tbl-sequence",
275 /* 10 */ "tbl-sequenceof",
276 /* 11 */ "tbl-setof",
277 /* 12 */ "tbl-choice",
278 /* 13 */ "tbl-typeref",
280 /* 14 */ "tbl-sequenceof-start",
281 /* 15 */ "tbl-typeref-nopop",
282 /* 16 */ "tbl-choice-done",
283 /* 17 */ "tbl-reserved",
284 /* 18 */ "tbl-choice-immediate",
286 /* 19 */ "tbl-invalid",
288 static const char *tbl_types_asn1[] = {
292 /* 2 */ "OCTET STRING",
294 /* 5 */ "OBJECT IDENTIFIER",
296 /* 7 */ "ENUMERATED",
299 /* 10 */ "SEQUENCE OF",
304 /* 14 */ "start-SEQUENCE OF",
305 /* 15 */ "TYPEREF nopop",
306 /* 16 */ "CHOICE done",
308 /* 18 */ "CHOICE immediate",
310 /* 19 */ "INVALID entry",
312 /* conversion from snacc type to appropriate ethereal type */
313 static guint tbl_types_ethereal[] = {
314 /* 0 */ FT_BOOLEAN, /* TBL_BOOLEAN */
315 /* 1 */ FT_UINT32, /* TBL_INTEGER */
316 /* 2 */ FT_UINT32, /* TBL_BITSTRING */
317 /* 2 */ FT_STRINGZ, /* TBL_OCTETSTRING */
318 /* 4 */ FT_NONE, /* TBL_NULL */
319 /* 5 */ FT_BYTES, /* TBL_OID */
320 /* 6 */ FT_DOUBLE, /* TBL_REAL */
321 /* 7 */ FT_UINT32, /* TBL_ENUMERATED */
322 /* 8 */ FT_NONE, /* TBL_SEQUENCE */
323 /* 9 */ FT_NONE, /* TBL_SET */
324 /* 10 */ FT_NONE, /* TBL_SEQUENCEOF */
325 /* 11 */ FT_NONE, /* TBL_SETOF */
326 /* 12 */ FT_NONE, /* TBL_CHOICE */
327 /* 13 */ FT_NONE, /* TBL_TYPEREF */
329 /* 14 */ FT_NONE, /* TBL_SEQUENCEOF_start */
330 /* 15 */ FT_NONE, /* TBL_TYPEREF_nopop */
331 /* 16 */ FT_NONE, /* TBL_CHOICE_done */
332 /* 17 */ FT_NONE, /* TBL_reserved */
333 /* 18 */ FT_NONE, /* TBL_CHOICE_immediate */
335 /* 19 */ FT_NONE, /* TBL_INVALID */
338 static const char *tbl_types_ethereal_txt[] = {
339 /* 0 */ "FT_BOOLEAN", /* TBL_BOOLEAN */
340 /* 1 */ "FT_UINT32", /* TBL_INTEGER */
341 /* 2 */ "FT_UINT32", /* TBL_BITSTRING */
342 /* 2 */ "FT_STRINGZ", /* TBL_OCTETSTRING */
343 /* 4 */ "FT_NONE", /* TBL_NULL */
344 /* 5 */ "FT_BYTES", /* TBL_OID */
345 /* 6 */ "FT_DOUBLE", /* TBL_REAL */
346 /* 7 */ "FT_UINT32", /* TBL_ENUMERATED */
347 /* 8 */ "FT_NONE", /* TBL_SEQUENCE */
348 /* 9 */ "FT_NONE", /* TBL_SET */
349 /* 10 */ "FT_NONE", /* TBL_SEQUENCEOF */
350 /* 11 */ "FT_NONE", /* TBL_SETOF */
351 /* 12 */ "FT_NONE", /* TBL_CHOICE */
352 /* 13 */ "FT_NONE", /* TBL_TYPEREF */
354 /* 14 */ "FT_NONE", /* TBL_SEQUENCEOF_start */
355 /* 15 */ "FT_NONE", /* TBL_TYPEREF_nopop */
356 /* 16 */ "FT_NONE", /* TBL_CHOICE_done */
357 /* 17 */ "FT_NONE", /* TBL_reserved */
358 /* 18 */ "FT_NONE", /* TBL_CHOICE_immediate */
360 /* 19 */ "FT_NONE", /* TBL_INVALID */
363 typedef struct _PDUinfo PDUinfo;
367 const char *typename;
368 const char *fullname;
374 gint basetype; /* parent type */
375 gint mytype; /* original type number, typenum may have gone through a reference */
376 gint value_id; /* ethereal field id for the value in this PDU */
377 gint type_id; /* ethereal field id for the type of this PDU */
378 hf_register_info value_hf; /* ethereal field info for this value */
382 /* bits in the flags collection */
383 #define PDU_OPTIONAL 1
384 #define PDU_IMPLICIT 2
385 #define PDU_NAMEDNUM 4
386 #define PDU_REFERENCE 8
387 #define PDU_TYPEDEF 0x10
388 #define PDU_ANONYMOUS 0x20
389 #define PDU_TYPETREE 0x40
391 #define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
393 static guint PDUinfo_initflags = 0; /* default flags for newly allocated PDUinfo structs */
395 /* description of PDU properties as passed from the matching routine
396 * to the decoder and GUI.
398 typedef struct _PDUprops PDUprops;
400 guint type; /* value from enum TBLTypeId */
402 const char *typename;
403 const char *fullname;
409 /* flags defined in PDUprops.flags */
410 #define OUT_FLAG_type 1
411 #define OUT_FLAG_data 2
412 #define OUT_FLAG_typename 4
413 #define OUT_FLAG_dontshow 8
414 #define OUT_FLAG_noname 0x10
415 #define OUT_FLAG_constructed 0x20
417 static PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
418 static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
420 static const char empty[] = ""; /* address of the empt string, avoids many tests for NULL */
421 #define MAX_OTSLEN 256 /* max printed size for an octet string */
424 #undef NEST /* show nesting of asn.1 enties */
426 #ifdef NEST /* only for debugging */
427 /* show nesting, only for debugging... */
428 #define MAXTAGS MAX_NEST
434 static char *showtaglist(guint level)
436 static char tagtxt[BUFLM];
441 for(i=0; i<= level; i++) {
442 switch(taglist[i].cls) {
443 case ASN1_UNI: *p++ = 'U'; break;
444 case ASN1_APL: *p++ = 'A'; break;
445 case ASN1_CTX: *p++ = 'C'; break;
446 case ASN1_PRV: *p++ = 'P'; break;
447 default: *p++ = 'x'; break;
449 p += sprintf(p, "%d.", taglist[i].tag);
451 #else /* only context tags */
453 for(i=0; i<= level; i++) {
454 if (taglist[i].cls == ASN1_CTX) {
455 p += sprintf(p, "%d.", taglist[i].tag);
459 *--p = 0; /* remove trailing '.' */
464 get_context(guint level)
469 for(i=0; i<=level; i++) {
470 if (taglist[i].cls == ASN1_CTX)
471 ctx = (ctx << 8) | taglist[i].tag;
475 #endif /* NEST, only for debugging */
478 /* Convert a bit string to an ascii representation for printing
479 * -- not thread safe ...
481 static const char *showbits(guchar *val, guint count)
483 static char str[BUFLM];
488 return "*too many bits*";
491 for(i=0; i<count; i++) {
492 if (i && ((i & 7) == 0)) *p++ = ' ';
493 *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
500 /* get bitnames string for bits set */
502 showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
504 static char str[BUFLL];
508 if (props->flags & OUT_FLAG_noname)
512 return "*too many bits, no names...*";
515 for(i=0; i<count; i++) {
516 if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
517 p += sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
521 --p; /* remove terminating , */
529 /* Convert an oid to its conventional text representation
530 * -- not thread safe...
532 static char *showoid(subid_t *oid, guint len)
534 static char str[BUFLM];
539 for(i=0; i<len; i++) {
541 p += sprintf(p, "%lu", (unsigned long)oid[i]);
548 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
550 showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
555 const char *endstr = empty;
561 for (i=0; i<len; i++) {
562 if (!isprint(octets[i])) /* maybe isblank() as well ... */
565 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
567 endstr = "...."; /* this is 5 bytes !! */
570 str = p = g_malloc(len*2 + 5);
571 for (i=0; i<len; i++) {
572 p += sprintf(p, "%2.2X", octets[i]);
576 if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
577 str = p = g_malloc(len*3+2);
578 for (i=0; i<len; i++) {
579 p += sprintf(p, "%2.2X", octets[i]);
581 *p++ = ' '; /* insert space */
582 strncpy(p, octets, len);
585 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
586 str = g_malloc(len+5);
587 strncpy(str, octets, len);
588 strcpy(&str[len], endstr);
595 /* allow NULL pointers in strcmp, handle them as empty strings */
597 g_strcmp(gconstpointer a, gconstpointer b)
599 if (a == 0) a = empty;
600 if (b == 0) b = empty;
604 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
605 /* WARNING WARNING WARNING WARNING WARNING WARNING */
607 /* Most of the following routine is guesswork in order to */
608 /* speed up resynchronisation if the dissector lost the */
609 /* encoding due to incomplete captures, or a capture that */
610 /* starts in the middle of a fragmented ip packet */
611 /* If this poses to many problems, these settings can be */
612 /* made part of the protocol settings in the user interface */
613 /*************************************************************/
615 /* check length for a reasonable value, return a corrected value */
617 checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
622 g_snprintf(lenstr, strmax, "indefinite");
626 if (len < 0) /* negative ..... */
629 if (cls != ASN1_UNI) { /* don't know about the tags */
634 case ASN1_EOC: /* End Of Contents */
635 case ASN1_NUL: /* Null */
638 case ASN1_BOL: /* Boolean */
641 case ASN1_INT: /* Integer */
642 case ASN1_ENUM: /* Enumerated */
646 case ASN1_BTS: /* Bit String */
650 case ASN1_OTS: /* Octet String */
651 case ASN1_NUMSTR: /* Numerical String */
652 case ASN1_PRNSTR: /* Printable String */
653 case ASN1_TEXSTR: /* Teletext String */
654 case ASN1_VIDSTR: /* Video String */
655 case ASN1_IA5STR: /* IA5 String */
656 case ASN1_GRASTR: /* Graphical String */
657 case ASN1_VISSTR: /* Visible String */
658 case ASN1_GENSTR: /* General String */
662 case ASN1_OJI: /* Object Identifier */
663 case ASN1_OJD: /* Description */
664 case ASN1_EXT: /* External */
668 case ASN1_REAL: /* Real */
672 case ASN1_SEQ: /* Sequence */
673 case ASN1_SET: /* Set */
677 case ASN1_UNITIM: /* Universal Time */
678 case ASN1_GENTIM: /* General Time */
691 /* a change was needed.... */
692 g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
694 g_snprintf(lenstr, strmax, "%d", len);
699 static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
700 static void PDUreset(int count, int counr2);
703 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
706 guint cls, con, tag, def, len, offset, reassembled;
711 const char *name, *tname;
712 volatile guint boffset;
713 volatile int i = 0; /* PDU counter */
714 proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
716 static guint lastseq;
721 reassembled = 1; /* UDP is not a stream, and thus always reassembled .... */
722 if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
723 struct tcpinfo *info = (struct tcpinfo *)pinfo->private_data;
724 gint delta = info->seq - lastseq;
725 reassembled = info->is_reassembled;
729 g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
730 info->seq, delta, reassembled);
733 g_message("dissect_asn1: udp");
736 /* Set the protocol column */
737 if(check_col(pinfo->cinfo, COL_PROTOCOL)){
738 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
741 if(check_col(pinfo->cinfo, COL_INFO))
742 col_clear(pinfo->cinfo, COL_INFO);
746 if ((first_pdu_offset > 0) && !reassembled) {
747 boffset = first_pdu_offset;
748 g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
751 /* open BER decoding */
752 asn1_open(&asn1, tvb, boffset);
754 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
756 asn1_close(&asn1, &offset);
758 PDUreset(pcount, 0); /* arguments are just for debugging */
759 getPDUprops(&props, boffset, cls, tag, con);
761 tname = props.typename;
763 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
767 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
769 g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
776 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
782 if (props.flags & OUT_FLAG_noname) {
783 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
784 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
786 g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
789 /* Set the info column */
790 if(check_col(pinfo->cinfo, COL_INFO)){
791 col_add_str(pinfo->cinfo, COL_INFO, headstr );
795 * If we have a non-null tree (ie we are building the proto_tree
796 * instead of just filling out the columns ), then add a BER
800 /* ignore the tree here, must decode BER to know how to reassemble!! */
803 TRY { /* catch incomplete PDU's */
805 ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
806 def? (int) (offset - boffset + len) : -1,
807 "ASN.1 %s", current_pduname);
809 tree2 = proto_item_add_subtree(ti, ett_asn1);
811 proto_tree_add_item_hidden(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
812 def? (int) (offset - boffset + len) : -1, TRUE);
814 offset = boffset; /* the first packet */
815 while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
818 /* open BER decoding */
819 asn1_open(&asn1, tvb, offset);
820 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
821 asn1_close(&asn1, &offset);
823 PDUreset(pcount, i+1);
824 getPDUprops(&props, boffset, cls, tag, con);
826 tname = props.typename;
829 len = tvb_length_remaining(tvb, offset);
831 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
835 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
837 g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
840 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
843 tvb_length_remaining(tvb, offset) );
845 if (props.value_id == -1)
846 ti2 = proto_tree_add_text(tree2, tvb, boffset,
847 def? (int) (offset - boffset + len) : -1,
848 "%s: (%s)%s %d-%d %s", current_pduname,
849 tname, name, pcount, i+1, headstr);
851 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
852 def? (int) (offset - boffset + len) : -1,
853 "%s: (%s)%s %d-%d %s ~", current_pduname,
854 tname, name, pcount, i+1, headstr);
856 if (props.type_id != -1)
857 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
858 def? (int) (offset - boffset + len) : -1, TRUE);
862 if (props.flags & OUT_FLAG_noname) {
863 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
864 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
866 if (props.value_id == -1)
867 ti2 = proto_tree_add_text(tree2, tvb, boffset,
868 def? (int) (offset - boffset + len) : -1,
869 "%s: (%s)%s", current_pduname, tname, name);
871 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
872 def? (int) (offset - boffset + len) : -1,
873 "%s: (%s)%s ~", current_pduname, tname, name);
874 if (props.type_id != -1)
875 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
876 def? (int) (offset - boffset + len) : -1, TRUE);
879 asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
882 taglist[0].cls = cls;
883 taglist[0].tag = tag;
886 if (!def) len++; /* make sure we get an exception if we run off the end! */
888 offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
890 proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
892 i++; /* one more full message handled */
894 if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
895 proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
897 if(check_col(pinfo->cinfo, COL_INFO))
898 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
900 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
905 CATCH(ReportedBoundsError) {
906 if(check_col(pinfo->cinfo, COL_INFO))
907 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
909 proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
911 proto_item_append_text(ti2, " (incomplete)");
912 if (asn1_desegment) {
913 pinfo->desegment_offset = boffset;
914 pinfo->desegment_len = 1;
916 g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
917 boffset, 1, pinfo->can_desegment);
925 g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
926 pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
929 /* decode an ASN.1 sequence, until we have consumed the specified length */
931 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
934 guint ret, cls, con, tag, def, len, boffset, soffset, eos;
936 const char *clsstr, *constr, *tagstr;
940 proto_tree *ti, *pt2;
941 guchar *octets, *bits, unused;
943 /* the debugging formats */
944 static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s"; /* decimal */
945 static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s"; /* enum */
946 static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s"; /* octet string */
947 static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s"; /* bit field */
948 static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s"; /* constructed */
949 static char matchind[] = " ~"; /* indication of possible match */
950 const char *name, *ename, *tname;
954 ti = 0; /* suppress gcc warning */
956 soffset = offset; /* where this sequence starts */
958 while (offset < eos) { /* while this entity has not ended... */
960 asn1_open(&asn1, tvb, offset);
961 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
962 asn1_close(&asn1, &offset); /* mark current position */
963 if (ret != ASN1_ERR_NOERROR) {
964 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
968 getPDUprops(&props, boffset, cls, tag, con);
970 tname = props.typename;
972 name = &props.fullname[pabbrev_pdu_len]; /* no abbrev.pduname */
973 if (asn1_debug) { /* show both names */
974 sprintf(fieldname, "%s[%s]", props.name, props.fullname);
978 clsstr = asn1_cls[cls];
979 constr = asn1_con[con];
980 if ((cls == ASN1_UNI) && ( tag < 32 )) {
981 tagstr = asn1_tag[tag];
983 g_snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
987 len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
990 g_snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
992 strncpy(nnbuf, "NN-", sizeof(nnbuf));
993 /* make sure we get an exception if we run off the end! */
994 len = tvb_length_remaining(tvb, offset) + 1;
996 if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
997 /* just give type name if we don't know any better */
999 name = nnbuf; /* this is better than just empty.... */
1003 taglist[level].cls = cls;
1004 taglist[level].tag = tag;
1008 if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
1011 oname = g_malloc(strlen(name) + 32);
1012 sprintf(oname, "%s ** nesting cut off **", name);
1016 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
1019 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1020 asn1_close(&asn1, &offset); /* mark where we are now */
1022 if ( (props.value_id == -1) ||
1023 (tbl_types_ethereal[props.type] != FT_UINT32) )
1024 /* unknown or unexpected: just text */
1025 proto_tree_add_text(pt, tvb, boffset,
1026 offset - boffset, textfmt_d, boffset,
1027 clsstr, constr, tagstr, tname, name, value,
1030 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1031 offset - boffset, value, textfmt_d, boffset,
1032 clsstr, constr, tagstr, tname, name, value,
1034 if (props.type_id != -1)
1035 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1036 boffset, offset - boffset, value);
1039 if ( (props.value_id == -1) ||
1040 (tbl_types_ethereal[props.type] != FT_UINT32) )
1041 /* unknown or unexpected, just text */
1042 proto_tree_add_text(pt, tvb, boffset,
1044 "(%s)%s: %d", tname, name, value);
1046 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1047 offset - boffset, value,
1048 "(%s)%s: %d ~", tname, name, value);
1049 if (props.type_id != -1)
1050 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1051 boffset, offset - boffset, value);
1057 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1058 asn1_close(&asn1, &offset); /* mark where we are now */
1059 ename = getPDUenum(&props, boffset, cls, tag, value);
1061 if ( (props.value_id == -1) ||
1062 (tbl_types_ethereal[props.type] != FT_UINT32) )
1063 /* unknown or unexpected, just text */
1064 proto_tree_add_text(pt, tvb, boffset,
1066 textfmt_e, boffset, clsstr, constr, tagstr,
1067 tname, name, value, ename, empty);
1069 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1070 offset - boffset, value,
1071 textfmt_e, boffset, clsstr, constr, tagstr,
1072 tname, name, value, ename, matchind);
1073 if (props.type_id != -1)
1074 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1075 boffset, offset - boffset, value);
1078 if ( (props.value_id == -1) ||
1079 (tbl_types_ethereal[props.type] != FT_UINT32) )
1080 /* unknown or unexpected, just text */
1081 proto_tree_add_text(pt, tvb, boffset,
1083 "(%s)%s: %d:%s", tname, name, value, ename);
1085 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1086 offset - boffset, value,
1087 "(%s)%s: %d:%s ~", tname, name, value, ename);
1088 if (props.type_id != -1)
1089 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1090 boffset, offset - boffset, value);
1096 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1097 asn1_close(&asn1, &offset); /* mark where we are now */
1099 if ( (props.value_id == -1) ||
1100 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1101 /* unknown or unexpected, just text */
1102 proto_tree_add_text(pt, tvb, boffset,
1104 textfmt_s, boffset, clsstr, constr, tagstr,
1105 tname, name, value? "true" : "false", empty);
1107 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1108 offset - boffset, value != 0,
1109 textfmt_s, boffset, clsstr, constr, tagstr,
1110 tname, name, value? "true" : "false", matchind);
1111 if (props.type_id != -1)
1112 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1113 boffset, offset - boffset, value != 0);
1116 if ( (props.value_id == -1) ||
1117 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1118 /* unknown or unexpected, just text */
1119 proto_tree_add_text(pt, tvb, boffset,
1121 "(%s)%s: %s", tname, name,
1122 value? "true" : "false");
1124 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1125 offset - boffset, value != 0,
1126 "(%s)%s: %s ~", tname, name,
1127 value? "true" : "false");
1128 if (props.type_id != -1)
1129 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1130 boffset, offset - boffset, value != 0);
1143 /* read value, \0 terminated */
1144 ret = asn1_string_value_decode(&asn1, len, &octets);
1145 asn1_close(&asn1, &offset); /* mark where we are now */
1146 ename = showoctets(octets, len, (tag == ASN1_OTS) ? 4 : 0 );
1148 if ( (props.value_id == -1) ||
1149 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1150 /* unknown or unexpected, just text */
1151 proto_tree_add_text(pt, tvb, boffset,
1153 textfmt_s, boffset, clsstr, constr, tagstr,
1154 tname, name, ename, empty);
1156 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1157 offset - boffset, octets, /* \0 termnated */
1158 textfmt_s, boffset, clsstr, constr, tagstr,
1159 tname, name, ename, matchind);
1160 if (props.type_id != -1)
1161 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1162 boffset, offset - boffset, octets);
1165 if ( (props.value_id == -1) ||
1166 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1167 /* unknown or unexpected, just text */
1168 proto_tree_add_text(pt, tvb, boffset,
1170 "(%s)%s: %s", tname, name, ename);
1172 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1173 offset - boffset, octets, /* \0 terminated */
1174 "(%s)%s: %s ~", tname, name, ename);
1175 if (props.type_id != -1)
1176 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1177 boffset, offset - boffset, octets);
1185 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1186 asn1_close(&asn1, &offset); /* mark where we are now */
1187 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1189 if ( (props.value_id == -1) ||
1190 (tbl_types_ethereal[props.type] != FT_UINT32) )
1191 /* unknown or unexpected, just text */
1192 proto_tree_add_text(pt, tvb, boffset,
1194 textfmt_b, boffset, clsstr, constr, tagstr,
1196 showbits(bits, (con*8)-unused), ename, empty);
1198 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1199 offset - boffset, *bits, /* XXX length ? XXX */
1200 textfmt_b, boffset, clsstr, constr, tagstr,
1202 showbits(bits, (con*8)-unused),ename, matchind);
1203 if (props.type_id != -1)
1204 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1205 boffset, offset - boffset, *bits);
1209 if ( (props.value_id == -1) ||
1210 (tbl_types_ethereal[props.type] != FT_UINT32) )
1211 /* unknown or unexpected, just text */
1212 proto_tree_add_text(pt, tvb, boffset,
1214 "(%s)%s: %s:%s", tname, name,
1215 showbits(bits, (con*8)-unused), ename);
1217 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1218 offset - boffset, *bits, /* XXX length ? XXX */
1219 "(%s)%s: %s:%s ~", tname, name,
1220 showbits(bits, (con*8)-unused), ename);
1221 if (props.type_id != -1)
1222 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1223 boffset, offset - boffset, *bits);
1231 /* show full sequence length */
1234 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1236 if ( (props.flags & OUT_FLAG_constructed))
1237 ename = ", unexpected constructed";
1239 if (props.value_id == -1)
1240 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1241 textfmt_c, boffset, clsstr, constr, tagstr,
1242 tname, name, ename, empty);
1244 ti = proto_tree_add_item(pt, props.value_id, tvb,
1246 /* change te text to to what I really want */
1247 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1248 tagstr, tname, name, ename, matchind);
1249 if (props.type_id != -1)
1250 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1254 if (props.value_id == -1) {
1255 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1256 ti = proto_tree_add_text(pt, tvb, boffset,
1257 offset - boffset + len,
1258 "(%s)%s", tname, name);
1260 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1261 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1262 boffset, offset - boffset + len,
1263 "(%s)%s ~", tname, name);
1265 /* don't care about the text */
1266 ti = proto_tree_add_item_hidden(pt, props.value_id, tvb,
1269 if (props.type_id != -1)
1270 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1274 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1276 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1277 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1281 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1283 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1284 proto_item_set_len(ti, offset - boffset);
1289 if (asn1_debug) { /* don't show if not debugging */
1290 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1291 boffset, clsstr, constr, tagstr, tname, name,
1292 offset - soffset, empty);
1294 getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1298 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1299 asn1_close(&asn1, &offset); /* mark where we are now */
1300 ename = showoid(oid, con);
1302 if ( (props.value_id == -1) ||
1303 (tbl_types_ethereal[props.type] != FT_BYTES) )
1304 /* unknown or unexpected, just text */
1305 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1306 boffset, clsstr, constr, tagstr, tname, name,
1309 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1310 offset - boffset, ename,/* XXX length?*/
1311 "(%s)%s: %s ~", tname, name, ename);
1312 if (props.type_id != -1)
1313 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1314 boffset, offset - boffset, ename);
1317 if ( (props.value_id == -1) ||
1318 (tbl_types_ethereal[props.type] != FT_BYTES) )
1319 /* unknown or unexpected, just text */
1320 proto_tree_add_text(pt, tvb, boffset,
1322 "(%s)%s: %s", tname, name, ename);
1324 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1325 offset - boffset, ename, /* XXX length ? */
1326 "(%s)%s: %s ~", tname, name, ename);
1327 if (props.type_id != -1)
1328 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1329 boffset, offset - boffset, ename);
1337 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1338 boffset, clsstr, constr, tagstr, tname, name,
1341 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1342 "(%s)%s: [NULL]", tname, name);
1344 offset += len; /* skip value ... */
1356 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1357 textfmt_s, boffset, clsstr, constr, tagstr,
1358 tname, name, lenbuf, empty);
1360 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1361 "(%s)%s: %s bytes", tname, name, lenbuf);
1363 proto_item_append_text(ti, " *"); /* indicate default is used */
1364 offset += len; /* skip value ... */
1369 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1370 case ASN1_APL: /* fprintf(stderr, "Application\n"); */
1371 case ASN1_PRV: /* fprintf(stderr, "Private\n"); */
1374 if (props.value_id == -1) /* type unknown, handle as string */
1376 switch(props.type) {
1377 /* this is via the asn1 description, don't trust the length */
1381 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1382 asn1_close(&asn1, &offset); /* mark where we are now */
1384 if ( (props.value_id == -1) ||
1385 (tbl_types_ethereal[props.type] != FT_UINT32) )
1386 /* unknown or unexpected, just text */
1387 proto_tree_add_text(pt, tvb,
1388 boffset, offset - boffset,
1389 textfmt_d, boffset, clsstr, constr,
1390 tagstr, tname, name, value, empty);
1392 proto_tree_add_uint_format(pt, props.value_id, tvb,
1393 boffset, offset - boffset, value,
1394 textfmt_d, boffset, clsstr, constr,
1395 tagstr, tname, name, value, matchind);
1396 if (props.type_id != -1)
1397 proto_tree_add_uint_hidden(pt, props.type_id,
1398 tvb, boffset, offset - boffset, value);
1401 if ( (props.value_id == -1) ||
1402 (tbl_types_ethereal[props.type] != FT_UINT32) )
1403 /* unknown or unexpected, just text */
1404 proto_tree_add_text(pt, tvb,
1405 boffset, offset - boffset,
1406 "(%s)%s: %d", tname, name, value);
1408 proto_tree_add_uint_format(pt, props.value_id, tvb,
1409 boffset, offset - boffset, value,
1410 "(%s)%s: %d ~", tname, name, value);
1411 if (props.type_id != -1)
1412 proto_tree_add_uint_hidden(pt, props.type_id,
1413 tvb, boffset, offset - boffset, value);
1418 case TBL_ENUMERATED:
1421 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1422 asn1_close(&asn1, &offset); /* mark where we are now */
1423 ename = getPDUenum(&props, boffset, cls, tag, value);
1425 if ( (props.value_id == -1) ||
1426 (tbl_types_ethereal[props.type] != FT_UINT32) )
1427 /* unknown or unexpected, just text */
1428 proto_tree_add_text(pt, tvb,
1429 boffset, offset - boffset,
1430 textfmt_e, boffset, clsstr, constr,
1431 tagstr, tname, name, value, ename, empty);
1433 proto_tree_add_uint_format(pt, props.value_id, tvb,
1434 boffset, offset - boffset, value,
1435 textfmt_e, boffset, clsstr, constr,
1436 tagstr, tname, name, value, ename, matchind);
1437 if (props.type_id != -1)
1438 proto_tree_add_uint_hidden(pt, props.type_id,
1439 tvb, boffset, offset - boffset, value);
1442 if ( (props.value_id == -1) ||
1443 (tbl_types_ethereal[props.type] != FT_UINT32) )
1444 /* unknown or unexpected, just text */
1445 proto_tree_add_text(pt, tvb,
1446 boffset, offset - boffset,
1447 "(%s)%s: %d:%s", tname, name, value, ename);
1449 proto_tree_add_uint_format(pt, props.value_id, tvb,
1450 boffset, offset - boffset, value,
1451 "(%s)%s: %d:%s ~", tname, name, value, ename);
1452 if (props.type_id != -1)
1453 proto_tree_add_uint_hidden(pt, props.type_id,
1454 tvb, boffset, offset - boffset, value);
1459 if (len > (1+4)) /* max 32 bits ...?.. */
1462 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1463 asn1_close(&asn1, &offset); /* mark where we are now */
1464 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1466 if ( (props.value_id == -1) ||
1467 (tbl_types_ethereal[props.type] != FT_UINT32) )
1468 /* unknown or unexpected, just text */
1469 proto_tree_add_text(pt, tvb,
1470 boffset, offset - boffset,
1471 textfmt_b, boffset, clsstr, constr,
1472 tagstr, tname, name,
1473 showbits(bits, (con*8)-unused), ename,
1476 proto_tree_add_uint_format(pt, props.value_id, tvb,
1477 boffset, offset - boffset, *bits,
1478 textfmt_b, boffset, clsstr, constr,
1479 tagstr, tname, name,
1480 showbits(bits, (con*8)-unused), ename,
1482 if (props.type_id != -1)
1483 proto_tree_add_uint_hidden(pt, props.type_id,
1484 tvb, boffset, offset - boffset, *bits);
1487 if ( (props.value_id == -1) ||
1488 (tbl_types_ethereal[props.type] != FT_UINT32) )
1489 /* unknown or unexpected, just text */
1490 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1491 "(%s)%s: %s:%s", tname, name,
1492 showbits(bits, (con*8)-unused), ename);
1494 proto_tree_add_uint_format(pt, props.value_id, tvb,
1495 boffset, offset - boffset, *bits,
1496 "(%s)%s: %s:%s ~", tname, name,
1497 showbits(bits, (con*8)-unused), ename);
1498 if (props.type_id != -1)
1499 proto_tree_add_uint_hidden(pt, props.type_id,
1500 tvb, boffset, offset - boffset, *bits);
1508 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1509 asn1_close(&asn1, &offset); /* mark where we are now */
1511 if ( (props.value_id == -1) ||
1512 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1513 /* unknown or unexpected, just text */
1514 proto_tree_add_text(pt, tvb,
1515 boffset, offset - boffset,
1516 textfmt_s, boffset, clsstr, constr,
1517 tagstr, tname, name,
1518 value? "true" : "false", empty);
1520 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1521 boffset, offset - boffset, value != 0,
1522 textfmt_s, boffset, clsstr, constr,
1523 tagstr, tname, name,
1524 value? "true" : "false", matchind);
1525 if (props.type_id != -1)
1526 proto_tree_add_boolean_hidden(pt, props.type_id,
1527 tvb, boffset, offset - boffset, value != 0);
1530 if ( (props.value_id == -1) ||
1531 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1532 /* unknown or unexpected, just text */
1533 proto_tree_add_text(pt, tvb,
1534 boffset, offset - boffset,
1535 "(%s)%s: %s", tname, name,
1536 value? "true" : "false");
1538 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1539 boffset, offset - boffset, value != 0,
1540 "(%s)%s: %s ~", tname, name,
1541 value? "true" : "false");
1542 if (props.type_id != -1)
1543 proto_tree_add_boolean_hidden(pt, props.type_id,
1544 tvb, boffset, offset - boffset, value != 0);
1552 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1553 textfmt_s, boffset, clsstr, constr,
1554 tagstr, tname, name, "[NULL]", empty);
1556 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1557 "(%s)%s: [NULL]", tname, name);
1559 offset += len; /* skip value ... */
1563 props.value_id = -1; /* unlikely this is correct, dont use it */
1565 case TBL_OCTETSTRING:
1566 /* defined length, not constructed, must be a string.... */
1567 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1568 asn1_close(&asn1, &offset); /* mark where we are now */
1569 ename = showoctets(octets, len, 2); /* convert octets to printable */
1571 if ( (props.value_id == -1) ||
1572 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1573 /* unknown or unexpected, just text */
1574 proto_tree_add_text(pt, tvb,
1575 boffset, offset - boffset,
1576 textfmt_s, boffset, clsstr, constr,
1577 tagstr, tname, name, ename, empty);
1579 proto_tree_add_string_format(pt, props.value_id, tvb,
1580 boffset, offset - boffset, octets, /* XXX */
1581 textfmt_s, boffset, clsstr, constr,
1582 tagstr, tname, name, ename, matchind);
1583 if (props.type_id != -1)
1584 proto_tree_add_string_hidden(pt, props.type_id,
1585 tvb, boffset, offset - boffset, octets);
1588 if ( (props.value_id == -1) ||
1589 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1590 /* unknown or unexpected, just text */
1591 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1592 "(%s)%s: %s", tname, name, ename);
1594 proto_tree_add_string_format(pt, props.value_id, tvb,
1595 boffset, offset - boffset, octets, /* XXX */
1596 "(%s)%s: %s ~", tname, name, ename);
1597 if (props.type_id != -1)
1598 proto_tree_add_string_hidden(pt, props.type_id,
1599 tvb, boffset, offset - boffset, octets);
1607 /* indefinite length or constructed.... must be a sequence .... */
1608 /* show full sequence length */
1611 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1613 if ( (props.flags & OUT_FLAG_constructed))
1614 ename = ", unexpected constructed";
1616 if (props.value_id == -1)
1617 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1618 textfmt_c, boffset, clsstr, constr,
1619 tagstr, tname, name, ename, empty);
1621 ti = proto_tree_add_item(pt, props.value_id, tvb,
1623 /* change te text to to what I really want */
1625 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1626 tagstr, tname, name, ename, matchind);
1627 if (props.type_id != -1)
1628 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1631 ti = proto_tree_add_text(pt, tvb, boffset,
1632 offset - boffset + len,
1633 textfmt_c, boffset, clsstr, constr,
1634 tagstr, tname, name, ename, empty);
1638 if (props.value_id == -1) {
1639 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1640 ti = proto_tree_add_text(pt, tvb, boffset,
1641 offset - boffset + len, "(%s)%s", tname, name);
1643 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1644 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1646 "(%s)%s ~", tname, name);
1648 /* don't care about the text */
1649 ti = proto_tree_add_item_hidden(pt, props.value_id,
1650 tvb, boffset, 1, TRUE);
1652 if (props.type_id != -1)
1653 proto_tree_add_item_hidden(pt, props.type_id,
1654 tvb, boffset, 1, TRUE);
1658 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1660 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1661 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1665 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1667 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1668 proto_item_set_len(ti, offset - boffset);
1672 default: /* fprintf(stderr, "Other\n"); */
1674 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1675 textfmt_s, boffset, clsstr, constr, tagstr,
1676 tname, name, lenbuf, empty);
1678 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1679 "(%s)%s: %s bytes %s data", tname, name,
1682 proto_item_append_text(ti, " *"); /* indicate default is used */
1683 offset += len; /* skip value ... */
1686 g_free(oname); /* XXX, memory management ? */
1688 /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1690 getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1697 /************************************************************************************************/
1698 /* search throug the ASN.1 description for appropriate names */
1699 /************************************************************************************************/
1701 guint lev_limit = G_MAXINT;
1703 int icount = 0; /* item counter */
1706 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1709 guint eos, ret, cls, con, tag, def, len, value;
1710 guchar *octets, *bits, unused;
1712 const char *clsstr, *constr, *tagstr;
1715 GNode *cur_node = 0;
1717 eos = offset + size;
1719 if (level > lev_limit)
1722 while(offset < eos) {
1723 if (ptr) /* build pointer tree to all asn1 enteties */
1724 cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
1726 asn1_open(&asn1, tvb, offset);
1727 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1728 asn1_close(&asn1, &offset); /* mark where we are */
1730 clsstr = asn1_cls[cls];
1731 constr = asn1_con[con];
1732 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1733 tagstr = asn1_tag[tag];
1735 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1739 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1741 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1742 len = tvb_length_remaining(tvb, offset);
1746 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
1750 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1751 asn1_close(&asn1, &offset); /* mark where we are */
1755 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1756 asn1_close(&asn1, &offset); /* mark where we are */
1767 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1768 asn1_close(&asn1, &offset); /* mark where we are */
1773 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1774 asn1_close(&asn1, &offset); /* mark where we are */
1780 if (len == 0) /* don't recurse if offset isn't going to change */
1783 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1790 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1791 asn1_close(&asn1, &offset); /* mark where we are */
1807 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1808 offset += len; /* skip value ... */
1813 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1815 g_snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
1817 /* defined length, not constructed, must be a string.... */
1818 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1819 asn1_close(&asn1, &offset); /* mark where we are */
1822 /* indefinite length or constructed.... must be a sequence .... */
1823 if (len == 0) /* don't recurse if offset isn't going to change */
1826 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1830 default: /* fprintf(stderr, "Other\n"); */
1831 if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1832 offset += len; /* skip value ... */
1839 static void showGNodes(GNode *p, int n);
1843 myLeaf(GNode *node, gpointer data)
1846 guint ret, cls, con, tag, def, len;
1847 char *clsstr, *constr, *tagstr;
1851 (void) data; /* make a reference */
1852 asn1_open(&asn1, asn1_desc, (int)node->data);
1854 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1856 clsstr = asn1_cls[cls];
1857 constr = asn1_con[con];
1858 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1859 tagstr = asn1_tag[tag];
1861 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1865 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1867 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1871 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1879 if (asn1_verbose) g_message("build GNode tree:");
1880 showGNodes(g_node_first_child(asn1_nodes), 0);
1881 if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1882 g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1883 g_node_max_height (asn1_nodes),
1884 g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1885 g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1887 g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1893 tt_build_tree(void) /* build a GNode tree with all offset's to ASN.1 entities */
1896 g_node_destroy(asn1_nodes);
1897 asn1_nodes = g_node_new(0);
1899 parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1903 /*****************************************************************************************************/
1905 static guint anonCount; /* for naming anonymous types */
1907 typedef struct _TBLModule TBLModule;
1908 typedef struct _TBLTypeDef TBLTypeDef;
1909 typedef struct _TBLTag TBLTag;
1910 typedef struct _TBLType TBLType;
1911 typedef struct _TBLTypeRef TBLTypeRef;
1912 typedef struct _TBLNamedNumber TBLNamedNumber;
1913 typedef struct _TBLRange TBLRange;
1921 TBLTYPE_NamedNumber,
1924 typedef enum _tbl_t tbl_t;
1925 /* text for 'tbl_t' type for debugging */
1926 static const char *data_types[] = {
1936 enum _TBLTypeContent_t {
1938 TBLTYPETYPE_Primitive,
1939 TBLTYPETYPE_Elements,
1942 typedef enum _TBLTypeContent_t TBLTypeContent_t;
1944 struct _TBLNamedNumber {
1956 struct _TBLTypeRef {
1972 TBLTypeContent_t content;
1975 gboolean constraint;
1978 struct _TBLTypeDef {
1993 guint totalNumModules;
1994 guint totalNumTypeDefs;
1995 guint totalNumTypes;
1997 guint totalNumStrings;
1998 guint totalLenStrings;
2001 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2004 get_asn1_int(guint want_tag, guint offset)
2007 guint ret, cls, con, tag, def, len;
2010 /* g_message("%d get_asn1_int", offset); */
2012 asn1_open(&asn1, asn1_desc, offset);
2014 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2015 if (ret == ASN1_ERR_NOERROR) {
2016 /* do not check class, both Unversal and Context are OK */
2017 if (con == ASN1_PRI && tag == want_tag) {
2019 asn1_uint32_value_decode(&asn1, len, &value);
2022 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2024 ret = ASN1_ERR_WRONG_TYPE;
2026 g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2031 static subid_t * /* with prepended length ..... */
2032 get_asn1_oid(guint want_tag, guint offset)
2035 guint ret, cls, con, tag, def, len;
2038 /* g_message("%d get_asn1_oid", offset); */
2040 asn1_open(&asn1, asn1_desc, offset);
2042 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2043 if (ret == ASN1_ERR_NOERROR) {
2044 /* do not check class, both Unversal and Context are OK */
2045 if ((con == ASN1_PRI) && (tag == want_tag)) {
2047 asn1_oid_value_decode(&asn1, len, &oid, &con);
2048 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2049 memmove(&oid[1], oid, con*sizeof(guint));
2053 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2055 ret = ASN1_ERR_WRONG_TYPE;
2057 g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2062 static guchar * /* 0 terminated string */
2063 get_asn1_string(guint want_tag, guint offset)
2066 guint ret, cls, con, tag, def, len;
2069 /* g_message("%d get_asn1_string", offset); */
2071 asn1_open(&asn1, asn1_desc, offset);
2073 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2074 if (ret == ASN1_ERR_NOERROR) {
2075 /* do not check class, both Unversal and Context are OK */
2076 if ((con == ASN1_PRI) && (tag == want_tag)) {
2078 asn1_string_value_decode(&asn1, len, &octets);
2079 octets = g_realloc(octets, len+1); /* need space for sentinel */
2083 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2085 ret = ASN1_ERR_WRONG_TYPE;
2087 g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2093 get_asn1_uint(guint offset)
2096 guint ret, len, value;
2098 /* g_message( "%d get_asn1_uint", offset); */
2100 asn1_open(&asn1, asn1_desc, offset);
2102 ret = asn1_uint32_decode(&asn1, &value, &len);
2104 if (ret != ASN1_ERR_NOERROR) {
2105 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2112 check_tag(guint want_tag, guint offset)
2115 guint ret, cls, con, tag, def, len;
2117 asn1_open(&asn1, asn1_desc, offset);
2119 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2120 if (ret == ASN1_ERR_NOERROR) {
2121 ret = (tag == want_tag) ? TRUE : FALSE;
2122 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2125 g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2132 constructed(guint offset)
2135 guint ret, cls, con, tag, def, len;
2137 /* g_message("%d constructed?", offset); */
2139 asn1_open(&asn1, asn1_desc, offset);
2141 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2142 if (ret == ASN1_ERR_NOERROR) {
2148 /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2155 define_constraint(GNode *p, GNode *q)
2157 TBLRange *range = g_malloc(sizeof(TBLRange));
2158 g_node_append_data(q, range);
2160 range->type = TBLTYPE_Range;
2162 /* g_message("define_constraint %p, %p", p, q); */
2164 p = g_node_first_child(p);
2166 range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2167 p = g_node_next_sibling(p);
2169 range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2174 define_namednumber(GNode *p, GNode *q)
2176 TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2177 g_node_append_data(q, num);
2179 num->type = TBLTYPE_NamedNumber;
2181 /* g_message("define_namednumber %p, %p", p, q); */
2183 p = g_node_first_child(p);
2185 num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2186 p = g_node_next_sibling(p);
2188 num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2192 define_typeref(GNode *p, GNode *q)
2194 TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2195 g_node_append_data(q, ref);
2197 ref->type = TBLTYPE_TypeRef;
2199 /* g_message("define_typeref %p, %p", p, q); */
2201 p = g_node_first_child(p);
2203 ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2204 p = g_node_next_sibling(p);
2206 ref->implicit = get_asn1_int(ASN1_BOL, GPOINTER_TO_UINT(p->data));
2210 define_tag(GNode *p, GNode *q)
2212 TBLTag *type = g_malloc(sizeof(TBLTag));
2213 g_node_append_data(q, type);
2215 type->type = TBLTYPE_Tag;
2217 /* g_message("define_tag %p, %p", p, q); */
2219 p = g_node_first_child(p);
2221 type->tclass = get_asn1_int(ASN1_ENUM, GPOINTER_TO_UINT(p->data));
2222 p = g_node_next_sibling(p);
2224 type->code = get_asn1_int(ASN1_INT, GPOINTER_TO_UINT(p->data));
2229 define_type(GNode *p, GNode *q)
2232 TBLType *type = g_malloc(sizeof(TBLType));
2234 GNode *t = g_node_append_data(q, type);
2236 type->type = TBLTYPE_Type;
2238 /* g_message("define_type %p, %p", p, q); */
2240 type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2241 p = g_node_next_sibling(p);
2243 type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2244 p = g_node_next_sibling(p);
2246 if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
2247 r = g_node_first_child(p);
2250 r = g_node_next_sibling(r);
2252 p = g_node_next_sibling(p);
2255 if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
2256 g_warning("expect tag 3, ERROR");
2258 r = g_node_first_child(p);
2260 type->content = TBLTYPETYPE_None;
2261 if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
2262 if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
2263 if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
2264 switch(type->content) {
2265 case TBLTYPETYPE_Primitive:
2267 case TBLTYPETYPE_Elements:
2268 r = g_node_first_child(r);
2270 define_type(g_node_first_child(r), t);
2271 r = g_node_next_sibling(r);
2274 case TBLTYPETYPE_TypeRef:
2275 define_typeref(r, t);
2277 case TBLTYPETYPE_None:
2278 g_warning("expected a contents choice, error");
2281 p = g_node_next_sibling(p);
2283 type->fieldName = 0;
2284 type->anonymous = FALSE;
2285 if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
2286 type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
2287 p = g_node_next_sibling(p);
2289 type->anonymous = TRUE;
2292 type->constraint = FALSE;
2293 if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
2294 type->constraint = TRUE;
2295 define_constraint(p, t);
2296 p = g_node_next_sibling(p);
2299 if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
2300 r = g_node_first_child(p);
2302 define_namednumber(r, t);
2303 r = g_node_next_sibling(r);
2309 define_typedef(GNode *p, GNode *q)
2311 TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2313 GNode *t = g_node_append_data(q, type_def);
2315 /* g_message("define_typedef %p, %p", p, q); */
2317 type_def->type = TBLTYPE_TypeDef;
2319 p = g_node_first_child(p);
2321 type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2322 p = g_node_next_sibling(p);
2324 type_def->typeName = get_asn1_string(ASN1_PRNSTR, GPOINTER_TO_UINT(p->data));
2325 p = g_node_next_sibling(p);
2327 define_type(g_node_first_child(p), t);
2328 p = g_node_next_sibling(p);
2330 type_def->isPdu = (p != 0); /* true if it exists, value ignored */
2334 define_module(GNode *p, GNode *q)
2336 TBLModule *module = g_malloc(sizeof(TBLModule));
2338 GNode *m = g_node_append_data(q, module);
2340 /* g_message("define_module %p %p", p, q); */
2342 module->type = TBLTYPE_Module;
2344 p = g_node_first_child(p);
2346 module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2347 p = g_node_next_sibling(p);
2350 if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */
2351 module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
2352 p = g_node_next_sibling(p);
2355 module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
2356 p = g_node_next_sibling(p);
2358 p = g_node_first_child(p);
2360 define_typedef(p, m);
2361 p = g_node_next_sibling(p);
2365 typedef struct _SearchDef SearchDef;
2372 is_typedef(GNode *node, gpointer data)
2374 TBLTypeDef *d = (TBLTypeDef *)node->data;
2375 SearchDef *s = (SearchDef *)data;
2377 if (d == 0) return FALSE;
2378 if (d->type != TBLTYPE_TypeDef) return FALSE;
2379 if (strcmp(s->key, d->typeName) == 0) {
2386 typedef struct _TypeRef TypeRef;
2392 GNode *pdu; /* location in PDU descriptor tree */
2393 guint level; /* recursion counter */
2395 GPtrArray *refs; /* pointers to PDUinfo structures teferencing this entry */
2398 typedef struct _NameDefs NameDefs;
2404 #define ALLOC_INCR 4
2405 #define CLASSREF (ASN1_PRV+1)
2408 is_named(GNode *node, gpointer data)
2410 TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2411 NameDefs *n = (NameDefs *)data;
2414 if (num == 0) return FALSE;
2415 if (num->type != TBLTYPE_NamedNumber) return FALSE;
2417 if (num->value >= n->max) { /* need larger array */
2419 n->max = num->value + ALLOC_INCR;
2420 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2421 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2423 if (num->value > n->used) /* track max used value, there may be holes... */
2424 n->used = num->value;
2426 n->info[num->value].name = num->name;
2432 index_typedef(GNode *node, gpointer data)
2434 TBLTypeDef *d = (TBLTypeDef *)node->data;
2435 NameDefs *n = (NameDefs *)data;
2440 if (d == 0) return FALSE;
2441 if (d->type != TBLTYPE_TypeDef) return FALSE;
2443 if (d->typeDefId >= n->max) { /* need larger array */
2445 n->max = d->typeDefId + ALLOC_INCR;
2446 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2447 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2449 if (d->typeDefId > n->used) /* track max used value, there may be holes... */
2450 n->used = d->typeDefId;
2452 t = &(n->info[d->typeDefId]);
2453 t->name = d->typeName;
2455 t->refs = g_ptr_array_new(); /* collect references here */
2456 node = g_node_first_child(node); /* the real type */
2457 tag = (TBLTag *)node->data;
2458 if ((tag->type == TBLTYPE_Type) && (((TBLType *)tag)->typeId == TBL_CHOICE)) {
2459 /* no reasonable default... ! */
2460 t->defclass = 3; /* Private .... */
2461 t->deftag= 9999; /* a random value */
2463 node = g_node_first_child(node); /* the default tag */
2464 tag = (TBLTag *)node->data;
2467 t->defclass = tag->tclass;
2468 t->deftag = tag->code;
2470 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2471 t->defclass = CLASSREF; /* invalid class.. */
2472 t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2475 g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2476 data_types[tag->type]);
2477 t->defclass = 3; /* Private .... */
2478 t->deftag= 9998; /* another random value */
2486 static TypeRef *typeDef_names = 0;
2487 static guint numTypedefs = 0;
2490 free_node_data(GNode *node, gpointer data _U_)
2497 get_values(void) /* collect values from ASN.1 tree */
2498 /* coded according to the tbl.asn1 description of snacc output */
2499 { /* This routine does not leave references to the tvbuff or */
2500 /* to the asn1_nodes, both can be freed by the caller of this.*/
2506 const char *t, *s, *E;
2507 static char missing[] = " **missing** ";
2509 if (asn1_verbose) g_message("interpreting tree");
2510 typeDef_names = 0; /* just forget allocated any data .... */
2513 g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2514 free_node_data, NULL);
2515 g_node_destroy(data_nodes);
2518 data_nodes = g_node_new(0);
2520 p = g_node_first_child(asn1_nodes); /* top of the data tree */
2522 p = g_node_first_child(p);
2523 TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2524 p = g_node_next_sibling(p);
2525 TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2526 p = g_node_next_sibling(p);
2527 TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2528 p = g_node_next_sibling(p);
2529 TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2530 p = g_node_next_sibling(p);
2531 TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2532 p = g_node_next_sibling(p);
2533 TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2534 p = g_node_next_sibling(p);
2536 p = g_node_first_child(p);
2538 define_module(p, data_nodes);
2539 p = g_node_next_sibling(p);
2542 /* g_message("finished with tree"); */
2544 if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2545 sd.key = "TBLTypeId";
2547 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2548 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", sd.here);
2552 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2553 g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2555 if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, nd.info);
2557 for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2560 s = nd.info[i].name;
2561 if (s == 0) s = missing;
2562 if (g_strcmp(t, s) == 0) { /* OK ! */
2566 E = ", X with errors X";
2568 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2570 if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2572 tbl_types_verified = TRUE;
2574 /* build table with typedef names */
2577 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2578 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2579 if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, nd.info);
2581 for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2582 TypeRef *ref = &(nd.info[i]);
2585 t = ref->name = missing;
2586 if (asn1_verbose) g_message(" %3d %s", i, t);
2588 if (asn1_verbose) g_message(" %3d %s, %c%d", i, t,
2589 tag_class[ref->defclass], ref->deftag);
2591 if (ref->pdu) { /* should be 0 */
2592 if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, ref->pdu);
2595 typeDef_names = nd.info;
2597 if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
2602 showGNode(GNode *p, int n)
2605 n *=2; /* 2 spaces per level */
2606 if (p->data) { /* show value ... */
2607 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
2608 switch (((TBLTag *)p->data)->type) {
2609 case TBLTYPE_Module: {
2610 TBLModule *m = (TBLModule *)p->data;
2612 g_message("%*smodule %s%s", n, empty, m->name,
2613 m->isUseful ? ", useful" : empty);
2616 case TBLTYPE_TypeDef: {
2617 TBLTypeDef *t = (TBLTypeDef *)p->data;
2619 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
2620 t->isPdu ? ", isPDU" : empty);
2623 case TBLTYPE_Type: {
2624 TBLType *t = (TBLType *)p->data;
2625 const char *fn, *s = empty;
2628 /* typeId is a value from enum TBLTypeId */
2629 fn = TBLTYPE(t->typeId);
2630 if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
2631 t->optional ? " opt" : empty, s );
2635 TBLTag *t = (TBLTag *)p->data;
2636 const char *s = empty;
2637 if ((t->tclass == ASN1_UNI) && (t->code < 32))
2638 s = asn1_tag[t->code];
2639 if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
2640 tag_class[t->tclass], t->code, s);
2643 case TBLTYPE_NamedNumber: {
2644 TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
2645 if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
2646 nn->value, nn->name);
2649 case TBLTYPE_Range: {
2650 TBLRange *r = (TBLRange *)p->data;
2651 if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
2655 case TBLTYPE_TypeRef: {
2656 TBLTypeRef *r = (TBLTypeRef *)p->data;
2657 const char *s = empty;
2659 s = typeDef_names[r->typeDefId].name;
2660 if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
2661 r->typeDefId, s, r->implicit ? ", implicit" : empty );
2665 TBLTag *x = (TBLTag *)p->data;
2666 if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
2670 } else { /* just show tree */
2672 g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
2673 n, empty, p, p->data, p->next, p->prev, p->parent, p->children);
2678 showGNodes(GNode *p, int n)
2682 showGNodes(p->children, n+1);
2683 showGNodes(p->next, n);
2686 static void showGenv(GNode *p, int n, int m)
2692 if (asn1_verbose) g_message("%*s.....", n*2, empty);
2696 for(i=0; p && (i < 3); p = p->next, i++) {
2698 showGenv(p->children, n+1, m);
2700 if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
2705 debug_dump_TT(void) /* dump contents of TT struct, for debugging */
2708 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
2710 TT.totalNumTypeDefs,
2714 TT.totalLenStrings);
2718 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
2719 const gchar *message, gpointer user_data)
2721 static FILE* logf = 0;
2722 static char eol[] = "\r\n";
2724 (void) log_domain; (void) log_level; (void) user_data; /* make references */
2726 if (logf == NULL && asn1_logfile) {
2727 logf = eth_fopen(asn1_logfile, "w");
2730 fputs(message, logf);
2732 fflush(logf); /* debugging ... */
2737 read_asn1_type_table(const char *filename)
2744 if ((filename == 0) || (strlen(filename) == 0))
2745 return; /* no filename provided */
2747 f = eth_fopen(filename, "rb");
2750 * Ignore "file not found" errors if it's the old default
2751 * ASN.1 file name, as we never shipped such a file.
2752 * Also, on Win32, ignore the earlier default, which
2753 * had a "/" rather than a "\" as the last pathname
2756 if ((strcmp(filename, old_default_asn1_filename) != 0
2758 && strcmp(filename, bad_separator_old_default_asn1_filename) != 0
2760 ) || errno != ENOENT)
2761 report_open_failure(filename, errno, FALSE);
2764 fstat(fileno(f), &stat);
2765 size = (int)stat.st_size;
2767 if (asn1_verbose) g_message("file %s is empty, ignored", filename);
2771 if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
2773 data = g_malloc(size);
2774 if (fread(data, size, 1, f) < 1) {
2775 g_warning("error reading %s, %s", filename, strerror(errno));
2780 /* ***** from the time when logging was just in a console... *****
2781 * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
2782 * " Sleep 5 sec...");
2786 static guint mylogh = 0;
2788 g_message("logging to file %s", asn1_logfile);
2791 mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2792 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
2796 asn1_desc = tvb_new_real_data(data, size, size);
2799 if (asn1_verbose) g_message("read %d items from %s", icount, filename);
2807 g_node_destroy(asn1_nodes); asn1_nodes = 0;
2808 #ifndef _WIN32 /* tvb_free not yet exported to plugins... */
2809 tvb_free(asn1_desc);
2812 g_free(data); data = 0;
2814 showGNodes(data_nodes, 0);
2820 /* XXX - Shoudn't we make sure we're not dereferencing a NULL pointer here? */
2821 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
2822 g_warning("**** unexpected type %s, want %s, at line %d", \
2823 data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
2827 save_reference(PDUinfo *p)
2834 g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
2838 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex);
2842 /* evaluate typeref, pointer to current pdu node and typedef */
2844 tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
2847 PDUinfo *p = (PDUinfo *)pdu->data, *p1;
2851 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
2852 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
2856 CHECKTYPE(tree, TBLTYPE_TypeDef);
2858 if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
2859 p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2861 p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
2862 p->flags |= PDU_TYPEDEF;
2864 tree = g_node_first_child(tree); /* move to its underlying type */
2865 CHECKTYPE(tree, TBLTYPE_Type);
2866 p->type = ((TBLType *)tree->data)->typeId;
2868 q = g_node_first_child(tree); /* the tag of this type entry ... is optional... */
2869 if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
2870 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
2874 /* XXX -- hack -- hack -- hack -- hack -- hack --
2875 * only change tag when class+tag == EOC,
2876 * or class is a reference,
2877 * or new class is not universal.
2879 if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
2880 (((TBLTag *)q->data)->tclass != ASN1_UNI) ) {
2881 p->tclass = ((TBLTag *)q->data)->tclass;
2882 p->tag = ((TBLTag *)q->data)->code;
2884 g_message("%*s*change typeref tag from %c%d to %c%d",
2888 tag_class[p->tclass],
2892 g_message("%*sNOT changing tag from %c%d to %c%d",
2896 tag_class[((TBLTag *)q->data)->tclass],
2897 ((TBLTag *)q->data)->code);
2905 if (p->tclass==CLASSREF)
2906 g_snprintf(ss, 128, ", CLASSREF %d", p->tag);
2907 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
2909 if (p->tclass==CLASSREF) {
2911 int i = p->basetype;
2912 /* CLASSREF....., get it defined using type of the reference */
2914 /* p->basetype may be -1 .... ? XXX */
2917 tr = &typeDef_names[i];
2919 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
2920 p->tag, tr->name, tr->pdu);
2922 tbl_typeref(n+1, pdu, tr->type, fullindex);
2929 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
2930 p->name, p->typename, p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2934 case TBL_ENUMERATED:
2935 /* names do not have a fullname */
2936 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
2937 /* read the enumeration [save min-max somewhere ?] */
2938 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type]; /* XXX change field type... */
2940 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2945 g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2946 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2947 p->name, p->fullname,
2948 tbl_types_ethereal_txt[p->type], p->value_id);
2951 while((q = g_node_next_sibling(q))) {
2952 CHECKTYPE(q, TBLTYPE_NamedNumber);
2953 p = g_malloc0(sizeof(PDUinfo));
2955 p->type = TBL_ENUMERATED;
2956 p->name = (((TBLNamedNumber *)q->data)->name);
2957 p->tag = (((TBLNamedNumber *)q->data)->value);
2958 p->flags = PDU_NAMEDNUM;
2959 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
2960 g_node_append_data(pdu, p);
2963 /* list all enum values in the field structure for matching */
2964 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
2965 q = g_node_first_child(pdu);
2968 p = (PDUinfo *)q->data;
2969 v[nvals].value = p->tag;
2970 v[nvals].strptr = p->name;
2971 /* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
2973 q = g_node_next_sibling(q);
2975 /* last entry is already initialized to { 0, NULL } */
2980 if (p->value_id == -1) { /* not yet registered ..... */
2981 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
2982 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2987 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2988 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2989 p->name, p->fullname,
2990 tbl_types_ethereal_txt[p->type], p->value_id);
2992 tbl_type(n, pdu, q, fullindex);
2996 if (p->value_id == -1) { /* not yet registered ..... */
2997 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
2998 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3003 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3004 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3005 p->name, p->fullname,
3006 tbl_types_ethereal_txt[p->type], p->value_id);
3008 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
3013 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
3021 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
3022 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3026 /* showGenv(list, n, n+1); */
3029 pdu1 = pdu; /* save start location for append */
3030 while (list) { /* handle all entries */
3032 g_message("%*s+handle a %s, list=%p", n*2, empty,
3033 data_types[((TBLTag *)list->data)->type], list);
3035 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
3036 list = g_node_next_sibling(list);
3037 if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
3042 /******* change to positive comparation, but leave comment for reference
3043 * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3044 * CHECKTYPE(list, TBLTYPE_Type);
3047 if (((TBLTag *)list->data)->type == TBLTYPE_Type) {
3048 CHECKTYPE(list, TBLTYPE_Type);
3050 p = g_malloc0(sizeof(PDUinfo));
3051 pdu = g_node_append_data(pdu1, p);
3053 p->type = ((TBLType *)list->data)->typeId;
3054 p->typename = tbl_types_asn1[p->type]; /* the default type */
3057 p->basetype = ((PDUinfo *)pdu1->data)->typenum;
3058 p->flags = PDUinfo_initflags;
3059 p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
3060 p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
3062 if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
3063 /* assign an anonymous name [XXX refer to parent typename...] */
3064 ((TBLType *)list->data)->fieldName =
3065 g_strdup_printf("anon%d", anonCount++);
3067 p->name = ((TBLType *)list->data)->fieldName;
3070 ni += snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
3071 p->fullname = g_strdup(fieldname);
3073 /* initialize field info */
3076 p->value_hf.p_id = &(p->value_id);
3077 p->value_hf.hfinfo.name = p->fullname;
3078 p->value_hf.hfinfo.abbrev = p->fullname;
3079 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
3080 p->value_hf.hfinfo.display = BASE_DEC;
3081 p->value_hf.hfinfo.blurb = p->fullname;
3082 /* all the other fields are already 0 ! */
3084 if (p->type < TBL__SIMPLE) {
3085 /* only register fields with a value here, postpone others */
3086 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3091 g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3092 p->mytype, p->typenum, p->basetype, p->flags,
3093 p->typename, p->name, p->fullname,
3094 tbl_types_ethereal_txt[p->type], p->value_id);
3097 q = g_node_first_child(list);
3099 p = (PDUinfo *)pdu->data;
3104 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
3109 case TBL_OCTETSTRING:
3113 CHECKTYPE(q, TBLTYPE_Tag);
3114 p->tclass = ((TBLTag *)q->data)->tclass;
3115 p->tag = ((TBLTag *)q->data)->code;
3119 case TBL_ENUMERATED:
3120 CHECKTYPE(q, TBLTYPE_Tag);
3121 p->tclass = ((TBLTag *)q->data)->tclass;
3122 p->tag = ((TBLTag *)q->data)->code;
3123 if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
3124 /* read the enumeration [save min-max somewhere ?] */
3127 while((q = g_node_next_sibling(q))) {
3128 CHECKTYPE(q, TBLTYPE_NamedNumber);
3129 p = g_malloc0(sizeof(PDUinfo));
3131 p->type = TBL_ENUMERATED;
3132 p->name = (((TBLNamedNumber *)q->data)->name);
3133 p->tag = (((TBLNamedNumber *)q->data)->value);
3134 p->flags = PDU_NAMEDNUM;
3135 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3136 g_node_append_data(pdu, p);
3139 /* list all enum values in the field structure for matching */
3140 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3141 q = g_node_first_child(pdu);
3144 p = (PDUinfo *)q->data;
3145 v[nvals].value = p->tag;
3146 v[nvals].strptr = p->name;
3147 /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3149 q = g_node_next_sibling(q);
3151 /* last entry is already initialized to { 0, NULL } */
3157 case TBL_SEQUENCEOF:
3160 CHECKTYPE(q, TBLTYPE_Tag);
3161 q = g_node_first_child(list);
3162 tbl_type(n+1, pdu, q, ni);
3165 case TBL_TYPEREF: { /* may have a tag ... */
3171 if ( ((TBLTag *)q->data)->type == TBLTYPE_Tag) {
3172 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3173 p->tclass = ((TBLTag *)q->data)->tclass;
3174 p->tag = ((TBLTag *)q->data)->code;
3176 g_message("%*s*insert type tag %c%d", n*2, empty,
3177 tag_class[p->tclass], p->tag);
3179 q = g_node_next_sibling(q);
3180 } else { /* use default tag for this type */
3181 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3182 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != ASN1_UNI)) ||
3183 ((p->tclass | p->tag) == 0 )) {
3184 /* not implicit, use this tag */
3185 p->tclass = tr->defclass;
3186 p->tag = tr->deftag;
3187 if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3188 tag_class[p->tclass], p->tag);
3191 CHECKTYPE(q, TBLTYPE_TypeRef);
3192 i = ((TBLTypeRef *)q->data)->typeDefId;
3194 tr = &typeDef_names[i];
3196 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, tr->pdu);
3197 p->typename = tr->name;
3199 if (tr->defclass == CLASSREF) {
3201 tr->pdu = pdu; /* remember this reference */
3203 tr = &typeDef_names[i];
3205 g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3206 i, tr->name, tr->pdu);
3208 /* evaluate reference if not done before or when below recursion limit */
3209 if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3212 tr->pdu = pdu; /* save for references we leave */
3214 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3216 g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3218 ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3221 tbl_typeref(n+1, pdu, tr->type, ni);
3225 g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3226 p->name, tr->name, tr->pdu);
3227 p->flags |= PDU_REFERENCE;
3228 p->reference = tr->pdu;
3233 g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3238 g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3239 n*2, empty, p->name, p->typename, p, TBLTYPE(p->type),
3240 tag_class[p->tclass], p->tag);
3242 if (p->value_id == -1) { /* not registered before, do it now */
3243 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3248 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3249 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3250 p->name, p->fullname,
3251 tbl_types_ethereal_txt[p->type], p->value_id);
3253 list = g_node_next_sibling(list);
3258 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
3261 const char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3264 tt = TBLTYPE(info->type);
3266 tn = info->typename;
3267 fn = info->fullname;
3268 if (info->flags & PDU_NAMEDNUM)
3269 txt += sprintf(txt, "name: %2d %s", info->tag, nn);
3271 if (info->flags & PDU_TYPEDEF)
3272 txt += sprintf(txt, "def %d: ", info->typenum);
3274 txt += sprintf(txt, " ");
3275 ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3276 txt += sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3277 tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3278 txt += sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
3279 oo = (info->flags & PDU_OPTIONAL) ? ", optional" : empty;
3280 ii = (info->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3281 nn = (info->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3282 an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3283 txt += sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
3284 if (info->flags & PDU_REFERENCE) {
3285 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3286 tt = TBLTYPE(rinfo->type);
3288 tn = rinfo->typename;
3289 fn = rinfo->fullname;
3290 txt += sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3291 if (rinfo->flags & PDU_TYPEDEF)
3292 txt += sprintf(txt, " T%d", rinfo->typenum);
3293 txt += sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3294 oo = (rinfo->flags & PDU_OPTIONAL) ? ", optional" : empty;
3295 ii = (rinfo->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3296 nn = (rinfo->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3297 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3298 tt = (rinfo->flags & PDU_TYPEDEF) ? ", typedef" : empty;
3299 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3300 tr = (rinfo->flags & PDU_TYPETREE) ? ", typetree" : empty;
3301 txt += sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3305 strcpy(txt, "no info available");
3313 showPDUtree(GNode *p, int n)
3319 info = (PDUinfo *)p->data;
3321 PDUtext(text, info);
3323 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3325 showPDUtree(g_node_first_child(p), n+1);
3327 p = g_node_next_sibling(p);
3334 build_pdu_tree(const char *pduname)
3337 guint pdudef, i, tcount;
3341 if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3344 if (asn1_verbose) g_message("no data nodes");
3349 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3351 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3352 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, sd.here, pdudef);
3354 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3358 /* If there's an existing PDU tree, free it */
3360 g_node_traverse(PDUtree, G_POST_ORDER, G_TRAVERSE_ALL, -1,
3361 free_node_data, NULL);
3362 g_node_destroy(PDUtree);
3365 /* initialize the PDU tree, hand craft the root entry */
3367 info = g_malloc0(sizeof(PDUinfo));
3368 info->name = pduname;
3369 info->typename = pduname;
3370 info->type = TBL_SEQUENCEOF;
3371 info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3372 info->flags = PDUinfo_initflags = 0;
3373 info->value_id = -1;
3375 info->basetype = -1;
3376 info->mytype = pdudef;
3378 info->value_hf.p_id = &(info->value_id);
3379 info->value_hf.hfinfo.name = info->fullname;
3380 info->value_hf.hfinfo.abbrev = info->fullname;
3381 info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
3382 info->value_hf.hfinfo.display = BASE_DEC;
3383 info->value_hf.hfinfo.blurb = info->fullname;
3385 anonCount = 0; /* anonymous types counter */
3387 PDUtree = g_node_new(info);
3388 pabbrev_pdu_len = sprintf(fieldname, "%s.%s.", pabbrev, pduname);
3389 sav_len = pabbrev_pdu_len;
3391 /* Now build the tree for this top level PDU */
3393 g_message("******** Define main type %d, %s", pdudef, pduname);
3394 tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1); /* strip initial . for new names */
3397 g_message("%d anonymous types", anonCount);
3399 /* Now make all types used available for matching */
3401 g_message("Define the types that are actually referenced through the top level PDU");
3402 for (i=0, tcount=0; i<numTypedefs; i++) {
3403 TypeRef *tr = &(typeDef_names[i]);
3405 if (tr->pdu) { /* ignore if not used in main pdu */
3408 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3410 g_message("******** Define type %d, %s", i, tr->name);
3412 /* .... do definition ..... */
3413 info = g_malloc0(sizeof(PDUinfo));
3414 info->name = tr->name;
3415 info->typename = tr->name;
3416 info->tclass = tr->defclass;
3417 info->tag = tr->deftag;
3418 info->type = TBL_TYPEREF;
3419 info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3420 info->flags = PDUinfo_initflags = PDU_TYPETREE;
3421 info->value_id = -1;
3423 info->basetype = -1;
3426 info->value_hf.p_id = &(info->value_id);
3427 info->value_hf.hfinfo.name = info->fullname;
3428 info->value_hf.hfinfo.abbrev = info->fullname;
3429 info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
3430 info->value_hf.hfinfo.display = BASE_DEC;
3431 info->value_hf.hfinfo.blurb = info->fullname;
3433 tr->typetree = g_node_new(info);
3434 pabbrev_pdu_len = sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
3435 tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3439 g_message("%d types used", tcount);
3441 pabbrev_pdu_len = sav_len;
3443 /* and show the result */
3445 g_message("Type index:");
3446 for (i=0; i<numTypedefs; i++) {
3447 TypeRef *tr = &(typeDef_names[i]);
3453 if (tr->pdu == 0) /* skip if not used */
3457 g_message(" %3d %s, %c%d, refs: %d",
3458 i, tr->name, tag_class[tr->defclass], tr->deftag,
3459 g_ptr_array_len(tr->refs));
3461 /* get defining node for this type */
3464 p = (PDUinfo *)(tr->typetree->data);
3465 defid = p->value_id;
3467 g_message(" -- defining id=%d", defid);
3469 for(j=0; j < g_ptr_array_len(tr->refs); j++) { /* show refs, and set type_id */
3470 p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3471 if (p->mytype == (gint)i)
3472 p->type_id = defid; /* normal reference */
3474 if ((p->flags & PDU_TYPETREE) == 0) {
3475 /* we have a primitive value, find its real type */
3476 for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3477 /* look at all refs */
3478 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3479 if ((q->flags & PDU_TYPETREE) == 0)
3480 continue; /* only type trees are interresting */
3481 if (q->type != p->type)
3482 continue; /* must be same types */
3483 if (strcmp(q->name, p->name) == 0) {
3484 /* OK, take the first we find, not entirely
3485 * correct, it may be from a different
3486 * base-base type...... XXX */
3487 p->type_id = q->value_id;
3496 g_message(" %s", text);
3502 g_message("The resulting PDU tree:");
3503 showPDUtree(PDUtree, 0);
3509 #ifdef DISSECTOR_WITH_GUI
3510 /* This cannot work in tethereal.... don't include for now */
3511 #if GTK_MAJOR_VERSION >= 2
3512 #define SHOWPDU /* this needs GTK2 */
3514 #endif /* DISSECTOR_WITH_GUI */
3517 static GtkWidget *window = NULL;
3519 /* the columns in the tree view */
3522 TITLE_COLUMN, /* text in this row */
3523 DEF_COLUMN, /* definition in this row, if any */
3524 REF_COLUMN, /* referennce from this column, if any */
3525 VALUE_COLUMN, /* indicate this is a value */
3526 NAME_COLUMN, /* name of this row */
3530 static FILE *namelist = 0;
3533 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3536 PDUinfo *info, *rinfo;
3543 info = (PDUinfo *)p->data;
3545 gtk_tree_store_append (store, &iter2, iter); /* Acquire iterator */
3547 PDUtext(text, info);
3550 if (info->flags & PDU_TYPEDEF)
3551 def = info->typenum;
3553 if (info->flags & PDU_REFERENCE) {
3554 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3555 ref = rinfo->typenum;
3557 pb = GTK_STOCK_CANCEL;
3558 if (G_NODE_IS_LEAF(p)) {
3559 if (info->flags & PDU_NAMEDNUM)
3560 pb = GTK_STOCK_BOLD;
3564 fprintf(namelist, "%16s %s\n",
3565 &(TBLTYPE(info->type)[4]), info->fullname);
3568 switch (info->type) {
3569 case TBL_ENUMERATED:
3573 fprintf(namelist, "%16s %s\n",
3574 &(TBLTYPE(info->type)[4]), info->fullname);
3581 gtk_tree_store_set (store, &iter2,
3586 NAME_COLUMN, info->fullname,
3589 build_tree_view(store, g_node_first_child(p), &iter2);
3591 p = g_node_next_sibling(p);
3603 #define PATHSTACKMAX 10
3604 static GtkTreePath *pathstack[PATHSTACKMAX];
3605 static gint pathstackp = 0;
3607 static void add_path(GtkTreePath *p)
3609 if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
3610 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
3611 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
3614 pathstack[pathstackp++] = p;
3617 static GtkTreePath *pop_path(void)
3620 return pathstack[--pathstackp];
3625 find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
3629 struct DefFind *df = (struct DefFind *)data;
3631 gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
3633 if (def == df->def) {
3634 df->path = gtk_tree_path_copy (path);
3642 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
3645 GtkTreePath *path, *path2;
3646 gchar *text, *oldpath, *newpath;
3652 path = gtk_tree_path_copy (spath);
3654 gtk_tree_model_get_iter (model, &iter, path);
3655 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
3657 oldpath = gtk_tree_path_to_string(path);
3658 path2 = gtk_tree_path_copy (path);
3660 add_path(gtk_tree_path_copy(path));
3662 if (ref != -1) { /* this is a reference, find matching definition */
3665 gtk_tree_model_foreach (model, find_definition, &df);
3667 gtk_tree_path_free(path);
3670 } else { /* just move to the next entry, if it exists */
3671 gtk_tree_path_next(path2);
3673 if (gtk_tree_model_get_iter (model, &iter, path2)) {
3674 gtk_tree_path_free(path);
3675 path = path2; /* OK */
3677 if (gtk_tree_path_get_depth (path) > 1)
3678 gtk_tree_path_up (path);
3683 gtk_tree_path_free (path2);
3685 gtk_tree_view_expand_to_path (treeview, path);
3686 gtk_tree_view_expand_row (treeview, path, FALSE);
3688 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3690 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3692 newpath = gtk_tree_path_to_string(path);
3695 g_message("my_signal_handler: treeview=%p, moveing from %s to %s",
3696 treeview, oldpath, newpath);
3702 /* gtk_tree_path_free(df.path); */
3707 menuitem_cb (gpointer callback_data,
3708 guint callback_action,
3712 GtkTreeModel *model;
3713 GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
3714 GtkTreeSelection *selection;
3719 gchar *oldpath, *newpath;
3720 GtkTreeViewColumn *focus_column;
3722 selection = gtk_tree_view_get_selection(treeview);
3724 model = gtk_tree_view_get_model(treeview);
3725 gtk_tree_view_get_cursor (treeview, &path, &focus_column);
3727 if (gtk_tree_model_get_iter (model, &iter, path)) {
3729 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
3730 NAME_COLUMN, &name, -1);
3731 oldpath = gtk_tree_path_to_string(path);
3734 switch (callback_action) {
3735 case 0: /* Select */
3736 gtk_tree_selection_select_path (selection, path);
3741 gtk_tree_view_expand_to_path (treeview, path);
3742 gtk_tree_view_expand_row (treeview, path, FALSE);
3744 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3746 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3748 newpath = gtk_tree_path_to_string(path);
3750 gtk_tree_path_free(path);
3752 newpath = g_strdup("** no path **");
3754 g_message("menueitem_cb: treeview=%p, moveing from %s to %s",
3755 treeview, oldpath, newpath);
3759 /* get all non anonymous names to the root */
3762 dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
3763 GTK_DIALOG_DESTROY_WITH_PARENT,
3766 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
3767 gtk_item_factory_path_from_widget (widget),
3768 callback_action, text, oldpath, newpath, name);
3770 /* Close dialog on user response */
3771 g_signal_connect (dialog,
3773 G_CALLBACK (gtk_widget_destroy),
3776 gtk_widget_show (dialog);
3781 if (newpath != empty)
3785 g_message("menuitem_cb: no iterator...");
3788 static GtkItemFactoryEntry menu_items[] = {
3789 { "/Select", NULL, menuitem_cb, 0, NULL, 0 },
3790 { "/Back", "<control>B", menuitem_cb, 1, NULL, 0 },
3791 { "/Find", "<control>F", menuitem_cb, 2, NULL, 0 },
3792 { "/Save", "<control>S", menuitem_cb, 3, NULL, 0 },
3795 static gint button_press_callback( GtkWidget *widget,
3796 GdkEventButton *event,
3799 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
3801 /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
3802 * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
3805 if (event->button == 3) {
3806 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
3813 return FALSE; /* continue handling this event */
3818 create_message_window(void)
3820 GtkCellRenderer *renderer;
3821 GtkTreeStore *model;
3824 GtkWidget *treeview;
3826 GtkItemFactory *item_factory;
3827 GtkAccelGroup *accel_group;
3828 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3832 /* create window, etc */
3833 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3834 gtk_window_set_title (GTK_WINDOW (window), current_pduname);
3835 g_signal_connect (window, "destroy",
3836 G_CALLBACK (gtk_widget_destroyed), &window);
3838 vbox = gtk_vbox_new (FALSE, 8);
3839 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3840 gtk_container_add (GTK_CONTAINER (window), vbox);
3842 text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
3844 gtk_box_pack_start (GTK_BOX (vbox),
3845 gtk_label_new (text),
3849 sw = gtk_scrolled_window_new (NULL, NULL);
3850 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
3851 GTK_SHADOW_ETCHED_IN);
3852 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
3853 GTK_POLICY_AUTOMATIC,
3854 GTK_POLICY_AUTOMATIC);
3855 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3857 model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3858 G_TYPE_STRING, G_TYPE_STRING);
3860 namelist = eth_fopen("namelist.txt", "w");
3861 build_tree_view(model, PDUtree, NULL);
3865 /* create tree view */
3866 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
3867 g_object_unref (model);
3868 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
3869 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
3870 GTK_SELECTION_MULTIPLE);
3872 renderer = gtk_cell_renderer_text_new ();
3874 #if 0 /* testing pango attributes */
3877 PangoAttrList* attr;
3879 attr = pango_attr_list_new();
3880 bg = pango_attr_background_new(50000,55000,50000);
3881 bg->start_index = 0;
3882 bg->end_index = 10000;
3883 pango_attr_list_insert(attr, bg);
3885 g_object_set(renderer, "attributes", attr, NULL);
3887 #endif /* testing pango attributes */
3889 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3890 TITLE_COLUMN, "asn1 entities", renderer,
3891 "text", TITLE_COLUMN, NULL );
3893 /* renderer = gtk_cell_renderer_text_new ();
3894 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3895 * DEF_COLUMN, "type definition", renderer,
3896 * "text", DEF_COLUMN, NULL );
3898 * renderer = gtk_cell_renderer_text_new ();
3899 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3900 * REF_COLUMN, "reference", renderer,
3901 * "text", REF_COLUMN, NULL );
3903 renderer = gtk_cell_renderer_pixbuf_new ();
3904 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3905 VALUE_COLUMN, "value", renderer,
3906 "stock_id", VALUE_COLUMN, NULL );
3908 renderer = gtk_cell_renderer_text_new ();
3909 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3910 NAME_COLUMN, "fieldname", renderer,
3911 "text", NAME_COLUMN, NULL );
3913 gtk_container_add (GTK_CONTAINER (sw), treeview);
3915 /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
3919 accel_group = gtk_accel_group_new ();
3921 /* This function initializes the item factory.
3922 * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
3923 * or GTK_TYPE_OPTION_MENU.
3924 * Param 2: The path of the menu.
3925 * Param 3: A pointer to a gtk_accel_group. The item factory sets up
3926 * the accelerator table while generating menus.
3929 item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
3931 /* This function generates the menu items. Pass the item factory,
3932 the number of items in the array, the array itself, and any
3933 callback data for the the menu items. */
3934 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
3936 /* Attach the new accelerator group to the window. */
3937 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
3940 /* expand all rows after the treeview widget has been realized */
3941 g_signal_connect (treeview, "realize",
3942 G_CALLBACK (gtk_tree_view_expand_all), NULL);
3943 g_signal_connect (treeview, "row-activated",
3944 G_CALLBACK (my_signal_handler), (gpointer)model);
3946 g_signal_connect (treeview, "button_press_event",
3947 G_CALLBACK (button_press_callback), item_factory);
3949 /* g_signal_connect_swapped (treeview, "event",
3950 * G_CALLBACK (button_press_handler),
3953 gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
3956 if (!GTK_WIDGET_VISIBLE (window))
3957 gtk_widget_show_all (window);
3960 gtk_widget_destroy (window);
3964 #endif /* SHOWPDU */
3966 /************************************************************************************************
3967 * routines to find names to go with the decoded data stream *
3968 ************************************************************************************************/
3969 #define PDUSTATE_STACK_SIZE 1024
3970 typedef struct _statestack statestack;
3971 static struct _statestack {
3976 } PDUstate[PDUSTATE_STACK_SIZE];
3977 static gint PDUstatec = 0;
3979 /* XXX - Shouldn't we do bounds checking here? */
3980 #define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
3981 #define POPSTATE PDUstate[--PDUstatec]
3984 getname(GNode *node) {
3985 if (node == NULL || node->data == NULL)
3986 THROW(ReportedBoundsError);
3988 return ((PDUinfo *)node->data)->name;
3992 gettype(GNode *node) {
3993 if (node == NULL || node->data == NULL)
3994 THROW(ReportedBoundsError);
3996 return ((PDUinfo *)node->data)->type & TBL_TYPEmask;
4000 getinfo(GNode *node) {
4002 THROW(ReportedBoundsError);
4007 #define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
4008 #define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
4009 #define MATCH ((class == info->tclass) && (tag == info->tag))
4010 #define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
4011 #define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
4012 #define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
4013 #define ISCHOICE (info && (info->flags & PDU_CHOICE))
4014 #define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
4017 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
4018 pos.node=NULL;PUSHNODE(pos);return ret;}}
4022 showstack(statestack *pos, char *txt, int n)
4025 const char *name, *type, *stype;
4026 const char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
4032 if ( ! asn1_verbose)
4038 g_message("==underflow");
4041 rep = chs = done = ref = pop = chr = rch = sch = con = empty;
4045 name = ((PDUinfo *)g->data)->name;
4046 type = TBLTYPE(((PDUinfo *)g->data)->type);
4048 name = "node<null>";
4052 stype = TBLTYPE(typef);
4053 if (typef & TBL_REPEAT) rep = "[repeat]";
4054 if (typef & TBL_CHOICE_made) chs = "[choice]";
4055 if (typef & TBL_SEQUENCE_done) done = "[done]";
4056 if (typef & TBL_REFERENCE) ref = "[ref]";
4057 if (typef & TBL_REFERENCE_pop) pop = "[ref-pop]";
4058 if (typef & TBL_CHOICE_repeat) chr = "[chs-rep]";
4059 if (typef & TBL_REPEAT_choice) rch = "[rep-chs]";
4060 if (typef & TBL_SEQUENCE_choice)sch = "[seq-chs]";
4061 if (typef & TBL_CONSTRUCTED) con = "[constr]";
4063 i = sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
4064 pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4065 pos->name, pos->offset);
4067 for(j=1, n--; n>0; j++, n--) {
4068 p = &PDUstate[PDUstatec-j];
4070 stype = TBLTYPE(typef);
4071 rep = (typef & TBL_REPEAT) ? "[repeat]" : empty;
4072 chs = (typef & TBL_CHOICE_made) ? "[choice]" : empty;
4073 done = (typef & TBL_SEQUENCE_done) ? "[done]" : empty;
4074 ref = (typef & TBL_REFERENCE) ? "[ref]" : empty;
4075 pop = (typef & TBL_REFERENCE_pop) ? "[ref-pop]" : empty;
4076 chr = (typef & TBL_CHOICE_repeat) ? "[chs-rep]" : empty;
4077 rch = (typef & TBL_REPEAT_choice) ? "[rep-chs]" : empty;
4078 sch = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
4079 con = (typef & TBL_CONSTRUCTED) ? "[constr]" : empty;
4081 i += sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
4082 p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4083 p->name, p->offset);
4089 showrefNode(GNode *node, int n)
4091 const char *name = empty, *type = empty, *tname = empty;
4092 int cls = 0, tag = 0;
4097 g_message("%*sstop, nesting too deep", 2*n, empty);
4101 info = (PDUinfo *)(node->data);
4102 type = TBLTYPE(info->type);
4104 tname = info->typename;
4105 ref = info->reference;
4109 g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4110 2*n, empty, tname, type, name, node, node->data,
4111 ref, tag_class[cls], tag);
4114 showrefNode(ref, n+1);
4118 showNode(GNode *node, int n, int m)
4120 const char *name = empty, *type = empty;
4127 type = TBLTYPE(((PDUinfo *)(node->data))->type);
4128 name = ((PDUinfo *)(node->data))->name;
4129 ref = ((PDUinfo *)(node->data))->reference;
4131 g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4132 2*n, empty, type, name, node, node->data, node->next, node->prev,
4133 node->parent, node->children);
4136 g_message("%*sstop, nesting too deep", 2*n, empty);
4140 if (ref) showrefNode(ref, n+2);
4142 if (node->children) showNode(node->children, n+1, m);
4143 if (node->next) showNode(node->next, n, m);
4147 PDUreset(int count, int count2)
4151 if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
4153 PDUstatec = 0; /* stackpointer */
4154 PDUerrcount = 0; /* error counter per asn.1 message */
4156 pos.node = NULL; /* sentinel */
4157 pos.name = "sentinel";
4158 pos.type = TBL_SEQUENCEOF;
4163 pos.node = PDUtree; /* root of the tree */
4164 pos.name = getname(pos.node);
4165 pos.type = gettype(pos.node) | TBL_REPEAT;
4171 static GNode * /* find GNode for a choice element, 0 if none */
4172 makechoice(GNode *p, guint class, guint tag)
4177 p = g_node_first_child(p); /* the list of choices */
4178 info = 0; /* avoid gcc warning */
4181 info = ((PDUinfo *)p->data);
4183 if (info->type == TBL_CHOICE) {
4185 g_message(" using sub choice (%s)%s", info->typename, info->name);
4187 q = makechoice(p, class, tag);
4188 if (q) { /* found it */
4190 info = ((PDUinfo *)p->data);
4192 } /* continue with this level */
4196 g_message(" have %c%d, found %c%d, %s", tag_class[class], tag,
4197 tag_class[info->tclass], info->tag, info->name);
4199 if ((class == info->tclass) && (tag == info->tag))
4200 break; /* found it */
4203 p = g_node_next_sibling(p);
4206 if (p) g_message(" OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
4208 else g_message(" ...no matching choice...");
4213 /* offset is for debugging only, a reference to output on screen */
4215 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
4217 statestack pos, pos2, save_pos;
4219 const char *ret, *tmp;
4220 int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4221 static char namestr[64]; /* enough ? */
4222 static char posstr[40];
4223 static char noname[] = "*noname*";
4224 static PDUprops constructed_save; /* for unexpectedly constructed enteties */
4226 if (PDUstatec > 0) /* don't read from below the stack */
4228 /* pos refers to the last asn1 node handled */
4230 /* a very simple, too simple??, way to handle constructed entities */
4231 if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4232 /* unexpectedly constructed, return same info as last time */
4233 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4234 showstack(&pos, posstr, 3);
4235 pos.offset = offset;
4236 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4237 PUSHNODE(pos); /* push extra, to match with a EOI operation */
4238 PUSHNODE(pos); /* restore the stack */
4239 *out = constructed_save;
4241 g_message(" return for constructed %s (%s)%s",
4242 TBLTYPE(out->type), out->typename, out->name);
4246 save_pos = pos; /* may need it again */
4250 out->typename = "*error*";
4257 if (PDUstatec <= 0) {
4258 if (PDUstatec > -10) {
4260 g_message(">>off=%d stack underflow, return", offset);
4262 if (PDUstatec == -10) {
4264 g_message(">>off=%d stack underflow, return, no more messages", offset);
4266 out->name = "*underflow*";
4267 out->flags |= OUT_FLAG_noname;
4271 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4273 showstack(&pos, posstr, 3);
4277 if (class == ASN1_EOI) { /* end of this input sequence */
4279 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4280 if (asn1_verbose) g_message(" EOI: reference pop");
4283 switch(pos.type & TBL_TYPEmask) {
4285 if (asn1_verbose) g_message(" EOI: pop typeref");
4286 pos = POPSTATE; /* remove typeref */
4288 case TBL_CHOICE_done:
4289 if (asn1_verbose) g_message(" EOI: mark choice");
4291 pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4299 pos = POPSTATE; /* this is pushed back on the stack later */
4300 if (pos.node == NULL) {
4301 if (asn1_verbose) g_message(" EOI, pos.node == NULL");
4302 out->name = "*no-name-EOI*";
4303 out->flags |= OUT_FLAG_noname;
4308 info = getinfo(pos.node);
4310 tmp = TBLTYPE(info->type);
4311 if (offset != pos.offset) {
4313 g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4314 tmp, ret, offset, pos.offset);
4315 while ((offset < pos.offset) && (PDUstatec > 0)) {
4318 g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
4319 offset, pos.offset);
4321 if (offset != pos.offset)
4322 PDUerrcount++; /* only count if still unequal */
4324 if (asn1_verbose) g_message(" EOI %s:%s OK, offset=%d", tmp, ret, offset);
4327 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4328 * indicated by the synthetic EOI call. */
4329 if ((class == ASN1_UNI) && (tag == ASN1_EOC)) { /* explicit EOC never has a name */
4330 PUSHNODE(pos); /* restore stack */
4331 ret = "explicit-EOC";
4332 if (asn1_verbose) g_message(" return '%s', ignore", ret);
4334 out->typename = "ASN1";
4338 /* find appropriate node for this tag */
4340 if (pos.node == NULL) {
4341 if (asn1_verbose) g_message(" pos.node == NULL");
4342 out->name = "*no-name*";
4343 out->flags |= OUT_FLAG_noname;
4348 /* showNode(pos.node, 3, 4); */
4350 switch (pos.type & TBL_TYPEmask) {
4351 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4355 if (pos.type & TBL_CHOICE_made) {
4356 if (asn1_verbose) g_message(" finish choice");
4362 info = getinfo(pos.node);
4364 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4365 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4367 if (asn1_verbose) g_message(" repeating choice"); /* ignore repeat */
4370 if (asn1_verbose) g_message(" seqof: repeat start");
4371 /* decide how to continue, CHILD for next instance of sequence
4372 * or NEXT for end of repeated sequence.
4373 * use the tag to make a descision */
4374 if (asn1_verbose) g_message(" seqof: first got %c%d, found %c%d",
4375 tag_class[class], tag,
4376 tag_class[info->tclass], info->tag);
4378 /* This is the start of repeating */
4380 ret = getname(pos.node);
4381 if (asn1_verbose) g_message(" return for repeat '%s'", ret);
4382 out->type = (pos.type & TBL_TYPEmask);
4383 out->typename = info->typename;
4385 out->value_id = info->value_id;
4386 out->type_id = info->type_id;
4388 if (asn1_verbose) g_message(" anonymous: dontshow");
4390 out->flags |= OUT_FLAG_dontshow;
4396 /* find out where to go .... */
4398 CHILD; /* assume sequence is repeated */
4400 info = getinfo(pos.node); /* needed for MATCH to look ahead */
4402 g_message(" seqof: child: got %c%d, found %c%d",
4403 tag_class[class], tag,
4404 tag_class[info->tclass], info->tag);
4406 if (pos2.type & TBL_CHOICE_repeat) {
4409 g_message(" repeating a choice, %s",
4411 pos.type = TBL_CHOICE_immediate;
4413 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4414 donext = 1; /* move on */
4416 g_message(" seqof: no repeat, force next");
4418 /* following code will take the child again */
4424 } else if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4425 if (asn1_verbose) g_message(" reference pop, donext");
4428 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4429 if (pos.type & TBL_SEQUENCE_choice) {
4430 pos = POPSTATE; /* expect to find a repeat here */
4433 if (asn1_verbose) g_message(" sequence done, donext");
4437 if (pos.type & TBL_REFERENCE) {
4438 if (asn1_verbose) g_message(" reference change ref -> pop");
4439 pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4442 pos.offset = offset;
4444 ret = pos.name; /* for the debug messages */
4447 if (asn1_verbose) g_message(" donext");
4450 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4451 case TBL_SETOF: /* ?? */
4452 case TBL_SEQUENCEOF:
4453 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4454 pos.type |= TBL_REPEAT;
4458 /* remember this is the start of a repeat cycle */
4459 typeflags |= TBL_REPEAT;
4461 g_message(" seqof: set repeat mark [push,child]");
4464 g_message(" seqof: end of reapeat loop [next]");
4468 case TBL_SET: /* ?? */
4470 pos.type |= TBL_SEQUENCE_done;
4474 if (asn1_verbose) g_message(" seq [push,child]");
4477 /* no more choice */
4478 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4481 pos.type = 0; /* clear all type flags */
4483 g_message(" choice [push], %c%d, %s",
4484 tag_class[info->tclass], info->tag, getname(pos.node));
4485 pos.node = makechoice(pos.node, class, tag);
4486 if (pos.node == NULL) {
4488 out->flags |= OUT_FLAG_noname;
4491 info = getinfo(pos.node);
4493 ret = getname(pos.node);
4495 g_message(" '%s' %c%d will be used",
4496 ret, tag_class[info->tclass], info->tag);
4498 case TBL_CHOICE_done:
4504 if (asn1_verbose) g_message(" typeref [pop,next]");
4506 case TBL_ENUMERATED:
4508 /* skip named numbers now, call to PDUenum() will retrieve a name */
4511 case TBL_CHOICE_immediate:
4512 if (asn1_verbose) g_message(" immediate choice [no next]");
4521 if (pos.node == NULL) {
4522 ret = "*no-name-2*";
4523 if (asn1_verbose) g_message(" return '%s'", ret);
4525 out->flags |= OUT_FLAG_noname;
4529 ret = pos.name = getname(pos.node);
4530 pos.type = gettype(pos.node) | (pos.type & ~TBL_TYPEmask);
4531 info = getinfo(pos.node);
4533 /* pos now points to the prospective current node, go check it ********************/
4534 if (asn1_verbose) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4535 (ISOPTIONAL)?", optional":empty,
4536 (ISIMPLICIT)?", implicit":empty,
4537 tag_class[info->tclass], info->tag );
4539 if (ISOPTIONAL) { /* must check the tag */
4540 while(! MATCH) { /* check optional here again...? */
4542 g_message(" got %c%d, found %c%d", tag_class[class], tag,
4543 tag_class[info->tclass], info->tag);
4545 if (pos.node == NULL) {
4548 pos = save_pos; /* reset for next time */
4549 pos.type |= TBL_SEQUENCE_done;
4551 pos.type &= ~TBL_SEQUENCE_done;
4553 out->flags |= OUT_FLAG_dontshow;
4555 g_message(" end of optional list, constructed, expect value next time");
4558 out->flags |= OUT_FLAG_noname;
4560 g_message(" *end of optional list...");
4561 info = 0; /* this is not valid any more... */
4563 break; /* end of list */
4565 info = getinfo(pos.node);
4566 if (asn1_verbose) g_message(" optional, %s", getname(pos.node));
4568 if (pos.node && ! cons_handled) {
4569 ret = pos.name = getname(pos.node);
4570 pos.type = gettype(pos.node);
4572 /* pos now refers to node with name we want, optional nodes skipped */
4575 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4576 pos2 = pos; /* save current state */
4580 g_message(" already pushed, skip next push");
4582 typeflags &= ~TBL_CHOICE_made;
4585 if (asn1_verbose && info)
4586 g_message(" immediate choice [push], %c%d, %s",
4587 tag_class[info->tclass], info->tag, getname(pos.node));
4589 pos.node = makechoice(pos.node, class, tag);
4591 if (pos.node == NULL) {
4595 info = getinfo(pos.node);
4596 pos.type = gettype(pos.node);
4597 out->type = (pos.type & TBL_TYPEmask);
4598 out->flags |= OUT_FLAG_type;
4600 sprintf(namestr, "%s!%s", ret, getname(pos.node));
4603 g_message(" %s:%s will be used", TBLTYPE(pos.type), ret);
4604 if (typeflags & TBL_REPEAT) {
4605 pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
4607 pos.type |= TBL_SEQUENCE_choice;
4610 g_message(" return from immediate choice [%s] '%s'",
4611 TBLTYPE(pos.type), ret);
4613 out->data = pos.node; /* for access to named numbers... */
4615 out->type = (pos.type & TBL_TYPEmask);
4618 out->typename = info->typename;
4619 out->fullname = info->fullname;
4620 out->value_id = info->value_id;
4621 out->type_id = info->type_id;
4626 typeflags |= TBL_CHOICE_made;
4629 if (asn1_verbose) g_message(" matching choice '%s'", ret);
4631 if ( ! cons ) { /* ISIMPLICIT was not OK for all */
4632 pos = pos2; /* reset for continuation */
4637 g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4638 (ISOPTIONAL)?", optional":empty,
4639 (ISIMPLICIT)?", implicit":empty,
4640 tag_class[info->tclass], info->tag );
4642 g_message(" using: unknown '%s'", ret);
4645 /* must follow references now */
4646 if (pos.type == TBL_TYPEREF && info) {
4647 out->typename = info->typename;
4648 out->type_id = info->typenum;
4649 out->flags |= OUT_FLAG_typename;
4651 PUSHNODE(pos); /* remember where we were */
4652 if (asn1_verbose) g_message(" typeref [push]");
4653 typeflags |= TBL_REFERENCE;
4654 if (info->reference == 0) { /* resolved ref to universal type.... */
4655 /* showNode(pos.node, 3, 4); */
4656 pos.type = gettype(pos.node); /* the resulting type */
4657 info = getinfo(pos.node);
4658 tmp = "inknown tag";
4659 if ((info->tclass == ASN1_UNI) && (info->tag < 31)) {
4660 tmp = asn1_tag[info->tag];
4661 pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
4663 if (asn1_verbose && info)
4664 g_message(" indirect typeref to %s:%s, %s [%c%d]",
4665 TBLTYPE(pos.type), info->typename, tmp,
4666 tag_class[info->tclass], info->tag );
4668 out->fullname = info->fullname;
4669 donext = (ISANONYMOUS); /* refereing entity has no name ? */
4670 pos.node = info->reference;
4671 pos.type = gettype(pos.node);
4672 info = getinfo(pos.node);
4674 g_message(" typeref %s %s", TBLTYPE(pos.type), getname(pos.node));
4675 /* keep name from before going through the reference, unless anonymous */
4676 if (donext) /* refering entity has no name */
4677 ret = getname(pos.node); /* a better name */
4679 /* handle choice here ? !!mm!! */
4681 out->type = (pos.type & TBL_TYPEmask);
4682 out->flags |= OUT_FLAG_type;
4683 /* showNode(pos.node, 3, 4); */
4684 /* ret = getname(pos.node);*/
4686 out->data = pos.node;
4687 out->flags |= OUT_FLAG_data;
4689 g_message(" typeref set named number list node %p", pos.node);
4693 pos.type = TBL_TYPEREF_nopop;
4694 if (asn1_verbose) g_message(" typeref pop");
4695 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
4696 /* do not enter the named-number list */
4698 pos.type = TBL_TYPEREF_nopop;
4699 if (asn1_verbose) g_message(" typeref [pop]");
4701 typeflags |= TBL_REFERENCE;
4706 if (cons && ! cons_handled) { /* This entity is constructed, expected ? */
4708 case TBL_BOOLEAN: /* these are not expected to be constructed */
4710 case TBL_OCTETSTRING:
4714 case TBL_ENUMERATED:
4716 typeflags |= TBL_CONSTRUCTED;
4717 /* this entry has no extra info, next is the same */
4718 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
4719 if (asn1_verbose) g_message(" dontshow and set constructed flag");
4721 default: /* others, such as sequences, are expected to be constructed */
4728 if (asn1_verbose) g_message(" anonymous: dontshow");
4729 if (asn1_debug) /* this entry has no extra info, next is the same */
4730 out->flags |= OUT_FLAG_dontshow;
4732 out->name = empty; /* show it, but no name */
4735 if (out->name != empty)
4738 if ( ! (out->flags & OUT_FLAG_data))
4739 out->data = pos.node; /* for access to named numbers... */
4741 pos.type |= typeflags;
4744 if ( ! (out->flags & OUT_FLAG_type))
4745 out->type = pos.type;
4747 out->type &= TBL_TYPEmask;
4749 if (ret == noname) {
4751 out->flags |= OUT_FLAG_noname;
4754 if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
4755 out->typename = info->typename;
4756 out->type_id = info->typenum;
4759 if (info && (out->value_id == -1)) {
4760 out->value_id = info->value_id;
4761 out->type_id = info->type_id;
4764 if ((out->fullname == 0) && info)
4765 out->fullname = info->fullname;
4767 if (typeflags & TBL_CONSTRUCTED)
4768 constructed_save = *out;
4771 g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
4772 out->value_id, out->type_id);
4778 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
4782 const char *ret, *name;
4783 static char unnamed[] = "*unnamed*";
4785 (void) cls; (void) tag; /* make a reference */
4787 if (props->flags & OUT_FLAG_noname)
4791 list = (GNode *)props->data;
4794 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
4796 return "*list-still-0*";
4799 if ((PDUinfo *)list->data)
4800 name = ((PDUinfo *)list->data)->name;
4804 for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
4805 info = (PDUinfo *)list->data;
4806 if (value == info->tag) {
4815 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
4819 #endif /* READSYNTAX */
4822 proto_register_asn1(void) {
4824 static const enum_val_t type_recursion_opts[] = {
4838 static gint *ett[1+MAX_NEST+MAXPDU];
4842 module_t *asn1_module;
4845 asn1_logfile = get_tempfile_path(ASN1LOGFILE);
4847 current_asn1 = g_strdup("");
4848 asn1_filename = g_strdup(current_asn1);
4850 current_pduname = g_strdup("ASN1");
4851 asn1_pduname = g_strdup(current_pduname);
4853 proto_asn1 = proto_register_protocol("ASN.1 decoding",
4857 for (i=0, j=1; i<MAX_NEST; i++, j++) {
4858 ett[j] = &ett_seq[i];
4861 for(i=0; i<MAXPDU; i++, j++) {
4862 ett[j] = &ett_pdu[i];
4866 proto_register_subtree_array(ett, array_length(ett));
4868 asn1_module = prefs_register_protocol(proto_asn1,
4869 proto_reg_handoff_asn1);
4870 #ifdef JUST_ONE_PORT
4871 prefs_register_uint_preference(asn1_module, "tcp_port",
4873 "The TCP port on which "
4874 "ASN.1 messages will be read",
4875 10, &global_tcp_port_asn1);
4876 prefs_register_uint_preference(asn1_module, "udp_port",
4878 "The UDP port on which "
4879 "ASN.1 messages will be read",
4880 10, &global_udp_port_asn1);
4881 prefs_register_uint_preference(asn1_module, "sctp_port",
4883 "The SCTP port on which "
4884 "ASN.1 messages will be read",
4885 10, &global_sctp_port_asn1);
4887 g_snprintf(tmpstr, sizeof(tmpstr), "%u", TCP_PORT_ASN1);
4888 range_convert_str(&global_tcp_ports_asn1, tmpstr, 65535);
4890 g_snprintf(tmpstr, sizeof(tmpstr), "%u", UDP_PORT_ASN1);
4891 range_convert_str(&global_udp_ports_asn1, tmpstr, 65535);
4893 g_snprintf(tmpstr, sizeof(tmpstr), "%u", SCTP_PORT_ASN1);
4894 range_convert_str(&global_sctp_ports_asn1, tmpstr, 65535);
4896 prefs_register_range_preference(asn1_module, "tcp_ports",
4898 "The TCP ports on which "
4899 "ASN.1 messages will be read",
4900 &global_tcp_ports_asn1, 65535);
4901 prefs_register_range_preference(asn1_module, "udp_ports",
4903 "The UDP ports on which "
4904 "ASN.1 messages will be read",
4905 &global_udp_ports_asn1, 65535);
4906 prefs_register_range_preference(asn1_module, "sctp_ports",
4908 "The SCTP ports on which "
4909 "ASN.1 messages will be read",
4910 &global_sctp_ports_asn1, 65535);
4911 #endif /* JUST_ONE_PORT */
4913 prefs_register_bool_preference(asn1_module, "desegment_messages",
4915 "Desegment ASN.1 messages that span TCP segments",
4918 old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
4920 bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
4923 prefs_register_string_preference(asn1_module, "file",
4924 "ASN.1 type table file",
4925 "Compiled ASN.1 description of ASN.1 types",
4927 prefs_register_string_preference(asn1_module, "pdu_name",
4929 "Name of top level PDU",
4931 prefs_register_uint_preference(asn1_module, "first_pdu_offset",
4932 "Offset to first PDU in first tcp packet",
4933 "Offset for non-reassembled packets, "
4934 "wrong if this happens on other than the first packet!",
4935 10, &first_pdu_offset);
4936 prefs_register_bool_preference(asn1_module, "flat",
4938 "Show full names for all values",
4940 prefs_register_enum_preference(asn1_module, "type_recursion",
4941 "Eliminate references to level",
4942 "Allow this recursion level for eliminated type references",
4943 &type_recursion_level,
4944 type_recursion_opts, FALSE);
4945 prefs_register_bool_preference(asn1_module, "debug",
4947 "Extra output useful for debuging",
4950 prefs_register_bool_preference(asn1_module, "message_win",
4952 "show full message description",
4955 prefs_register_obsolete_preference(asn1_module, "message_win");
4957 prefs_register_bool_preference(asn1_module, "verbose_log",
4958 "Write very verbose log",
4959 "log to file $TMP/" ASN1LOGFILE,
4963 /* The registration hand-off routing */
4965 static dissector_handle_t asn1_handle;
4968 register_tcp_port(guint32 port)
4970 dissector_add("tcp.port", port, asn1_handle);
4974 unregister_tcp_port(guint32 port)
4976 dissector_delete("tcp.port", port, asn1_handle);
4980 register_udp_port(guint32 port)
4982 dissector_add("udp.port", port, asn1_handle);
4986 unregister_udp_port(guint32 port)
4988 dissector_delete("udp.port", port, asn1_handle);
4992 register_sctp_port(guint32 port)
4994 dissector_add("sctp.port", port, asn1_handle);
4998 unregister_sctp_port(guint32 port)
5000 dissector_delete("sctp.port", port, asn1_handle);
5004 proto_reg_handoff_asn1(void) {
5005 static int asn1_initialized = FALSE;
5006 #ifndef JUST_ONE_PORT
5007 char *tcp_ports_asn1_string, *udp_ports_asn1_string, *sctp_ports_asn1_string;
5012 #ifdef JUST_ONE_PORT
5013 if (asn1_verbose) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegnment=%d, "
5014 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5015 global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
5016 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5019 tcp_ports_asn1_string = range_convert_range(global_tcp_ports_asn1);
5020 udp_ports_asn1_string = range_convert_range(global_udp_ports_asn1);
5021 sctp_ports_asn1_string = range_convert_range(global_sctp_ports_asn1);
5022 g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegnment=%d, "
5023 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5024 tcp_ports_asn1_string, udp_ports_asn1_string, sctp_ports_asn1_string, asn1_desegment,
5025 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5027 #endif /* JUST_ONE_PORT */
5029 if(!asn1_initialized) {
5030 asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
5031 asn1_initialized = TRUE;
5032 } else { /* clean up ports and their lists */
5033 #ifdef JUST_ONE_PORT
5034 unregister_tcp_port(tcp_port_asn1);
5035 unregister_udp_port(udp_port_asn1);
5036 unregister_sctp_port(sctp_port_asn1);
5038 if (tcp_ports_asn1 != NULL) {
5039 range_foreach(tcp_ports_asn1, unregister_tcp_port);
5040 g_free(tcp_ports_asn1);
5043 if (udp_ports_asn1 != NULL) {
5044 range_foreach(udp_ports_asn1, unregister_udp_port);
5045 g_free(udp_ports_asn1);
5048 if (sctp_ports_asn1 != NULL) {
5049 range_foreach(sctp_ports_asn1, unregister_sctp_port);
5050 g_free(sctp_ports_asn1);
5052 #endif /* JUST_ONE_PORT */
5055 if (strcmp(asn1_filename, current_asn1) != 0) {
5056 /* new definitions, parse the file if we have one */
5057 /* !!! should be postponed until we really need it !!! */
5059 read_asn1_type_table(asn1_filename);
5060 #endif /* READSYNTAX */
5061 g_free(current_asn1);
5062 current_asn1 = g_strdup(asn1_filename);
5064 if (!PDUtree || /* no tree built yet for PDU type */
5065 strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
5066 if (build_pdu_tree(asn1_pduname)) {
5067 g_free(current_pduname);
5068 current_pduname = g_strdup(asn1_pduname);
5072 if (asn1_message_win) { /* show what we are prepared to recognize */
5074 gtk_widget_destroy (window);
5077 create_message_window();
5079 #endif /* SHOWPDU */
5081 /* If we now have a PDU tree, register for the port or ports we have */
5083 #ifdef JUST_ONE_PORT
5084 tcp_port_asn1 = global_tcp_port_asn1;
5085 udp_port_asn1 = global_udp_port_asn1;
5086 sctp_port_asn1 = global_sctp_port_asn1;
5088 register_tcp_port(tcp_port_asn1);
5089 register_udp_port(udp_port_asn1);
5090 register_sctp_port(sctp_port_asn1);
5092 tcp_ports_asn1 = range_copy(global_tcp_ports_asn1);
5093 udp_ports_asn1 = range_copy(global_udp_ports_asn1);
5094 sctp_ports_asn1 = range_copy(global_sctp_ports_asn1);
5096 range_foreach(tcp_ports_asn1, register_tcp_port);
5097 range_foreach(udp_ports_asn1, register_udp_port);
5098 range_foreach(sctp_ports_asn1, register_sctp_port);
5100 #endif /* JUST_ONE_PORT */