1 /******************************************************************************************************/
4 * Copyright (c) 2003 by Matthijs Melchior <matthijs.melchior@xs4all.nl>
6 * $Id: packet-asn1.c,v 1.21 2004/03/02 23:45:34 jmayer Exp $
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>
70 #include "plugins/plugin_api.h"
72 #include "moduleinfo.h"
80 #include <epan/packet.h>
81 #include <epan/resolv.h>
83 #include <epan/strutil.h>
84 #include <epan/filesystem.h>
86 #include "report_err.h"
87 #include "simple_dialog.h"
89 #include "plugins/plugin_api_defs.h"
91 #ifdef DISSECTOR_WITH_GUI
98 /* Define version if we are not building ethereal statically */
100 #ifndef ENABLE_STATIC
101 G_MODULE_EXPORT const gchar version[] = VERSION;
109 /* Define default ports */
111 #define TCP_PORT_ASN1 801
112 #define UDP_PORT_ASN1 801
114 void proto_reg_handoff_asn1(void);
116 /* Define the asn1 proto */
118 static int proto_asn1 = -1;
120 /* Define the tree for asn1*/
122 static int ett_asn1 = -1;
124 #define MAXPDU 64 /* max # PDU's in one packet */
125 static int ett_pdu[MAXPDU];
127 #define MAX_NEST 32 /* max nesting level for ASN.1 elements */
128 static int ett_seq[MAX_NEST];
131 * Global variables associated with the preferences for asn1
134 static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
135 static guint global_udp_port_asn1 = UDP_PORT_ASN1;
136 static guint tcp_port_asn1 = TCP_PORT_ASN1;
137 static guint udp_port_asn1 = UDP_PORT_ASN1;
139 static gboolean asn1_desegment = TRUE;
140 static char *asn1_filename = NULL;
141 static char *old_default_asn1_filename = NULL;
142 #define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
144 #define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
145 static char *bad_separator_old_default_asn1_filename = NULL;
147 static char *current_asn1 = NULL;
148 static char *asn1_pduname = NULL;
149 static char *current_pduname = NULL;
150 static gboolean asn1_debug = FALSE;
151 static guint first_pdu_offset = 0;
152 static gboolean asn1_message_win = FALSE;
153 static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
154 static gboolean asn1_full = FALSE; /* show full names */
155 static guint type_recursion_level = 1; /* eliminate 1 level of references */
156 static char *asn1_logfile = NULL;
158 #define ASN1LOGFILE "ethereal.log"
160 /* PDU counter, for correlation between GUI display and log file in debug mode */
161 static int pcount = 0;
163 static tvbuff_t *asn1_desc; /* the PDU description */
164 static GNode *asn1_nodes = 0; /* GNode tree pointing to every asn1 data element */
165 static GNode *data_nodes = 0; /* GNode tree describing the syntax data */
166 static GNode *PDUtree = 0; /* GNode tree describing the expected PDU format */
168 static guint PDUerrcount = 0; /* count of parse errors in one ASN.1 message */
170 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
173 char pabbrev[] = "asn1"; /* field prefix */
175 char fieldname[512]; /* for constructing full names */
176 guint pabbrev_pdu_len; /* length initial part of fieldname with 'abbrev.asn1pdu.' */
179 * Text strings describing the standard, universal, ASN.1 names.
182 #define ASN1_EOI 4 /* this is in the class number space... */
183 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
185 char tag_class[] = "UACPX";
187 char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
189 char *asn1_con[] = { "Primitive", "Constructed" };
192 /* 0 */ "EOC", "Boolean", "Integer", "BitString",
193 /* 4 */ "OctetString", "Null", "ObjectIdentifier", "ObjectDescriptor",
194 /* 8 */ "External", "Real", "Enumerated", "tag11",
195 /* 12 */ "UTF8String", "tag13", "tag14", "tag15",
196 /* 16 */ "Sequence", "Set", "NumericString", "PrintableString",
197 /* 20 */ "TeletexString", "VideotexString", "IA5String", "UTCTime",
198 /* 24 */ "GeneralTime", "GraphicString", "ISO646String", "GeneralString",
199 /* 28 */ "UniversalString", "tag29", "BMPString", "Long tag prefix"
200 /* TT61 == TELETEX */
201 /* ISO646 == VISIBLE*/
204 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
205 gboolean tbl_types_verified = FALSE;
207 typedef enum { /* copied from .../snacc/c-lib/boot/tbl.h */
216 TBL__SIMPLE = 8, /* values smaller than this can have a value */
224 TBL_SEQUENCEOF_start, /* to mark potential sequence-of repeat */
225 TBL_TYPEREF_nopop, /* typeref has been handled immediately */
226 TBL_CHOICE_done, /* choice is finished */
227 TBL_reserved, /* this sequence has been visited */
228 TBL_CHOICE_immediate, /* immediate choice, no next */
230 TBL_INVALID /* incorrect value for this enum */
233 /* Universal tags mapped to snacc ASN.1 table types */
234 int asn1_uni_type[] = {
235 /* 0 */ TBL_INVALID, TBL_BOOLEAN, TBL_INTEGER, TBL_BITSTRING,
236 /* 4 */ TBL_OCTETSTRING, TBL_NULL, TBL_OID, TBL_INVALID,
237 /* 8 */ TBL_INVALID, TBL_REAL, TBL_ENUMERATED, TBL_INVALID,
238 /* 12 */ TBL_OCTETSTRING, TBL_INVALID, TBL_INVALID, TBL_INVALID,
239 /* 16 */ TBL_SEQUENCE, TBL_SET, TBL_OCTETSTRING, TBL_OCTETSTRING,
240 /* 20 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
241 /* 24 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
242 /* 28 */ TBL_OCTETSTRING, TBL_INVALID, TBL_OCTETSTRING, TBL_INVALID,
246 #define TBL_REPEAT 0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
247 #define TBL_REPEAT_choice 0x00020000 /* repeating a choice */
248 #define TBL_CHOICE_made 0x00040000 /* This was a choice entry */
249 #define TBL_SEQUENCE_done 0x00080000 /* children have been processed */
250 #define TBL_CHOICE_repeat 0x00100000 /* a repeating choice */
251 #define TBL_REFERENCE 0x00200000 /* This entry is result of a typeref */
252 #define TBL_REFERENCE_pop 0x00400000 /* reference handled, do pop i.s.o. next */
253 #define TBL_SEQUENCE_choice 0x00800000 /* this sequence is a first of a repeating choice */
254 #define TBL_CONSTRUCTED 0x01000000 /* unexpectedly constructed entry */
255 #define TBL_TYPEmask 0x0000FFFF /* Mask just the type */
258 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
260 /* text tables for debugging and GUI */
261 char *tbl_types[] = { /* 0 */ "tbl-boolean",
262 /* 1 */ "tbl-integer",
263 /* 2 */ "tbl-bitstring",
264 /* 2 */ "tbl-octetstring",
268 /* 7 */ "tbl-enumerated",
269 /* 8 */ "tbl-sequence",
271 /* 10 */ "tbl-sequenceof",
272 /* 11 */ "tbl-setof",
273 /* 12 */ "tbl-choice",
274 /* 13 */ "tbl-typeref",
276 /* 14 */ "tbl-sequenceof-start",
277 /* 15 */ "tbl-typeref-nopop",
278 /* 16 */ "tbl-choice-done",
279 /* 17 */ "tbl-reserved",
280 /* 18 */ "tbl-choice-immediate",
282 /* 19 */ "tbl-invalid",
284 char *tbl_types_asn1[] = {
288 /* 2 */ "OCTET STRING",
290 /* 5 */ "OBJECT IDENTIFIER",
292 /* 7 */ "ENUMERATED",
295 /* 10 */ "SEQUENCE OF",
300 /* 14 */ "start-SEQUENCE OF",
301 /* 15 */ "TYPEREF nopop",
302 /* 16 */ "CHOICE done",
304 /* 18 */ "CHOICE immediate",
306 /* 19 */ "INVALID entry",
308 /* conversion from snacc type to appropriate ethereal type */
309 guint tbl_types_ethereal[] = {
310 /* 0 */ FT_BOOLEAN, /* TBL_BOOLEAN */
311 /* 1 */ FT_UINT32, /* TBL_INTEGER */
312 /* 2 */ FT_UINT32, /* TBL_BITSTRING */
313 /* 2 */ FT_STRINGZ, /* TBL_OCTETSTRING */
314 /* 4 */ FT_NONE, /* TBL_NULL */
315 /* 5 */ FT_BYTES, /* TBL_OID */
316 /* 6 */ FT_DOUBLE, /* TBL_REAL */
317 /* 7 */ FT_UINT32, /* TBL_ENUMERATED */
318 /* 8 */ FT_NONE, /* TBL_SEQUENCE */
319 /* 9 */ FT_NONE, /* TBL_SET */
320 /* 10 */ FT_NONE, /* TBL_SEQUENCEOF */
321 /* 11 */ FT_NONE, /* TBL_SETOF */
322 /* 12 */ FT_NONE, /* TBL_CHOICE */
323 /* 13 */ FT_NONE, /* TBL_TYPEREF */
325 /* 14 */ FT_NONE, /* TBL_SEQUENCEOF_start */
326 /* 15 */ FT_NONE, /* TBL_TYPEREF_nopop */
327 /* 16 */ FT_NONE, /* TBL_CHOICE_done */
328 /* 17 */ FT_NONE, /* TBL_reserved */
329 /* 18 */ FT_NONE, /* TBL_CHOICE_immediate */
331 /* 19 */ FT_NONE, /* TBL_INVALID */
334 char *tbl_types_ethereal_txt[] = {
335 /* 0 */ "FT_BOOLEAN", /* TBL_BOOLEAN */
336 /* 1 */ "FT_UINT32", /* TBL_INTEGER */
337 /* 2 */ "FT_UINT32", /* TBL_BITSTRING */
338 /* 2 */ "FT_STRINGZ", /* TBL_OCTETSTRING */
339 /* 4 */ "FT_NONE", /* TBL_NULL */
340 /* 5 */ "FT_BYTES", /* TBL_OID */
341 /* 6 */ "FT_DOUBLE", /* TBL_REAL */
342 /* 7 */ "FT_UINT32", /* TBL_ENUMERATED */
343 /* 8 */ "FT_NONE", /* TBL_SEQUENCE */
344 /* 9 */ "FT_NONE", /* TBL_SET */
345 /* 10 */ "FT_NONE", /* TBL_SEQUENCEOF */
346 /* 11 */ "FT_NONE", /* TBL_SETOF */
347 /* 12 */ "FT_NONE", /* TBL_CHOICE */
348 /* 13 */ "FT_NONE", /* TBL_TYPEREF */
350 /* 14 */ "FT_NONE", /* TBL_SEQUENCEOF_start */
351 /* 15 */ "FT_NONE", /* TBL_TYPEREF_nopop */
352 /* 16 */ "FT_NONE", /* TBL_CHOICE_done */
353 /* 17 */ "FT_NONE", /* TBL_reserved */
354 /* 18 */ "FT_NONE", /* TBL_CHOICE_immediate */
356 /* 19 */ "FT_NONE", /* TBL_INVALID */
359 /* description of PDU properties as passed from the matching routine
360 * to the decoder and GUI.
362 typedef struct _PDUprops PDUprops;
364 guint type; /* value from enum TBLTypeId */
373 /* flags defined in PDUprops.flags */
374 #define OUT_FLAG_type 1
375 #define OUT_FLAG_data 2
376 #define OUT_FLAG_typename 4
377 #define OUT_FLAG_dontshow 8
378 #define OUT_FLAG_noname 0x10
379 #define OUT_FLAG_constructed 0x20
381 PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
382 char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
384 char empty[] = ""; /* address of the empt string, avoids many tests for NULL */
385 #define MAX_OTSLEN 256 /* max printed size for an octet string */
388 #undef NEST /* show nesting of asn.1 enties */
390 #ifdef NEST /* only for debugging */
391 /* show nesting, only for debugging... */
392 #define MAXTAGS MAX_NEST
398 char *showtaglist(guint level)
400 static char tagtxt[BUFLM];
405 for(i=0; i<= level; i++) {
406 switch(taglist[i].cls) {
407 case ASN1_UNI: *p++ = 'U'; break;
408 case ASN1_APL: *p++ = 'A'; break;
409 case ASN1_CTX: *p++ = 'C'; break;
410 case ASN1_PRV: *p++ = 'P'; break;
411 default: *p++ = 'x'; break;
413 p += sprintf(p, "%d.", taglist[i].tag);
415 #else /* only context tags */
417 for(i=0; i<= level; i++) {
418 if (taglist[i].cls == ASN1_CTX) {
419 p += sprintf(p, "%d.", taglist[i].tag);
423 *--p = 0; /* remove trailing '.' */
428 get_context(guint level)
433 for(i=0; i<=level; i++) {
434 if (taglist[i].cls == ASN1_CTX)
435 ctx = (ctx << 8) | taglist[i].tag;
439 #endif /* NEST, only for debugging */
442 /* Convert a bit string to an ascii representation for printing
443 * -- not thread safe ...
445 char *showbits(guchar *val, guint count)
447 static char str[BUFLM];
452 return "*too many bits*";
455 for(i=0; i<count; i++) {
456 if (i && ((i & 7) == 0)) *p++ = ' ';
457 *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
464 /* get bitnames string for bits set */
465 char * showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
467 static char str[BUFLL];
471 if (props->flags & OUT_FLAG_noname)
475 return "*too many bits, no names...*";
478 for(i=0; i<count; i++) {
479 if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
480 p += sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
484 --p; /* remove terminating , */
492 /* Convert an oid to its conventional text representation
493 * -- not thread safe...
495 char *showoid(subid_t *oid, guint len)
497 static char str[BUFLM];
502 for(i=0; i<len; i++) {
504 p += sprintf(p, "%lu", (unsigned long)oid[i]);
511 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
512 char *showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
517 char *endstr = empty;
523 for (i=0; i<len; i++) {
524 if (!isprint(octets[i])) /* maybe isblank() as well ... */
527 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
529 endstr = "...."; /* this is 5 bytes !! */
532 str = p = g_malloc(len*2 + 5);
533 for (i=0; i<len; i++) {
534 p += sprintf(p, "%2.2X", octets[i]);
538 if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
539 str = p = g_malloc(len*3+2);
540 for (i=0; i<len; i++) {
541 p += sprintf(p, "%2.2X", octets[i]);
543 *p++ = ' '; /* insert space */
544 strncpy(p, octets, len);
547 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
548 str = g_malloc(len+5);
549 strncpy(str, octets, len);
550 strcpy(&str[len], endstr);
557 /* allow NULL pointers in strcmp, handle them as empty strings */
559 g_strcmp(gconstpointer a, gconstpointer b)
561 if (a == 0) a = empty;
562 if (b == 0) b = empty;
566 guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
567 void PDUreset(int count, int counr2);
570 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
573 guint cls, con, tag, def, len, offset, reassembled;
579 volatile guint boffset;
580 volatile int i = 0; /* PDU counter */
581 proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
583 static guint lastseq;
588 reassembled = 1; /* UDP is not a stream, and thus always reassembled .... */
589 if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
590 struct tcpinfo *info = (struct tcpinfo *)pinfo->private_data;
591 gint delta = info->seq - lastseq;
592 reassembled = info->is_reassembled;
596 g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
597 info->seq, delta, reassembled);
600 g_message("dissect_asn1: udp");
603 /* Set the protocol column */
604 if(check_col(pinfo->cinfo, COL_PROTOCOL)){
605 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
608 if(check_col(pinfo->cinfo, COL_INFO))
609 col_clear(pinfo->cinfo, COL_INFO);
613 if ((first_pdu_offset > 0) && !reassembled) {
614 boffset = first_pdu_offset;
615 snprintf(offstr, sizeof(offstr), " at %d", boffset);
618 /* open BER decoding */
619 asn1_open(&asn1, tvb, boffset);
621 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
623 asn1_close(&asn1, &offset);
625 PDUreset(pcount, 0); /* arguments are just for debugging */
626 getPDUprops(&props, boffset, cls, tag, con);
631 snprintf(lenstr, sizeof(lenstr), "%d", len);
633 strncpy(lenstr, "indefinite", sizeof(lenstr) );
635 snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
637 snprintf(headstr, sizeof(headstr), "first%s: %s %d %s, %s, %s, len=%s, off=%d, size=%d ",
643 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
649 if (props.flags & OUT_FLAG_noname) {
650 snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
651 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
653 snprintf(headstr, sizeof(headstr), "first pdu%s: %s ", offstr, name );
656 /* Set the info column */
657 if(check_col(pinfo->cinfo, COL_INFO)){
658 col_add_str(pinfo->cinfo, COL_INFO, headstr );
662 * If we have a non-null tree (ie we are building the proto_tree
663 * instead of just filling out the columns ), then add a BER
667 /* ignore the tree here, must decode BER to know how to reassemble!! */
670 TRY { /* catch incomplete PDU's */
672 ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
673 def? (int) (offset - boffset + len) : -1,
674 "ASN.1 %s", current_pduname);
676 tree2 = proto_item_add_subtree(ti, ett_asn1);
678 offset = boffset; /* the first packet */
679 while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
682 /* open BER decoding */
683 asn1_open(&asn1, tvb, offset);
684 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
685 asn1_close(&asn1, &offset);
687 PDUreset(pcount, i+1);
688 getPDUprops(&props, boffset, cls, tag, con);
692 len = tvb_length_remaining(tvb, offset);
696 snprintf(lenstr, sizeof(lenstr), "%d", len);
698 strncpy(lenstr, "indefinite", sizeof(lenstr));
700 snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
702 snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
705 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
708 tvb_length_remaining(tvb, offset) );
710 if (props.value_id == -1)
711 ti2 = proto_tree_add_text(tree2, tvb, boffset,
712 def? (int) (offset - boffset + len) : -1,
713 "%s: %s %d-%d %s", current_pduname, name,
714 pcount, i+1, headstr);
716 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
717 def? (int) (offset - boffset + len) : -1,
718 "%s: %s %d-%d %s ~", current_pduname, name,
719 pcount, i+1, headstr);
721 if (props.type_id != -1)
722 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
723 def? (int) (offset - boffset + len) : -1, TRUE);
727 if (props.flags & OUT_FLAG_noname) {
728 snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
729 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
731 if (props.value_id == -1)
732 ti2 = proto_tree_add_text(tree2, tvb, boffset,
733 def? (int) (offset - boffset + len) : -1,
734 "%s: %s", current_pduname, name);
736 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
737 def? (int) (offset - boffset + len) : -1,
738 "%s: %s ~", current_pduname, name);
739 if (props.type_id != -1)
740 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
741 def? (int) (offset - boffset + len) : -1, TRUE);
744 asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
747 taglist[0].cls = cls;
748 taglist[0].tag = tag;
751 if (!def) len++; /* make sure we get an exception if we run off the end! */
752 offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
753 proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
755 i++; /* one more full message handled */
757 if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
758 proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
760 if(check_col(pinfo->cinfo, COL_INFO))
761 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
763 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
768 CATCH(ReportedBoundsError) {
769 if(check_col(pinfo->cinfo, COL_INFO))
770 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
772 proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
774 proto_item_append_text(ti2, " (incomplete)");
775 if (asn1_desegment) {
776 pinfo->desegment_offset = boffset;
777 pinfo->desegment_len = 1;
779 g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
780 boffset, 1, pinfo->can_desegment);
788 g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
789 pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
792 /* decode an ASN.1 sequence, until we have consumed the specified length */
794 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
797 guint ret, cls, con, tag, def, len, boffset, soffset, eos;
799 char *clsstr, *constr, *tagstr;
803 proto_tree *ti, *pt2;
804 guchar *octets, *bits, unused;
806 /* the debugging formats */
807 static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s"; /* decimal */
808 static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s"; /* enum */
809 static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s"; /* octet string */
810 static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s"; /* bit field */
811 static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s"; /* constructed */
812 static char matchind[] = " ~"; /* indication of possible match */
813 char *name, *ename, *tname, *oname;
816 ti = 0; /* suppress gcc warning */
818 soffset = offset; /* where this sequence starts */
820 while (offset < eos) { /* while this entity has not ended... */
822 asn1_open(&asn1, tvb, offset);
823 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
824 asn1_close(&asn1, &offset); /* mark current position */
825 if (ret != ASN1_ERR_NOERROR) {
826 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
830 getPDUprops(&props, boffset, cls, tag, con);
832 tname = props.typename;
834 name = &props.fullname[pabbrev_pdu_len]; /* no abbrev.pduname */
835 if (asn1_debug) { /* show both names */
836 sprintf(fieldname, "%s[%s]", props.name, props.fullname);
840 clsstr = asn1_cls[cls];
841 constr = asn1_con[con];
842 if ((cls == ASN1_UNI) && ( tag < 32 )) {
843 tagstr = asn1_tag[tag];
845 snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
849 snprintf(lenbuf, sizeof(lenbuf), "%d", len);
850 snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
852 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
853 strncpy(nnbuf, "NN-", sizeof(nnbuf));
854 /* make sure we get an exception if we run off the end! */
855 len = tvb_length_remaining(tvb, offset) + 1;
857 if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
858 /* just give type name if we don't know any better */
860 name = nnbuf; /* this is better than just empty.... */
864 taglist[level].cls = cls;
865 taglist[level].tag = tag;
869 if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
872 oname = g_malloc(strlen(name) + 32);
873 sprintf(oname, "%s ** nesting cut off **", name);
877 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
880 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
881 asn1_close(&asn1, &offset); /* mark where we are now */
883 if ( (props.value_id == -1) ||
884 (tbl_types_ethereal[props.type] != FT_UINT32) )
885 /* unknown or unexpected: just text */
886 proto_tree_add_text(pt, tvb, boffset,
887 offset - boffset, textfmt_d, boffset,
888 clsstr, constr, tagstr, tname, name, value,
891 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
892 offset - boffset, value, textfmt_d, boffset,
893 clsstr, constr, tagstr, tname, name, value,
895 if (props.type_id != -1)
896 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
897 boffset, offset - boffset, value);
900 if ( (props.value_id == -1) ||
901 (tbl_types_ethereal[props.type] != FT_UINT32) )
902 /* unknown or unexpected, just text */
903 proto_tree_add_text(pt, tvb, boffset,
905 "(%s)%s: %d", tname, name, value);
907 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
908 offset - boffset, value,
909 "(%s)%s: %d ~", tname, name, value);
910 if (props.type_id != -1)
911 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
912 boffset, offset - boffset, value);
918 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
919 asn1_close(&asn1, &offset); /* mark where we are now */
920 ename = getPDUenum(&props, boffset, cls, tag, value);
922 if ( (props.value_id == -1) ||
923 (tbl_types_ethereal[props.type] != FT_UINT32) )
924 /* unknown or unexpected, just text */
925 proto_tree_add_text(pt, tvb, boffset,
927 textfmt_e, boffset, clsstr, constr, tagstr,
928 tname, name, value, ename, empty);
930 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
931 offset - boffset, value,
932 textfmt_e, boffset, clsstr, constr, tagstr,
933 tname, name, value, ename, matchind);
934 if (props.type_id != -1)
935 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
936 boffset, offset - boffset, value);
939 if ( (props.value_id == -1) ||
940 (tbl_types_ethereal[props.type] != FT_UINT32) )
941 /* unknown or unexpected, just text */
942 proto_tree_add_text(pt, tvb, boffset,
944 "(%s)%s: %d:%s", tname, name, value, ename);
946 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
947 offset - boffset, value,
948 "(%s)%s: %d:%s ~", tname, name, value, ename);
949 if (props.type_id != -1)
950 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
951 boffset, offset - boffset, value);
957 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
958 asn1_close(&asn1, &offset); /* mark where we are now */
960 if ( (props.value_id == -1) ||
961 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
962 /* unknown or unexpected, just text */
963 proto_tree_add_text(pt, tvb, boffset,
965 textfmt_s, boffset, clsstr, constr, tagstr,
966 tname, name, value? "true" : "false", empty);
968 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
969 offset - boffset, value != 0,
970 textfmt_s, boffset, clsstr, constr, tagstr,
971 tname, name, value? "true" : "false", matchind);
972 if (props.type_id != -1)
973 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
974 boffset, offset - boffset, value != 0);
977 if ( (props.value_id == -1) ||
978 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
979 /* unknown or unexpected, just text */
980 proto_tree_add_text(pt, tvb, boffset,
982 "(%s)%s: %s", tname, name,
983 value? "true" : "false");
985 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
986 offset - boffset, value != 0,
987 "(%s)%s: %s ~", tname, name,
988 value? "true" : "false");
989 if (props.type_id != -1)
990 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
991 boffset, offset - boffset, value != 0);
1004 /* read value, \0 terminated */
1005 ret = asn1_string_value_decode(&asn1, len, &octets);
1006 asn1_close(&asn1, &offset); /* mark where we are now */
1007 ename = showoctets(octets, len, (tag == ASN1_OTS) ? 4 : 0 );
1009 if ( (props.value_id == -1) ||
1010 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1011 /* unknown or unexpected, just text */
1012 proto_tree_add_text(pt, tvb, boffset,
1014 textfmt_s, boffset, clsstr, constr, tagstr,
1015 tname, name, ename, empty);
1017 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1018 offset - boffset, octets, /* \0 termnated */
1019 textfmt_s, boffset, clsstr, constr, tagstr,
1020 tname, name, ename, matchind);
1021 if (props.type_id != -1)
1022 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1023 boffset, offset - boffset, octets);
1026 if ( (props.value_id == -1) ||
1027 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1028 /* unknown or unexpected, just text */
1029 proto_tree_add_text(pt, tvb, boffset,
1031 "(%s)%s: %s", tname, name, ename);
1033 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1034 offset - boffset, octets, /* \0 terminated */
1035 "(%s)%s: %s ~", tname, name, ename);
1036 if (props.type_id != -1)
1037 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1038 boffset, offset - boffset, octets);
1046 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1047 asn1_close(&asn1, &offset); /* mark where we are now */
1048 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1050 if ( (props.value_id == -1) ||
1051 (tbl_types_ethereal[props.type] != FT_UINT32) )
1052 /* unknown or unexpected, just text */
1053 proto_tree_add_text(pt, tvb, boffset,
1055 textfmt_b, boffset, clsstr, constr, tagstr,
1057 showbits(bits, (con*8)-unused), ename, empty);
1059 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1060 offset - boffset, *bits, /* XXX length ? XXX */
1061 textfmt_b, boffset, clsstr, constr, tagstr,
1063 showbits(bits, (con*8)-unused),ename, matchind);
1064 if (props.type_id != -1)
1065 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1066 boffset, offset - boffset, *bits);
1070 if ( (props.value_id == -1) ||
1071 (tbl_types_ethereal[props.type] != FT_UINT32) )
1072 /* unknown or unexpected, just text */
1073 proto_tree_add_text(pt, tvb, boffset,
1075 "(%s)%s: %s:%s", tname, name,
1076 showbits(bits, (con*8)-unused), ename);
1078 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1079 offset - boffset, *bits, /* XXX length ? XXX */
1080 "(%s)%s: %s:%s ~", tname, name,
1081 showbits(bits, (con*8)-unused), ename);
1082 if (props.type_id != -1)
1083 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1084 boffset, offset - boffset, *bits);
1092 /* show full sequence length */
1095 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1097 if ( (props.flags & OUT_FLAG_constructed))
1098 ename = ", unexpected constructed";
1100 if (props.value_id == -1)
1101 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1102 textfmt_c, boffset, clsstr, constr, tagstr,
1103 tname, name, ename, empty);
1105 ti = proto_tree_add_item(pt, props.value_id, tvb,
1107 /* change te text to to what I really want */
1108 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1109 tagstr, tname, name, ename, matchind);
1110 if (props.type_id != -1)
1111 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1115 if (props.value_id == -1) {
1116 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1117 ti = proto_tree_add_text(pt, tvb, boffset,
1118 offset - boffset + len,
1119 "(%s)%s", tname, name);
1121 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1122 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1123 boffset, offset - boffset + len,
1124 "(%s)%s ~", tname, name);
1126 /* don't care about the text */
1127 ti = proto_tree_add_item_hidden(pt, props.value_id, tvb,
1130 if (props.type_id != -1)
1131 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1135 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1137 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1138 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1142 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1144 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1145 proto_item_set_len(ti, offset - boffset);
1150 if (asn1_debug) { /* don't show if not debugging */
1151 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1152 boffset, clsstr, constr, tagstr, tname, name,
1153 offset - soffset, empty);
1155 getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1159 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1160 asn1_close(&asn1, &offset); /* mark where we are now */
1161 ename = showoid(oid, con);
1163 if ( (props.value_id == -1) ||
1164 (tbl_types_ethereal[props.type] != FT_BYTES) )
1165 /* unknown or unexpected, just text */
1166 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1167 boffset, clsstr, constr, tagstr, tname, name,
1170 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1171 offset - boffset, ename,/* XXX length?*/
1172 "(%s)%s: %s ~", tname, name, ename);
1173 if (props.type_id != -1)
1174 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1175 boffset, offset - boffset, ename);
1178 if ( (props.value_id == -1) ||
1179 (tbl_types_ethereal[props.type] != FT_BYTES) )
1180 /* unknown or unexpected, just text */
1181 proto_tree_add_text(pt, tvb, boffset,
1183 "(%s)%s: %s", tname, name, ename);
1185 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1186 offset - boffset, ename, /* XXX length ? */
1187 "(%s)%s: %s ~", tname, name, ename);
1188 if (props.type_id != -1)
1189 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1190 boffset, offset - boffset, ename);
1198 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1199 boffset, clsstr, constr, tagstr, tname, name,
1202 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1203 "(%s)%s: [NULL]", tname, name);
1205 offset += len; /* skip value ... */
1217 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1218 textfmt_s, boffset, clsstr, constr, tagstr,
1219 tname, name, lenbuf, empty);
1221 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1222 "(%s)%s: %s bytes", tname, name, lenbuf);
1224 proto_item_append_text(ti, " *"); /* indicate default is used */
1225 offset += len; /* skip value ... */
1230 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1231 case ASN1_APL: /* fprintf(stderr, "Application\n"); */
1232 case ASN1_PRV: /* fprintf(stderr, "Private\n"); */
1235 if (props.value_id == -1) /* type unknown, handle as string */
1237 switch(props.type) {
1238 /* this is via the asn1 description, don't trust the length */
1242 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1243 asn1_close(&asn1, &offset); /* mark where we are now */
1245 if ( (props.value_id == -1) ||
1246 (tbl_types_ethereal[props.type] != FT_UINT32) )
1247 /* unknown or unexpected, just text */
1248 proto_tree_add_text(pt, tvb,
1249 boffset, offset - boffset,
1250 textfmt_d, boffset, clsstr, constr,
1251 tagstr, tname, name, value, empty);
1253 proto_tree_add_uint_format(pt, props.value_id, tvb,
1254 boffset, offset - boffset, value,
1255 textfmt_d, boffset, clsstr, constr,
1256 tagstr, tname, name, value, matchind);
1257 if (props.type_id != -1)
1258 proto_tree_add_uint_hidden(pt, props.type_id,
1259 tvb, boffset, offset - boffset, value);
1262 if ( (props.value_id == -1) ||
1263 (tbl_types_ethereal[props.type] != FT_UINT32) )
1264 /* unknown or unexpected, just text */
1265 proto_tree_add_text(pt, tvb,
1266 boffset, offset - boffset,
1267 "(%s)%s: %d", tname, name, value);
1269 proto_tree_add_uint_format(pt, props.value_id, tvb,
1270 boffset, offset - boffset, value,
1271 "(%s)%s: %d ~", tname, name, value);
1272 if (props.type_id != -1)
1273 proto_tree_add_uint_hidden(pt, props.type_id,
1274 tvb, boffset, offset - boffset, value);
1279 case TBL_ENUMERATED:
1282 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1283 asn1_close(&asn1, &offset); /* mark where we are now */
1284 ename = getPDUenum(&props, boffset, cls, tag, value);
1286 if ( (props.value_id == -1) ||
1287 (tbl_types_ethereal[props.type] != FT_UINT32) )
1288 /* unknown or unexpected, just text */
1289 proto_tree_add_text(pt, tvb,
1290 boffset, offset - boffset,
1291 textfmt_e, boffset, clsstr, constr,
1292 tagstr, tname, name, value, ename, empty);
1294 proto_tree_add_uint_format(pt, props.value_id, tvb,
1295 boffset, offset - boffset, value,
1296 textfmt_e, boffset, clsstr, constr,
1297 tagstr, tname, name, value, ename, matchind);
1298 if (props.type_id != -1)
1299 proto_tree_add_uint_hidden(pt, props.type_id,
1300 tvb, boffset, offset - boffset, value);
1303 if ( (props.value_id == -1) ||
1304 (tbl_types_ethereal[props.type] != FT_UINT32) )
1305 /* unknown or unexpected, just text */
1306 proto_tree_add_text(pt, tvb,
1307 boffset, offset - boffset,
1308 "(%s)%s: %d:%s", tname, name, value, ename);
1310 proto_tree_add_uint_format(pt, props.value_id, tvb,
1311 boffset, offset - boffset, value,
1312 "(%s)%s: %d:%s ~", tname, name, value, ename);
1313 if (props.type_id != -1)
1314 proto_tree_add_uint_hidden(pt, props.type_id,
1315 tvb, boffset, offset - boffset, value);
1320 if (len > (1+4)) /* max 32 bits ...?.. */
1323 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1324 asn1_close(&asn1, &offset); /* mark where we are now */
1325 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1327 if ( (props.value_id == -1) ||
1328 (tbl_types_ethereal[props.type] != FT_UINT32) )
1329 /* unknown or unexpected, just text */
1330 proto_tree_add_text(pt, tvb,
1331 boffset, offset - boffset,
1332 textfmt_b, boffset, clsstr, constr,
1333 tagstr, tname, name,
1334 showbits(bits, (con*8)-unused), ename,
1337 proto_tree_add_uint_format(pt, props.value_id, tvb,
1338 boffset, offset - boffset, *bits,
1339 textfmt_b, boffset, clsstr, constr,
1340 tagstr, tname, name,
1341 showbits(bits, (con*8)-unused), ename,
1343 if (props.type_id != -1)
1344 proto_tree_add_uint_hidden(pt, props.type_id,
1345 tvb, boffset, offset - boffset, *bits);
1348 if ( (props.value_id == -1) ||
1349 (tbl_types_ethereal[props.type] != FT_UINT32) )
1350 /* unknown or unexpected, just text */
1351 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1352 "(%s)%s: %s:%s", tname, name,
1353 showbits(bits, (con*8)-unused), ename);
1355 proto_tree_add_uint_format(pt, props.value_id, tvb,
1356 boffset, offset - boffset, *bits,
1357 "(%s)%s: %s:%s ~", tname, name,
1358 showbits(bits, (con*8)-unused), ename);
1359 if (props.type_id != -1)
1360 proto_tree_add_uint_hidden(pt, props.type_id,
1361 tvb, boffset, offset - boffset, *bits);
1369 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1370 asn1_close(&asn1, &offset); /* mark where we are now */
1372 if ( (props.value_id == -1) ||
1373 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1374 /* unknown or unexpected, just text */
1375 proto_tree_add_text(pt, tvb,
1376 boffset, offset - boffset,
1377 textfmt_s, boffset, clsstr, constr,
1378 tagstr, tname, name,
1379 value? "true" : "false", empty);
1381 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1382 boffset, offset - boffset, value != 0,
1383 textfmt_s, boffset, clsstr, constr,
1384 tagstr, tname, name,
1385 value? "true" : "false", matchind);
1386 if (props.type_id != -1)
1387 proto_tree_add_boolean_hidden(pt, props.type_id,
1388 tvb, boffset, offset - boffset, value != 0);
1391 if ( (props.value_id == -1) ||
1392 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1393 /* unknown or unexpected, just text */
1394 proto_tree_add_text(pt, tvb,
1395 boffset, offset - boffset,
1396 "(%s)%s: %s", tname, name,
1397 value? "true" : "false");
1399 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1400 boffset, offset - boffset, value != 0,
1401 "(%s)%s: %s ~", tname, name,
1402 value? "true" : "false");
1403 if (props.type_id != -1)
1404 proto_tree_add_boolean_hidden(pt, props.type_id,
1405 tvb, boffset, offset - boffset, value != 0);
1413 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1414 textfmt_s, boffset, clsstr, constr,
1415 tagstr, tname, name, "[NULL]", empty);
1417 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1418 "(%s)%s: [NULL]", tname, name);
1420 offset += len; /* skip value ... */
1424 props.value_id = -1; /* unlikely this is correct, dont use it */
1426 case TBL_OCTETSTRING:
1427 /* defined length, not constructed, must be a string.... */
1428 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1429 asn1_close(&asn1, &offset); /* mark where we are now */
1430 ename = showoctets(octets, len, 2); /* convert octets to printable */
1432 if ( (props.value_id == -1) ||
1433 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1434 /* unknown or unexpected, just text */
1435 proto_tree_add_text(pt, tvb,
1436 boffset, offset - boffset,
1437 textfmt_s, boffset, clsstr, constr,
1438 tagstr, tname, name, ename, empty);
1440 proto_tree_add_string_format(pt, props.value_id, tvb,
1441 boffset, offset - boffset, octets, /* XXX */
1442 textfmt_s, boffset, clsstr, constr,
1443 tagstr, tname, name, ename, matchind);
1444 if (props.type_id != -1)
1445 proto_tree_add_string_hidden(pt, props.type_id,
1446 tvb, boffset, offset - boffset, octets);
1449 if ( (props.value_id == -1) ||
1450 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1451 /* unknown or unexpected, just text */
1452 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1453 "(%s)%s: %s", tname, name, ename);
1455 proto_tree_add_string_format(pt, props.value_id, tvb,
1456 boffset, offset - boffset, octets, /* XXX */
1457 "(%s)%s: %s ~", tname, name, ename);
1458 if (props.type_id != -1)
1459 proto_tree_add_string_hidden(pt, props.type_id,
1460 tvb, boffset, offset - boffset, octets);
1468 /* indefinite length or constructed.... must be a sequence .... */
1469 /* show full sequence length */
1472 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1474 if ( (props.flags & OUT_FLAG_constructed))
1475 ename = ", unexpected constructed";
1477 if (props.value_id == -1)
1478 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1479 textfmt_c, boffset, clsstr, constr,
1480 tagstr, tname, name, ename, empty);
1482 ti = proto_tree_add_item(pt, props.value_id, tvb,
1484 /* change te text to to what I really want */
1486 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1487 tagstr, tname, name, ename, matchind);
1488 if (props.type_id != -1)
1489 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1492 ti = proto_tree_add_text(pt, tvb, boffset,
1493 offset - boffset + len,
1494 textfmt_c, boffset, clsstr, constr,
1495 tagstr, tname, name, ename, empty);
1499 if (props.value_id == -1) {
1500 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1501 ti = proto_tree_add_text(pt, tvb, boffset,
1502 offset - boffset + len, "(%s)%s", tname, name);
1504 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1505 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1507 "(%s)%s ~", tname, name);
1509 /* don't care about the text */
1510 ti = proto_tree_add_item_hidden(pt, props.value_id,
1511 tvb, boffset, 1, TRUE);
1513 if (props.type_id != -1)
1514 proto_tree_add_item_hidden(pt, props.type_id,
1515 tvb, boffset, 1, TRUE);
1519 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1521 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1522 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1526 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1528 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1529 proto_item_set_len(ti, offset - boffset);
1533 default: /* fprintf(stderr, "Other\n"); */
1535 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1536 textfmt_s, boffset, clsstr, constr, tagstr,
1537 tname, name, lenbuf, empty);
1539 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1540 "(%s)%s: %s bytes %s data", tname, name,
1543 proto_item_append_text(ti, " *"); /* indicate default is used */
1544 offset += len; /* skip value ... */
1547 g_free(oname); /* XXX, memory management ? */
1549 /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1551 getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1558 /************************************************************************************************/
1559 /* search throug the ASN.1 description for appropriate names */
1560 /************************************************************************************************/
1562 guint lev_limit = G_MAXINT;
1564 int icount = 0; /* item counter */
1567 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1570 guint eos, ret, cls, con, tag, def, len, value;
1571 guchar *octets, *bits, unused;
1573 char *clsstr, *constr, *tagstr;
1576 GNode *cur_node = 0;
1578 eos = offset + size;
1580 if (level > lev_limit)
1583 while(offset < eos) {
1584 if (ptr) /* build pointer tree to all asn1 enteties */
1585 cur_node = g_node_append_data(ptr, (void *)offset);
1587 asn1_open(&asn1, tvb, offset);
1588 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1589 asn1_close(&asn1, &offset); /* mark where we are */
1591 clsstr = asn1_cls[cls];
1592 constr = asn1_con[con];
1593 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1594 tagstr = asn1_tag[tag];
1596 snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1600 snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1602 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1603 len = tvb_length_remaining(tvb, offset);;
1607 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
1611 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1612 asn1_close(&asn1, &offset); /* mark where we are */
1616 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1617 asn1_close(&asn1, &offset); /* mark where we are */
1628 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1629 asn1_close(&asn1, &offset); /* mark where we are */
1634 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1635 asn1_close(&asn1, &offset); /* mark where we are */
1641 if (len == 0) /* don't recurse if offset isn't going to change */
1644 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1651 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1652 asn1_close(&asn1, &offset); /* mark where we are */
1668 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1669 offset += len; /* skip value ... */
1674 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1676 snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
1678 /* defined length, not constructed, must be a string.... */
1679 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1680 asn1_close(&asn1, &offset); /* mark where we are */
1683 /* indefinite length or constructed.... must be a sequence .... */
1684 if (len == 0) /* don't recurse if offset isn't going to change */
1687 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1691 default: /* fprintf(stderr, "Other\n"); */
1692 if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1693 offset += len; /* skip value ... */
1700 void showGNodes(GNode *p, int n);
1703 myLeaf(GNode *node, gpointer data)
1706 guint ret, cls, con, tag, def, len;
1707 char *clsstr, *constr, *tagstr;
1711 (void) data; /* make a reference */
1712 asn1_open(&asn1, asn1_desc, (int)node->data);
1714 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1716 clsstr = asn1_cls[cls];
1717 constr = asn1_con[con];
1718 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1719 tagstr = asn1_tag[tag];
1721 snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1725 snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1727 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1731 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1739 if (asn1_verbose) g_message("build GNode tree:");
1740 showGNodes(g_node_first_child(asn1_nodes), 0);
1741 if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1742 g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1743 g_node_max_height (asn1_nodes),
1744 g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1745 g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1747 g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1752 tt_build_tree(void) /* build a GNode tree with all offset's to ASN.1 entities */
1755 g_node_destroy(asn1_nodes);
1756 asn1_nodes = g_node_new(0);
1758 parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1762 /*****************************************************************************************************/
1764 guint anonCount; /* for naming anonymous types */
1766 typedef struct _TBLModule TBLModule;
1767 typedef struct _TBLTypeDef TBLTypeDef;
1768 typedef struct _TBLTag TBLTag;
1769 typedef struct _TBLType TBLType;
1770 typedef struct _TBLTypeRef TBLTypeRef;
1771 typedef struct _TBLNamedNumber TBLNamedNumber;
1772 typedef struct _TBLRange TBLRange;
1780 TBLTYPE_NamedNumber,
1783 typedef enum _tbl_t tbl_t;
1784 /* text for 'tbl_t' type for debugging */
1785 char *data_types[] = { "Module",
1794 enum _TBLTypeContent_t {
1796 TBLTYPETYPE_Primitive,
1797 TBLTYPETYPE_Elements,
1800 typedef enum _TBLTypeContent_t TBLTypeContent_t;
1802 struct _TBLNamedNumber {
1814 struct _TBLTypeRef {
1830 TBLTypeContent_t content;
1833 gboolean constraint;
1836 struct _TBLTypeDef {
1851 guint totalNumModules;
1852 guint totalNumTypeDefs;
1853 guint totalNumTypes;
1855 guint totalNumStrings;
1856 guint totalLenStrings;
1859 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
1862 get_asn1_int(guint want_tag, guint offset)
1865 guint ret, cls, con, tag, def, len;
1868 /* g_message("%d get_asn1_int", offset); */
1870 asn1_open(&asn1, asn1_desc, offset);
1872 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1873 if (ret == ASN1_ERR_NOERROR) {
1874 /* do not check class, both Unversal and Context are OK */
1875 if (con == ASN1_PRI && tag == want_tag) {
1877 asn1_uint32_value_decode(&asn1, len, &value);
1880 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
1882 ret = ASN1_ERR_WRONG_TYPE;
1884 g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
1889 subid_t * /* with prepended length ..... */
1890 get_asn1_oid(guint want_tag, guint offset)
1893 guint ret, cls, con, tag, def, len;
1896 /* g_message("%d get_asn1_oid", offset); */
1898 asn1_open(&asn1, asn1_desc, offset);
1900 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1901 if (ret == ASN1_ERR_NOERROR) {
1902 /* do not check class, both Unversal and Context are OK */
1903 if ((con == ASN1_PRI) && (tag == want_tag)) {
1905 asn1_oid_value_decode(&asn1, len, &oid, &con);
1906 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
1907 memmove(&oid[1], oid, con*sizeof(guint));
1911 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
1913 ret = ASN1_ERR_WRONG_TYPE;
1915 g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
1920 guchar * /* 0 terminated string */
1921 get_asn1_string(guint want_tag, guint offset)
1924 guint ret, cls, con, tag, def, len;
1927 /* g_message("%d get_asn1_string", offset); */
1929 asn1_open(&asn1, asn1_desc, offset);
1931 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1932 if (ret == ASN1_ERR_NOERROR) {
1933 /* do not check class, both Unversal and Context are OK */
1934 if ((con == ASN1_PRI) && (tag == want_tag)) {
1936 asn1_string_value_decode(&asn1, len, &octets);
1937 octets = g_realloc(octets, len+1); /* need space for sentinel */
1941 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
1943 ret = ASN1_ERR_WRONG_TYPE;
1945 g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
1951 get_asn1_uint(guint offset)
1954 guint ret, len, value;
1956 /* g_message( "%d get_asn1_uint", offset); */
1958 asn1_open(&asn1, asn1_desc, offset);
1960 ret = asn1_uint32_decode(&asn1, &value, &len);
1962 if (ret != ASN1_ERR_NOERROR) {
1963 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
1970 check_tag(guint want_tag, guint offset)
1973 guint ret, cls, con, tag, def, len;
1975 asn1_open(&asn1, asn1_desc, offset);
1977 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1978 if (ret == ASN1_ERR_NOERROR) {
1979 ret = (tag == want_tag) ? TRUE : FALSE;
1980 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
1983 g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
1989 constructed(guint offset)
1992 guint ret, cls, con, tag, def, len;
1994 /* g_message("%d constructed?", offset); */
1996 asn1_open(&asn1, asn1_desc, offset);
1998 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1999 if (ret == ASN1_ERR_NOERROR) {
2005 /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2011 define_constraint(GNode *p, GNode *q)
2013 TBLRange *range = g_malloc(sizeof(TBLRange));
2014 g_node_append_data(q, range);
2016 range->type = TBLTYPE_Range;
2018 /* g_message("define_constraint %p, %p", p, q); */
2020 p = g_node_first_child(p);
2022 range->from = get_asn1_int(0, (guint)p->data);
2023 p = g_node_next_sibling(p);
2025 range->to = get_asn1_int(1, (guint)p->data);
2030 define_namednumber(GNode *p, GNode *q)
2032 TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2033 g_node_append_data(q, num);
2035 num->type = TBLTYPE_NamedNumber;
2037 /* g_message("define_namednumber %p, %p", p, q); */
2039 p = g_node_first_child(p);
2041 num->name = get_asn1_string(0, (guint)p->data);
2042 p = g_node_next_sibling(p);
2044 num->value = get_asn1_int(1, (guint)p->data);
2048 define_typeref(GNode *p, GNode *q)
2050 TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2051 g_node_append_data(q, ref);
2053 ref->type = TBLTYPE_TypeRef;
2055 /* g_message("define_typeref %p, %p", p, q); */
2057 p = g_node_first_child(p);
2059 ref->typeDefId = get_asn1_uint((guint)p->data);
2060 p = g_node_next_sibling(p);
2062 ref->implicit = get_asn1_int(ASN1_BOL, (guint)p->data);
2066 define_tag(GNode *p, GNode *q)
2068 TBLTag *type = g_malloc(sizeof(TBLTag));
2069 g_node_append_data(q, type);
2071 type->type = TBLTYPE_Tag;
2073 /* g_message("define_tag %p, %p", p, q); */
2075 p = g_node_first_child(p);
2077 type->tclass = get_asn1_int(ASN1_ENUM, (guint)p->data);
2078 p = g_node_next_sibling(p);
2080 type->code = get_asn1_int(ASN1_INT, (guint)p->data);
2085 define_type(GNode *p, GNode *q)
2088 TBLType *type = g_malloc(sizeof(TBLType));
2090 GNode *t = g_node_append_data(q, type);
2092 type->type = TBLTYPE_Type;
2094 /* g_message("define_type %p, %p", p, q); */
2096 type->typeId = get_asn1_int(0, (guint)p->data);
2097 p = g_node_next_sibling(p);
2099 type->optional = get_asn1_int(1, (guint)p->data);
2100 p = g_node_next_sibling(p);
2102 if (check_tag(2, (guint)p->data)) { /* optional, need empty node if not there ?*/
2103 r = g_node_first_child(p);
2106 r = g_node_next_sibling(r);
2108 p = g_node_next_sibling(p);
2111 if (!check_tag(3, (guint)p->data)) {
2112 g_warning("expect tag 3, ERROR");
2114 r = g_node_first_child(p);
2116 type->content = TBLTYPETYPE_None;
2117 if (check_tag(0, (guint)r->data)) type->content = TBLTYPETYPE_Primitive;
2118 if (check_tag(1, (guint)r->data)) type->content = TBLTYPETYPE_Elements;
2119 if (check_tag(2, (guint)r->data)) type->content = TBLTYPETYPE_TypeRef;
2120 switch(type->content) {
2121 case TBLTYPETYPE_Primitive:
2123 case TBLTYPETYPE_Elements:
2124 r = g_node_first_child(r);
2126 define_type(g_node_first_child(r), t);
2127 r = g_node_next_sibling(r);
2130 case TBLTYPETYPE_TypeRef:
2131 define_typeref(r, t);
2133 case TBLTYPETYPE_None:
2134 g_warning("expected a contents choice, error");
2137 p = g_node_next_sibling(p);
2139 type->fieldName = 0;
2140 type->anonymous = FALSE;
2141 if (p && check_tag(4, (guint)p->data)) {
2142 type->fieldName = get_asn1_string(4, (guint)p->data);
2143 p = g_node_next_sibling(p);
2145 type->anonymous = TRUE;
2148 type->constraint = FALSE;
2149 if (p && check_tag(5, (guint)p->data)) {
2150 type->constraint = TRUE;
2151 define_constraint(p, t);
2152 p = g_node_next_sibling(p);
2155 if (p && check_tag(6, (guint)p->data)) {
2156 r = g_node_first_child(p);
2158 define_namednumber(r, t);
2159 r = g_node_next_sibling(r);
2165 define_typedef(GNode *p, GNode *q)
2167 TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2169 GNode *t = g_node_append_data(q, type_def);
2171 /* g_message("define_typedef %p, %p", p, q); */
2173 type_def->type = TBLTYPE_TypeDef;
2175 p = g_node_first_child(p);
2177 type_def->typeDefId = get_asn1_uint((guint)p->data);
2178 p = g_node_next_sibling(p);
2180 type_def->typeName = get_asn1_string(ASN1_PRNSTR, (guint)p->data);
2181 p = g_node_next_sibling(p);
2183 define_type(g_node_first_child(p), t);
2184 p = g_node_next_sibling(p);
2186 type_def->isPdu = (p != 0); /* true if it exists, value ignored */
2190 define_module(GNode *p, GNode *q)
2192 TBLModule *module = g_malloc(sizeof(TBLModule));
2194 GNode *m = g_node_append_data(q, module);
2196 /* g_message("define_module %p %p", p, q); */
2198 module->type = TBLTYPE_Module;
2200 p = g_node_first_child(p);
2202 module->name = get_asn1_string(0, (guint)p->data);
2203 p = g_node_next_sibling(p);
2206 if (check_tag(1, (guint)p->data)) { /* optional */
2207 module->id = get_asn1_oid(1, (guint)p->data);
2208 p = g_node_next_sibling(p);
2211 module->isUseful = get_asn1_int(2, (guint)p->data);
2212 p = g_node_next_sibling(p);
2214 p = g_node_first_child(p);
2216 define_typedef(p, m);
2217 p = g_node_next_sibling(p);
2221 typedef struct _SearchDef SearchDef;
2228 is_typedef(GNode *node, gpointer data)
2230 TBLTypeDef *d = (TBLTypeDef *)node->data;
2231 SearchDef *s = (SearchDef *)data;
2233 if (d == 0) return FALSE;
2234 if (d->type != TBLTYPE_TypeDef) return FALSE;
2235 if (strcmp(s->key, d->typeName) == 0) {
2242 typedef struct _TypeRef TypeRef;
2248 GNode *pdu; /* location in PDU descriptor tree */
2249 guint level; /* recursion counter */
2251 GPtrArray *refs; /* pointers to PDUinfo structures teferencing this entry */
2254 typedef struct _NameDefs NameDefs;
2260 #define ALLOC_INCR 4
2261 #define CLASSREF (ASN1_PRV+1)
2264 is_named(GNode *node, gpointer data)
2266 TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2267 NameDefs *n = (NameDefs *)data;
2270 if (num == 0) return FALSE;
2271 if (num->type != TBLTYPE_NamedNumber) return FALSE;
2273 if (num->value >= n->max) { /* need larger array */
2275 n->max = num->value + ALLOC_INCR;
2276 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2277 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2279 if (num->value > n->used) /* track max used value, there may be holes... */
2280 n->used = num->value;
2282 n->info[num->value].name = num->name;
2288 index_typedef(GNode *node, gpointer data)
2290 TBLTypeDef *d = (TBLTypeDef *)node->data;
2291 NameDefs *n = (NameDefs *)data;
2296 if (d == 0) return FALSE;
2297 if (d->type != TBLTYPE_TypeDef) return FALSE;
2299 if (d->typeDefId >= n->max) { /* need larger array */
2301 n->max = d->typeDefId + ALLOC_INCR;
2302 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2303 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2305 if (d->typeDefId > n->used) /* track max used value, there may be holes... */
2306 n->used = d->typeDefId;
2308 t = &(n->info[d->typeDefId]);
2309 t->name = d->typeName;
2311 t->refs = g_ptr_array_new(); /* collect references here */
2312 node = g_node_first_child(node); /* the real type */
2313 tag = (TBLTag *)node->data;
2314 if ((tag->type == TBLTYPE_Type) && (((TBLType *)tag)->typeId == TBL_CHOICE)) {
2315 /* no reasonable default... ! */
2316 t->defclass = 3; /* Private .... */
2317 t->deftag= 9999; /* a random value */
2319 node = g_node_first_child(node); /* the default tag */
2320 tag = (TBLTag *)node->data;
2323 t->defclass = tag->tclass;
2324 t->deftag = tag->code;
2326 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2327 t->defclass = CLASSREF; /* invalid class.. */
2328 t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2331 g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2332 data_types[tag->type]);
2333 t->defclass = 3; /* Private .... */
2334 t->deftag= 9998; /* another random value */
2342 TypeRef *typeDef_names = 0;
2343 guint numTypedefs = 0;
2346 get_values(void) /* collect values from ASN.1 tree */
2347 /* coded according to the tbl.asn1 description of snacc output */
2348 { /* This routine does not leave references to the tvbuff or */
2349 /* to the asn1_nodes, both can be freed by the caller of this.*/
2355 static char missing[] = " **missing** ";
2357 if (asn1_verbose) g_message("interpreting tree");
2358 typeDef_names = 0; /* just forget allocated any data .... */
2361 g_node_destroy(data_nodes);
2363 data_nodes = g_node_new(0);
2365 p = g_node_first_child(asn1_nodes); /* top of the data tree */
2367 p = g_node_first_child(p);
2368 TT.totalNumModules = get_asn1_uint((guint)p->data);
2369 p = g_node_next_sibling(p);
2370 TT.totalNumTypeDefs = get_asn1_uint((guint)p->data);
2371 p = g_node_next_sibling(p);
2372 TT.totalNumTypes = get_asn1_uint((guint)p->data);
2373 p = g_node_next_sibling(p);
2374 TT.totalNumTags = get_asn1_uint((guint)p->data);
2375 p = g_node_next_sibling(p);
2376 TT.totalNumStrings = get_asn1_uint((guint)p->data);
2377 p = g_node_next_sibling(p);
2378 TT.totalLenStrings = get_asn1_uint((guint)p->data);
2379 p = g_node_next_sibling(p);
2381 p = g_node_first_child(p);
2383 define_module(p, data_nodes);
2384 p = g_node_next_sibling(p);
2387 /* g_message("finished with tree"); */
2389 if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2390 sd.key = "TBLTypeId";
2392 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2393 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", sd.here);
2397 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2398 g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2400 if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, nd.info);
2402 for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2405 s = nd.info[i].name;
2406 if (s == 0) s = missing;
2407 if (g_strcmp(t, s) == 0) { /* OK ! */
2411 E = ", X with errors X";
2413 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2415 if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2417 tbl_types_verified = TRUE;
2419 /* build table with typedef names */
2422 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2423 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2424 if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, nd.info);
2426 for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2427 TypeRef *ref = &(nd.info[i]);
2430 t = ref->name = missing;
2431 if (asn1_verbose) g_message(" %3d %s", i, t);
2433 if (asn1_verbose) g_message(" %3d %s, %c%d", i, t,
2434 tag_class[ref->defclass], ref->deftag);
2436 if (ref->pdu) { /* should be 0 */
2437 if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, ref->pdu);
2440 typeDef_names = nd.info;
2442 if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
2447 showGNode(GNode *p, int n)
2450 n *=2; /* 2 spaces per level */
2451 if (p->data) { /* show value ... */
2452 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
2453 switch (((TBLTag *)p->data)->type) {
2454 case TBLTYPE_Module: {
2455 TBLModule *m = (TBLModule *)p->data;
2457 g_message("%*smodule %s%s", n, empty, m->name,
2458 m->isUseful ? ", useful" : empty);
2461 case TBLTYPE_TypeDef: {
2462 TBLTypeDef *t = (TBLTypeDef *)p->data;
2464 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
2465 t->isPdu ? ", isPDU" : empty);
2468 case TBLTYPE_Type: {
2469 TBLType *t = (TBLType *)p->data;
2470 char *fn, *s = empty;
2473 /* typeId is a value from enum TBLTypeId */
2474 fn = TBLTYPE(t->typeId);
2475 if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
2476 t->optional ? " opt" : empty, s );
2480 TBLTag *t = (TBLTag *)p->data;
2482 if ((t->tclass == ASN1_UNI) && (t->code < 32))
2483 s = asn1_tag[t->code];
2484 if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
2485 tag_class[t->tclass], t->code, s);
2488 case TBLTYPE_NamedNumber: {
2489 TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
2490 if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
2491 nn->value, nn->name);
2494 case TBLTYPE_Range: {
2495 TBLRange *r = (TBLRange *)p->data;
2496 if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
2500 case TBLTYPE_TypeRef: {
2501 TBLTypeRef *r = (TBLTypeRef *)p->data;
2504 s = typeDef_names[r->typeDefId].name;
2505 if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
2506 r->typeDefId, s, r->implicit ? ", implicit" : empty );
2510 TBLTag *x = (TBLTag *)p->data;
2511 if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
2515 } else { /* just show tree */
2517 g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
2518 n, empty, p, p->data, p->next, p->prev, p->parent, p->children);
2523 showGNodes(GNode *p, int n)
2527 showGNodes(p->children, n+1);
2528 showGNodes(p->next, n);
2531 void showGenv(GNode *p, int n, int m)
2537 if (asn1_verbose) g_message("%*s.....", n*2, empty);
2541 for(i=0; p && (i < 3); p = p->next, i++) {
2543 showGenv(p->children, n+1, m);
2545 if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
2550 debug_dump_TT(void) /* dump contents of TT struct, for debugging */
2553 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
2555 TT.totalNumTypeDefs,
2559 TT.totalLenStrings);
2563 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
2564 const gchar *message, gpointer user_data)
2566 static FILE* logf = 0;
2567 static char eol[] = "\r\n";
2569 (void) log_domain; (void) log_level; (void) user_data; /* make references */
2571 if (logf == NULL && asn1_logfile) {
2572 logf = fopen(asn1_logfile, "w");
2575 fputs(message, logf);
2581 read_asn1_type_table(char *filename)
2588 if ((filename == 0) || (strlen(filename) == 0))
2589 return; /* no filename provided */
2591 f = fopen(filename, "rb");
2594 * Ignore "file not found" errors if it's the old default
2595 * ASN.1 file name, as we never shipped such a file.
2596 * Also, on Win32, ignore the earlier default, which
2597 * had a "/" rather than a "\" as the last pathname
2600 if ((strcmp(filename, old_default_asn1_filename) != 0
2602 && strcmp(filename, bad_separator_old_default_asn1_filename) != 0
2604 ) || errno != ENOENT)
2605 report_open_failure(filename, errno, FALSE);
2608 fstat(fileno(f), &stat);
2609 size = (int)stat.st_size;
2611 if (asn1_verbose) g_message("file %s is empty, ignored", filename);
2615 if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
2617 data = g_malloc(size);
2618 if (fread(data, size, 1, f) < 1) {
2619 report_read_failure(filename, errno);
2624 /* ***** from the time when logging was just in a console... *****
2625 * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
2626 * " Sleep 5 sec...");
2630 static guint mylogh = 0;
2632 g_message("logging to file %s", asn1_logfile);
2635 mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2636 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
2640 asn1_desc = tvb_new_real_data(data, size, size);
2643 if (asn1_verbose) g_message("read %d items from %s", icount, filename);
2645 /* list_modules(); */
2649 g_node_destroy(asn1_nodes); asn1_nodes = 0;
2650 #ifndef WIN32 /* tvb_free not yet exported to plugins... */
2651 tvb_free(asn1_desc);
2654 g_free(data); data = 0;
2656 showGNodes(data_nodes, 0);
2661 typedef struct _PDUinfo PDUinfo;
2672 gint basetype; /* parent type */
2673 gint mytype; /* original type number, typenum may have gone through a reference */
2674 gint value_id; /* ethereal field id for the value in this PDU */
2675 gint type_id; /* ethereal field id for the type of this PDU */
2676 hf_register_info value_hf; /* ethereal field info for this value */
2680 /* bits in the flags collection */
2681 #define PDU_OPTIONAL 1
2682 #define PDU_IMPLICIT 2
2683 #define PDU_NAMEDNUM 4
2684 #define PDU_REFERENCE 8
2685 #define PDU_TYPEDEF 0x10
2686 #define PDU_ANONYMOUS 0x20
2687 #define PDU_TYPETREE 0x40
2689 #define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
2691 guint PDUinfo_initflags = 0; /* default flags for newly allocated PDUinfo structs */
2693 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
2694 g_warning("**** unexpected type %s, want %s, at line %d", \
2695 data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
2699 save_reference(PDUinfo *p)
2706 g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
2710 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex);
2714 /* evaluate typeref, pointer to current pdu node and typedef */
2716 tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
2719 PDUinfo *p = (PDUinfo *)pdu->data, *p1;
2723 CHECKTYPE(tree, TBLTYPE_TypeDef);
2725 if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
2726 p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2728 p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
2729 p->flags |= PDU_TYPEDEF;
2731 tree = g_node_first_child(tree); /* move to its underlying type */
2732 CHECKTYPE(tree, TBLTYPE_Type);
2733 p->type = ((TBLType *)tree->data)->typeId;
2735 q = g_node_first_child(tree); /* the tag of this type entry ... is optional... */
2736 if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
2737 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
2741 /* XXX -- hack -- hack -- hack -- hack -- hack --
2742 * only change tag when class+tag == EOC,
2743 * or class is a reference,
2744 * or new class is not universal.
2746 if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
2747 (((TBLTag *)q->data)->tclass != ASN1_UNI) ) {
2748 p->tclass = ((TBLTag *)q->data)->tclass;
2749 p->tag = ((TBLTag *)q->data)->code;
2751 g_message("%*s*change typeref tag from %c%d to %c%d",
2755 tag_class[p->tclass],
2759 g_message("%*sNOT changing tag from %c%d to %c%d",
2763 tag_class[((TBLTag *)q->data)->tclass],
2764 ((TBLTag *)q->data)->code);
2772 if (p->tclass==CLASSREF)
2773 snprintf(ss, 128, ", CLASSREF %d", p->tag);
2774 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
2776 if (p->tclass==CLASSREF) {
2778 /* CLASSREF....., get it defined using type of the reference */
2780 tr = &typeDef_names[p->tag];
2782 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
2783 p->tag, tr->name, tr->pdu);
2785 tbl_typeref(n+1, pdu, tr->type, fullindex);
2792 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
2793 p->name, p->typename, p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2797 case TBL_ENUMERATED:
2798 /* names do not have a fullname */
2799 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
2800 /* read the enumeration [save min-max somewhere ?] */
2801 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type]; /* XXX change field type... */
2803 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2808 g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2809 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2810 p->name, p->fullname,
2811 tbl_types_ethereal_txt[p->type], p->value_id);
2814 while((q = g_node_next_sibling(q))) {
2815 CHECKTYPE(q, TBLTYPE_NamedNumber);
2816 p = g_malloc0(sizeof(PDUinfo));
2818 p->type = TBL_ENUMERATED;
2819 p->name = (((TBLNamedNumber *)q->data)->name);
2820 p->tag = (((TBLNamedNumber *)q->data)->value);
2821 p->flags = PDU_NAMEDNUM;
2822 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
2823 g_node_append_data(pdu, p);
2826 /* list all enum values in the field structure for matching */
2827 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
2828 q = g_node_first_child(pdu);
2831 p = (PDUinfo *)q->data;
2832 v[nvals].value = p->tag;
2833 v[nvals].strptr = p->name;
2834 /* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
2836 q = g_node_next_sibling(q);
2838 /* last entry is already initialized to { 0, NULL } */
2843 if (p->value_id == -1) { /* not yet registered ..... */
2844 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
2845 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2850 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2851 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2852 p->name, p->fullname,
2853 tbl_types_ethereal_txt[p->type], p->value_id);
2855 tbl_type(n, pdu, q, fullindex);
2859 if (p->value_id == -1) { /* not yet registered ..... */
2860 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
2861 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2866 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2867 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2868 p->name, p->fullname,
2869 tbl_types_ethereal_txt[p->type], p->value_id);
2871 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
2876 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
2884 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
2885 g_warning("**** n>40, return [recursion too deep] ****************");
2889 /* showGenv(list, n, n+1); */
2892 pdu1 = pdu; /* save start location for append */
2893 while (list) { /* handle all entries */
2895 g_message("%*s+handle a %s", n*2, empty,
2896 data_types[((TBLTag *)list->data)->type]);
2898 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
2899 list = g_node_next_sibling(list);
2900 if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
2905 if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
2906 CHECKTYPE(list, TBLTYPE_Type);
2908 p = g_malloc0(sizeof(PDUinfo));
2909 pdu = g_node_append_data(pdu1, p);
2911 p->type = ((TBLType *)list->data)->typeId;
2912 p->typename = tbl_types_asn1[p->type]; /* the default type */
2915 p->basetype = ((PDUinfo *)pdu1->data)->typenum;
2916 p->flags = PDUinfo_initflags;
2917 p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
2918 p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
2920 if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
2921 /* assign an anonymous name [XXX refer to parent typename...] */
2922 ((TBLType *)list->data)->fieldName =
2923 g_strdup_printf("anon%d", anonCount++);
2925 p->name = ((TBLType *)list->data)->fieldName;
2928 ni += sprintf(&fieldname[ni], ".%s", p->name);
2929 p->fullname = g_strdup(fieldname);
2931 /* initialize field info */
2934 p->value_hf.p_id = &(p->value_id);
2935 p->value_hf.hfinfo.name = p->fullname;
2936 p->value_hf.hfinfo.abbrev = p->fullname;
2937 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
2938 p->value_hf.hfinfo.display = BASE_DEC;
2939 p->value_hf.hfinfo.blurb = p->fullname;
2940 /* all the other fields are already 0 ! */
2942 if (p->type < TBL__SIMPLE) {
2943 /* only register fields with a value here, postpone others */
2944 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2949 g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2950 p->mytype, p->typenum, p->basetype, p->flags,
2951 p->typename, p->name, p->fullname,
2952 tbl_types_ethereal_txt[p->type], p->value_id);
2955 q = g_node_first_child(list);
2957 p = (PDUinfo *)pdu->data;
2962 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
2967 case TBL_OCTETSTRING:
2971 CHECKTYPE(q, TBLTYPE_Tag);
2972 p->tclass = ((TBLTag *)q->data)->tclass;
2973 p->tag = ((TBLTag *)q->data)->code;
2977 case TBL_ENUMERATED:
2978 CHECKTYPE(q, TBLTYPE_Tag);
2979 p->tclass = ((TBLTag *)q->data)->tclass;
2980 p->tag = ((TBLTag *)q->data)->code;
2981 if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
2982 /* read the enumeration [save min-max somewhere ?] */
2985 while((q = g_node_next_sibling(q))) {
2986 CHECKTYPE(q, TBLTYPE_NamedNumber);
2987 p = g_malloc0(sizeof(PDUinfo));
2989 p->type = TBL_ENUMERATED;
2990 p->name = (((TBLNamedNumber *)q->data)->name);
2991 p->tag = (((TBLNamedNumber *)q->data)->value);
2992 p->flags = PDU_NAMEDNUM;
2993 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
2994 g_node_append_data(pdu, p);
2997 /* list all enum values in the field structure for matching */
2998 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
2999 q = g_node_first_child(pdu);
3002 p = (PDUinfo *)q->data;
3003 v[nvals].value = p->tag;
3004 v[nvals].strptr = p->name;
3005 /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3007 q = g_node_next_sibling(q);
3009 /* last entry is already initialized to { 0, NULL } */
3015 case TBL_SEQUENCEOF:
3018 CHECKTYPE(q, TBLTYPE_Tag);
3019 tbl_type(n+1, pdu, q, ni);
3022 case TBL_TYPEREF: { /* may have a tag ... */
3025 if ( q && (((TBLTag *)q->data)->type == TBLTYPE_Tag)) {
3026 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3027 p->tclass = ((TBLTag *)q->data)->tclass;
3028 p->tag = ((TBLTag *)q->data)->code;
3030 g_message("%*s*insert type tag %c%d", n*2, empty,
3031 tag_class[p->tclass], p->tag);
3033 q = g_node_next_sibling(q);
3034 } else { /* use default tag for this type */
3035 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3036 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != ASN1_UNI)) ||
3037 ((p->tclass | p->tag) == 0 )) {
3038 /* not implicit, use this tag */
3039 p->tclass = tr->defclass;
3040 p->tag = tr->deftag;
3041 if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3042 tag_class[p->tclass], p->tag);
3045 CHECKTYPE(q, TBLTYPE_TypeRef);
3046 i = ((TBLTypeRef *)q->data)->typeDefId;
3048 tr = &typeDef_names[i];
3050 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, tr->pdu);
3051 p->typename = tr->name;
3053 if (tr->defclass == CLASSREF) {
3055 tr->pdu = pdu; /* remember this reference */
3057 tr = &typeDef_names[i];
3059 g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3060 i, tr->name, tr->pdu);
3062 /* evaluate reference if not done before or when below recursion limit */
3063 if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3066 tr->pdu = pdu; /* save for references we leave */
3068 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3070 g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3072 ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3075 tbl_typeref(n+1, pdu, tr->type, ni);
3079 g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3080 p->name, tr->name, tr->pdu);
3081 p->flags |= PDU_REFERENCE;
3082 p->reference = tr->pdu;
3087 g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3092 g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3093 n*2, empty, p->name, p->typename, p, TBLTYPE(p->type),
3094 tag_class[p->tclass], p->tag);
3096 if (p->value_id == -1) { /* not registered before, do it now */
3097 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3102 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3103 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3104 p->name, p->fullname,
3105 tbl_types_ethereal_txt[p->type], p->value_id);
3107 list = g_node_next_sibling(list);
3112 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
3115 char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3118 tt = TBLTYPE(info->type);
3120 tn = info->typename;
3121 fn = info->fullname;
3122 if (info->flags & PDU_NAMEDNUM)
3123 txt += sprintf(txt, "name: %2d %s", info->tag, nn);
3125 if (info->flags & PDU_TYPEDEF)
3126 txt += sprintf(txt, "def %d: ", info->typenum);
3128 txt += sprintf(txt, " ");
3129 ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3130 txt += sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3131 tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3132 txt += sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
3133 oo = (info->flags & PDU_OPTIONAL) ? ", optional" : empty;
3134 ii = (info->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3135 nn = (info->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3136 an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3137 txt += sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
3138 if (info->flags & PDU_REFERENCE) {
3139 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3140 tt = TBLTYPE(rinfo->type);
3142 tn = rinfo->typename;
3143 fn = rinfo->fullname;
3144 txt += sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3145 if (rinfo->flags & PDU_TYPEDEF)
3146 txt += sprintf(txt, " T%d", rinfo->typenum);
3147 txt += sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3148 oo = (rinfo->flags & PDU_OPTIONAL) ? ", optional" : empty;
3149 ii = (rinfo->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3150 nn = (rinfo->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3151 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3152 tt = (rinfo->flags & PDU_TYPEDEF) ? ", typedef" : empty;
3153 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3154 tr = (rinfo->flags & PDU_TYPETREE) ? ", typetree" : empty;
3155 txt += sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3159 strcpy(txt, "no info available");
3167 showPDUtree(GNode *p, int n)
3173 info = (PDUinfo *)p->data;
3175 PDUtext(text, info);
3177 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3179 showPDUtree(g_node_first_child(p), n+1);
3181 p = g_node_next_sibling(p);
3188 build_pdu_tree(char *pduname)
3191 guint pdudef, i, tcount;
3195 if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3199 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3201 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3202 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, sd.here, pdudef);
3204 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3208 /* initialize the PDU tree, hand craft the root entry */
3210 info = g_malloc0(sizeof(PDUinfo));
3211 info->name = pduname;
3212 info->typename = pduname;
3213 info->type = TBL_SEQUENCEOF;
3214 info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3215 info->flags = PDUinfo_initflags = 0;
3216 info->value_id = -1;
3218 info->basetype = -1;
3219 info->mytype = pdudef;
3221 info->value_hf.p_id = &(info->value_id);
3222 info->value_hf.hfinfo.name = info->fullname;
3223 info->value_hf.hfinfo.abbrev = info->fullname;
3224 info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
3225 info->value_hf.hfinfo.display = BASE_DEC;
3226 info->value_hf.hfinfo.blurb = info->fullname;
3228 anonCount = 0; /* anonymous types counter */
3230 PDUtree = g_node_new(info);
3231 pabbrev_pdu_len = sprintf(fieldname, "%s.%s.", pabbrev, pduname);
3232 sav_len = pabbrev_pdu_len;
3234 /* Now build the tree for this top level PDU */
3236 g_message("******** Define main type %d, %s", pdudef, pduname);
3237 tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1); /* strip initial . for new names */
3240 g_message("%d anonymous types", anonCount);
3242 /* Now make all types used available for matching */
3244 g_message("Define the types that are actually referenced through the top level PDU");
3245 for (i=0, tcount=0; i<numTypedefs; i++) {
3246 TypeRef *tr = &(typeDef_names[i]);
3248 if (tr->pdu) { /* ignore if not used in main pdu */
3251 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3253 g_message("******** Define type %d, %s", i, tr->name);
3255 /* .... do definition ..... */
3256 info = g_malloc0(sizeof(PDUinfo));
3257 info->name = tr->name;
3258 info->typename = tr->name;
3259 info->tclass = tr->defclass;
3260 info->tag = tr->deftag;
3261 info->type = TBL_TYPEREF;
3262 info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3263 info->flags = PDUinfo_initflags = PDU_TYPETREE;
3264 info->value_id = -1;
3266 info->basetype = -1;
3269 info->value_hf.p_id = &(info->value_id);
3270 info->value_hf.hfinfo.name = info->fullname;
3271 info->value_hf.hfinfo.abbrev = info->fullname;
3272 info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
3273 info->value_hf.hfinfo.display = BASE_DEC;
3274 info->value_hf.hfinfo.blurb = info->fullname;
3276 tr->typetree = g_node_new(info);
3277 pabbrev_pdu_len = sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
3278 tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3282 g_message("%d types used", tcount);
3284 pabbrev_pdu_len = sav_len;
3286 /* and show the result */
3288 g_message("Type index:");
3289 for (i=0; i<numTypedefs; i++) {
3290 TypeRef *tr = &(typeDef_names[i]);
3296 if (tr->pdu == 0) /* skip if not used */
3300 g_message(" %3d %s, %c%d, refs: %d",
3301 i, tr->name, tag_class[tr->defclass], tr->deftag,
3302 g_ptr_array_len(tr->refs));
3304 /* get defining node for this type */
3307 p = (PDUinfo *)(tr->typetree->data);
3308 defid = p->value_id;
3310 g_message(" -- defining id=%d", defid);
3312 for(j=0; j < g_ptr_array_len(tr->refs); j++) { /* show refs, and set type_id */
3313 p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3314 if (p->mytype == (gint)i)
3315 p->type_id = defid; /* normal reference */
3317 if ((p->flags & PDU_TYPETREE) == 0) {
3318 /* we have a primitive value, find its real type */
3319 for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3320 /* look at all refs */
3321 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3322 if ((q->flags & PDU_TYPETREE) == 0)
3323 continue; /* only type trees are interresting */
3324 if (q->type != p->type)
3325 continue; /* must be same types */
3326 if (strcmp(q->name, p->name) == 0) {
3327 /* OK, take the first we find, not entirely
3328 * correct, it may be from a different
3329 * base-base type...... XXX */
3330 p->type_id = q->value_id;
3339 g_message(" %s", text);
3345 g_message("The resulting PDU tree:");
3346 showPDUtree(PDUtree, 0);
3352 #ifdef DISSECTOR_WITH_GUI
3353 /* This cannot work in tethereal.... don't include for now */
3354 #if GTK_MAJOR_VERSION >= 2
3355 #define SHOWPDU /* this needs GTK2 */
3357 #endif /* DISSECTOR_WITH_GUI */
3360 static GtkWidget *window = NULL;
3362 /* the columns in the tree view */
3365 TITLE_COLUMN, /* text in this row */
3366 DEF_COLUMN, /* definition in this row, if any */
3367 REF_COLUMN, /* referennce from this column, if any */
3368 VALUE_COLUMN, /* indicate this is a value */
3369 NAME_COLUMN, /* name of this row */
3376 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3379 PDUinfo *info, *rinfo;
3386 info = (PDUinfo *)p->data;
3388 gtk_tree_store_append (store, &iter2, iter); /* Acquire iterator */
3390 PDUtext(text, info);
3393 if (info->flags & PDU_TYPEDEF)
3394 def = info->typenum;
3396 if (info->flags & PDU_REFERENCE) {
3397 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3398 ref = rinfo->typenum;
3400 pb = GTK_STOCK_CANCEL;
3401 if (G_NODE_IS_LEAF(p)) {
3402 if (info->flags & PDU_NAMEDNUM)
3403 pb = GTK_STOCK_BOLD;
3407 fprintf(namelist, "%16s %s\n",
3408 &(TBLTYPE(info->type)[4]), info->fullname);
3411 switch (info->type) {
3412 case TBL_ENUMERATED:
3416 fprintf(namelist, "%16s %s\n",
3417 &(TBLTYPE(info->type)[4]), info->fullname);
3424 gtk_tree_store_set (store, &iter2,
3429 NAME_COLUMN, info->fullname,
3432 build_tree_view(store, g_node_first_child(p), &iter2);
3434 p = g_node_next_sibling(p);
3446 #define PATHSTACKMAX 10
3447 GtkTreePath *pathstack[PATHSTACKMAX];
3448 gint pathstackp = 0;
3450 void add_path(GtkTreePath *p)
3452 if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
3453 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
3454 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
3457 pathstack[pathstackp++] = p;
3460 GtkTreePath *pop_path() {
3462 return pathstack[--pathstackp];
3466 gboolean find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
3470 struct DefFind *df = (struct DefFind *)data;
3472 gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
3474 if (def == df->def) {
3475 df->path = gtk_tree_path_copy (path);
3483 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
3486 GtkTreePath *path, *path2;
3487 gchar *text, *oldpath, *newpath;
3493 path = gtk_tree_path_copy (spath);
3495 gtk_tree_model_get_iter (model, &iter, path);
3496 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
3498 oldpath = gtk_tree_path_to_string(path);
3499 path2 = gtk_tree_path_copy (path);
3501 add_path(gtk_tree_path_copy(path));
3503 if (ref != -1) { /* this is a reference, find matching definition */
3506 gtk_tree_model_foreach (model, find_definition, &df);
3508 gtk_tree_path_free(path);
3511 } else { /* just move to the next entry, if it exists */
3512 gtk_tree_path_next(path2);
3514 if (gtk_tree_model_get_iter (model, &iter, path2)) {
3515 gtk_tree_path_free(path);
3516 path = path2; /* OK */
3518 if (gtk_tree_path_get_depth (path) > 1)
3519 gtk_tree_path_up (path);
3524 gtk_tree_path_free (path2);
3526 gtk_tree_view_expand_to_path (treeview, path);
3527 gtk_tree_view_expand_row (treeview, path, FALSE);
3529 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3531 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3533 newpath = gtk_tree_path_to_string(path);
3536 g_message("my_signal_handler: treeview=%p, moveing from %s to %s",
3537 treeview, oldpath, newpath);
3543 /* gtk_tree_path_free(df.path); */
3548 menuitem_cb (gpointer callback_data,
3549 guint callback_action,
3553 GtkTreeModel *model;
3554 GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
3555 GtkTreeSelection *selection;
3560 gchar *oldpath, *newpath;
3561 GtkTreeViewColumn *focus_column;
3563 selection = gtk_tree_view_get_selection(treeview);
3565 model = gtk_tree_view_get_model(treeview);
3566 gtk_tree_view_get_cursor (treeview, &path, &focus_column);
3568 if (gtk_tree_model_get_iter (model, &iter, path)) {
3570 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
3571 NAME_COLUMN, &name, -1);
3572 oldpath = gtk_tree_path_to_string(path);
3575 switch (callback_action) {
3576 case 0: /* Select */
3577 gtk_tree_selection_select_path (selection, path);
3582 gtk_tree_view_expand_to_path (treeview, path);
3583 gtk_tree_view_expand_row (treeview, path, FALSE);
3585 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3587 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3589 newpath = gtk_tree_path_to_string(path);
3591 gtk_tree_path_free(path);
3593 newpath = g_strdup("** no path **");
3595 g_message("menueitem_cb: treeview=%p, moveing from %s to %s",
3596 treeview, oldpath, newpath);
3600 /* get all non anonymous names to the root */
3603 dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
3604 GTK_DIALOG_DESTROY_WITH_PARENT,
3607 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
3608 gtk_item_factory_path_from_widget (widget),
3609 callback_action, text, oldpath, newpath, name);
3611 /* Close dialog on user response */
3612 g_signal_connect (dialog,
3614 G_CALLBACK (gtk_widget_destroy),
3617 gtk_widget_show (dialog);
3622 if (newpath != empty)
3626 g_message("menuitem_cb: no iterator...");
3629 static GtkItemFactoryEntry menu_items[] = {
3630 { "/Select", NULL, menuitem_cb, 0, NULL, 0 },
3631 { "/Back", "<control>B", menuitem_cb, 1, NULL, 0 },
3632 { "/Find", "<control>F", menuitem_cb, 2, NULL, 0 },
3633 { "/Save", "<control>S", menuitem_cb, 3, NULL, 0 },
3636 static gint button_press_callback( GtkWidget *widget,
3637 GdkEventButton *event,
3640 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
3642 /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
3643 * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
3646 if (event->button == 3) {
3647 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
3654 return FALSE; /* continue handling this event */
3659 create_message_window()
3661 GtkCellRenderer *renderer;
3662 GtkTreeStore *model;
3665 GtkWidget *treeview;
3667 GtkItemFactory *item_factory;
3668 GtkAccelGroup *accel_group;
3669 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3673 /* create window, etc */
3674 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3675 gtk_window_set_title (GTK_WINDOW (window), current_pduname);
3676 g_signal_connect (window, "destroy",
3677 G_CALLBACK (gtk_widget_destroyed), &window);
3679 vbox = gtk_vbox_new (FALSE, 8);
3680 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3681 gtk_container_add (GTK_CONTAINER (window), vbox);
3683 text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
3685 gtk_box_pack_start (GTK_BOX (vbox),
3686 gtk_label_new (text),
3690 sw = scrolled_window_new(NULL, NULL);
3691 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
3693 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3695 model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3696 G_TYPE_STRING, G_TYPE_STRING);
3698 namelist = fopen("namelist.txt", "w");
3699 build_tree_view(model, PDUtree, NULL);
3703 /* create tree view */
3704 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
3705 g_object_unref (model);
3706 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
3707 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
3708 GTK_SELECTION_MULTIPLE);
3710 renderer = gtk_cell_renderer_text_new ();
3712 #if 0 /* testing pango attributes */
3715 PangoAttrList* attr;
3717 attr = pango_attr_list_new();
3718 bg = pango_attr_background_new(50000,55000,50000);
3719 bg->start_index = 0;
3720 bg->end_index = 10000;
3721 pango_attr_list_insert(attr, bg);
3723 g_object_set(renderer, "attributes", attr, NULL);
3725 #endif /* testing pango attributes */
3727 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3728 TITLE_COLUMN, "asn1 entities", renderer,
3729 "text", TITLE_COLUMN, NULL );
3731 /* renderer = gtk_cell_renderer_text_new ();
3732 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3733 * DEF_COLUMN, "type definition", renderer,
3734 * "text", DEF_COLUMN, NULL );
3736 * renderer = gtk_cell_renderer_text_new ();
3737 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3738 * REF_COLUMN, "reference", renderer,
3739 * "text", REF_COLUMN, NULL );
3741 renderer = gtk_cell_renderer_pixbuf_new ();
3742 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3743 VALUE_COLUMN, "value", renderer,
3744 "stock_id", VALUE_COLUMN, NULL );
3746 renderer = gtk_cell_renderer_text_new ();
3747 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3748 NAME_COLUMN, "fieldname", renderer,
3749 "text", NAME_COLUMN, NULL );
3751 gtk_container_add (GTK_CONTAINER (sw), treeview);
3753 /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
3757 accel_group = gtk_accel_group_new ();
3759 /* This function initializes the item factory.
3760 * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
3761 * or GTK_TYPE_OPTION_MENU.
3762 * Param 2: The path of the menu.
3763 * Param 3: A pointer to a gtk_accel_group. The item factory sets up
3764 * the accelerator table while generating menus.
3767 item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
3769 /* This function generates the menu items. Pass the item factory,
3770 the number of items in the array, the array itself, and any
3771 callback data for the the menu items. */
3772 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
3774 /* Attach the new accelerator group to the window. */
3775 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
3778 /* expand all rows after the treeview widget has been realized */
3779 g_signal_connect (treeview, "realize",
3780 G_CALLBACK (gtk_tree_view_expand_all), NULL);
3781 g_signal_connect (treeview, "row-activated",
3782 G_CALLBACK (my_signal_handler), (gpointer)model);
3784 g_signal_connect (treeview, "button_press_event",
3785 G_CALLBACK (button_press_callback), item_factory);
3787 /* g_signal_connect_swapped (treeview, "event",
3788 * G_CALLBACK (button_press_handler),
3791 gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
3794 if (!GTK_WIDGET_VISIBLE (window))
3795 gtk_widget_show_all (window);
3798 gtk_widget_destroy (window);
3802 #endif /* SHOWPDU */
3804 /************************************************************************************************
3805 * routines to find names to go with the decoded data stream *
3806 ************************************************************************************************/
3807 typedef struct _statestack statestack;
3808 struct _statestack {
3816 #define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
3817 #define STORENODE(x) { PDUstate[PDUstatec-1] = (x); }
3818 #define POPSTATE PDUstate[--PDUstatec]
3819 #define GETSTATE PDUstate[PDUstatec-1]
3820 #define GETNAME (((PDUinfo *)pos.node->data)->name)
3821 #define TYPENAME (((PDUinfo *)pos.node->data)->typename)
3822 #define GETTYPE (((PDUinfo *)pos.node->data)->type & TBL_TYPEmask)
3823 #define GETFLAGS (((PDUinfo *)pos.node->data)->flags)
3824 #define GETINFO ((PDUinfo *)pos.node->data)
3825 #define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
3826 #define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
3827 #define MATCH ((class == info->tclass) && (tag == info->tag))
3828 #define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
3829 #define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
3830 #define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
3831 #define ISCHOICE (info && (info->flags & PDU_CHOICE))
3832 #define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
3835 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
3836 pos.node=0;PUSHNODE(pos);return ret;}}
3840 showstack(statestack *pos, char *txt, int n)
3842 char buf[1024], *name, *type, *stype;
3843 char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
3849 if ( ! asn1_verbose)
3855 g_message("==underflow");
3858 rep = chs = done = ref = pop = chr = rch = sch = con = empty;
3862 name = ((PDUinfo *)g->data)->name;
3863 type = TBLTYPE(((PDUinfo *)g->data)->type);
3865 name = "node<null>";
3869 stype = TBLTYPE(typef);
3870 if (typef & TBL_REPEAT) rep = "[repeat]";
3871 if (typef & TBL_CHOICE_made) chs = "[choice]";
3872 if (typef & TBL_SEQUENCE_done) done = "[done]";
3873 if (typef & TBL_REFERENCE) ref = "[ref]";
3874 if (typef & TBL_REFERENCE_pop) pop = "[ref-pop]";
3875 if (typef & TBL_CHOICE_repeat) chr = "[chs-rep]";
3876 if (typef & TBL_REPEAT_choice) rch = "[rep-chs]";
3877 if (typef & TBL_SEQUENCE_choice)sch = "[seq-chs]";
3878 if (typef & TBL_CONSTRUCTED) con = "[constr]";
3880 i = sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
3881 pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
3882 pos->name, pos->offset);
3884 for(j=1, n--; n>0; j++, n--) {
3885 p = &PDUstate[PDUstatec-j];
3887 stype = TBLTYPE(typef);
3888 rep = (typef & TBL_REPEAT) ? "[repeat]" : empty;
3889 chs = (typef & TBL_CHOICE_made) ? "[choice]" : empty;
3890 done = (typef & TBL_SEQUENCE_done) ? "[done]" : empty;
3891 ref = (typef & TBL_REFERENCE) ? "[ref]" : empty;
3892 pop = (typef & TBL_REFERENCE_pop) ? "[ref-pop]" : empty;
3893 chr = (typef & TBL_CHOICE_repeat) ? "[chs-rep]" : empty;
3894 rch = (typef & TBL_REPEAT_choice) ? "[rep-chs]" : empty;
3895 sch = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
3896 con = (typef & TBL_CONSTRUCTED) ? "[constr]" : empty;
3898 i += sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
3899 p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
3900 p->name, p->offset);
3906 showrefNode(GNode *node, int n)
3908 char *name = empty, *type = empty, *tname = empty;
3909 int cls = 0, tag = 0;
3914 g_message("%*sstop, nesting too deep", 2*n, empty);
3918 info = (PDUinfo *)(node->data);
3919 type = TBLTYPE(info->type);
3921 tname = info->typename;
3922 ref = info->reference;
3926 g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
3927 2*n, empty, tname, type, name, node, node->data,
3928 ref, tag_class[cls], tag);
3931 showrefNode(ref, n+1);
3935 showNode(GNode *node, int n, int m)
3937 char *name = empty, *type = empty;
3944 type = TBLTYPE(((PDUinfo *)(node->data))->type);
3945 name = ((PDUinfo *)(node->data))->name;
3946 ref = ((PDUinfo *)(node->data))->reference;
3948 g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
3949 2*n, empty, type, name, node, node->data, node->next, node->prev,
3950 node->parent, node->children);
3953 g_message("%*sstop, nesting too deep", 2*n, empty);
3957 if (ref) showrefNode(ref, n+2);
3959 if (node->children) showNode(node->children, n+1, m);
3960 if (node->next) showNode(node->next, n, m);
3964 PDUreset(int count, int count2)
3968 if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
3970 PDUstatec = 0; /* stackpointer */
3971 PDUerrcount = 0; /* error counter per asn.1 message */
3973 pos.node = 0; /* sentinel */
3974 pos.name = "sentinel";
3975 pos.type = TBL_SEQUENCEOF;
3980 pos.node = PDUtree; /* root of the tree */
3981 pos.name = GETNAME;;
3982 pos.type = GETTYPE | TBL_REPEAT;
3988 GNode * /* find GNode for a choice element, 0 if none */
3989 makechoice(GNode *p, guint class, guint tag)
3994 p = g_node_first_child(p); /* the list of choices */
3995 info = 0; /* avoid gcc warning */
3998 info = ((PDUinfo *)p->data);
4000 if (info->type == TBL_CHOICE) {
4002 g_message(" using sub choice (%s)%s", info->typename, info->name);
4004 q = makechoice(p, class, tag);
4005 if (q) { /* found it */
4007 info = ((PDUinfo *)p->data);
4009 } /* continue with this level */
4013 g_message(" have %c%d, found %c%d, %s", tag_class[class], tag,
4014 tag_class[info->tclass], info->tag, info->name);
4016 if ((class == info->tclass) && (tag == info->tag))
4017 break; /* found it */
4020 p = g_node_next_sibling(p);
4023 if (p) g_message(" OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
4025 else g_message(" ...no matching choice...");
4030 /* offset is for debugging only, a reference to output on screen */
4032 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
4034 statestack pos, pos2, save_pos;
4037 int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4038 static char namestr[64]; /* enough ? */
4039 static char posstr[40];
4040 static char noname[] = "*noname*";
4041 static PDUprops constructed_save; /* for unexpectedly constructed enteties */
4043 if (PDUstatec > 0) /* don't read from below the stack */
4045 /* pos refers to the last asn1 node handled */
4047 /* a very simple, too simple??, way to handle constructed entities */
4048 if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4049 /* unexpectedly constructed, return same info as last time */
4050 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4051 showstack(&pos, posstr, 3);
4052 pos.offset = offset;
4053 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4054 PUSHNODE(pos); /* push extra, to match with a EOI operation */
4055 PUSHNODE(pos); /* restore the stack */
4056 *out = constructed_save;
4058 g_message(" return for constructed %s (%s)%s",
4059 TBLTYPE(out->type), out->typename, out->name);
4063 save_pos = pos; /* may need it again */
4067 out->typename = "*error*";
4074 if (PDUstatec <= 0) {
4075 if (PDUstatec > -10) {
4077 g_message(">>off=%d stack underflow, return", offset);
4079 if (PDUstatec == -10) {
4081 g_message(">>off=%d stack underflow, return, no more messages", offset);
4083 out->name = "*underflow*";
4084 out->flags |= OUT_FLAG_noname;
4088 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4090 showstack(&pos, posstr, 3);
4094 if (class == ASN1_EOI) { /* end of this input sequence */
4096 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4097 if (asn1_verbose) g_message(" EOI: reference pop");
4100 switch(pos.type & TBL_TYPEmask) {
4102 if (asn1_verbose) g_message(" EOI: pop typeref");
4103 pos = POPSTATE; /* remove typeref */
4105 case TBL_CHOICE_done:
4106 if (asn1_verbose) g_message(" EOI: mark choice");
4108 pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4116 pos = POPSTATE; /* this is pushed back on the stack later */
4117 if (pos.node == 0) {
4118 if (asn1_verbose) g_message(" EOI, pos.node == 0");
4119 out->name = "*no-name-EOI*";
4120 out->flags |= OUT_FLAG_noname;
4127 tmp = TBLTYPE(info->type);
4128 if (offset != pos.offset) {
4130 g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4131 tmp, ret, offset, pos.offset);
4132 while ((offset < pos.offset) && (PDUstatec > 0)) {
4135 g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
4136 offset, pos.offset);
4138 if (offset != pos.offset)
4139 PDUerrcount++; /* only count if still unequal */
4141 if (asn1_verbose) g_message(" EOI %s:%s OK, offset=%d", tmp, ret, offset);
4144 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4145 * indicated by the synthetic EOI call. */
4146 if ((class == ASN1_UNI) && (tag == ASN1_EOC)) { /* explicit EOC never has a name */
4147 PUSHNODE(pos); /* restore stack */
4148 ret = "explicit-EOC";
4149 if (asn1_verbose) g_message(" return '%s', ignore", ret);
4151 out->typename = "ASN1";
4155 /* find appropriate node for this tag */
4157 if (pos.node == 0) {
4158 if (asn1_verbose) g_message(" pos.node == 0");
4159 out->name = "*no-name*";
4160 out->flags |= OUT_FLAG_noname;
4165 /* showNode(pos.node, 3, 4); */
4167 switch (pos.type & TBL_TYPEmask) {
4168 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4172 if (pos.type & TBL_CHOICE_made) {
4173 if (asn1_verbose) g_message(" finish choice");
4181 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4182 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4184 if (asn1_verbose) g_message(" repeating choice"); /* ignore repeat */
4187 if (asn1_verbose) g_message(" seqof: repeat start");
4188 /* decide how to continue, CHILD for next instance of sequence
4189 * or NEXT for end of repeated sequence.
4190 * use the tag to make a descision */
4191 if (asn1_verbose) g_message(" seqof: first got %c%d, found %c%d",
4192 tag_class[class], tag,
4193 tag_class[info->tclass], info->tag);
4195 /* This is the start of repeating */
4198 if (asn1_verbose) g_message(" return for repeat '%s'", ret);
4199 out->type = (pos.type & TBL_TYPEmask);
4200 out->typename = info->typename;
4202 out->value_id = info->value_id;
4203 out->type_id = info->type_id;
4205 if (asn1_verbose) g_message(" anonymous: dontshow");
4207 out->flags |= OUT_FLAG_dontshow;
4213 /* find out where to go .... */
4215 CHILD; /* assume sequence is repeated */
4217 info = GETINFO; /* needed for MATCH to look ahead */
4219 g_message(" seqof: child: got %c%d, found %c%d",
4220 tag_class[class], tag,
4221 tag_class[info->tclass], info->tag);
4223 if (pos2.type & TBL_CHOICE_repeat) {
4226 g_message(" repeating a choice, %s",
4228 pos.type = TBL_CHOICE_immediate;
4230 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4231 donext = 1; /* move on */
4233 g_message(" seqof: no repeat, force next");
4235 /* following code will take the child again */
4241 } else if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4242 if (asn1_verbose) g_message(" reference pop, donext");
4245 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4246 if (pos.type & TBL_SEQUENCE_choice) {
4247 pos = POPSTATE; /* expect to find a repeat here */
4250 if (asn1_verbose) g_message(" sequence done, donext");
4254 if (pos.type & TBL_REFERENCE) {
4255 if (asn1_verbose) g_message(" reference change ref -> pop");
4256 pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4259 pos.offset = offset;
4261 ret = pos.name; /* for the debug messages */
4264 if (asn1_verbose) g_message(" donext");
4267 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4268 case TBL_SETOF: /* ?? */
4269 case TBL_SEQUENCEOF:
4270 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4271 pos.type |= TBL_REPEAT;
4275 /* remember this is the start of a repeat cycle */
4276 typeflags |= TBL_REPEAT;
4278 g_message(" seqof: set repeat mark [push,child]");
4281 g_message(" seqof: end of reapeat loop [next]");
4285 case TBL_SET: /* ?? */
4287 pos.type |= TBL_SEQUENCE_done;
4291 if (asn1_verbose) g_message(" seq [push,child]");
4294 /* no more choice */
4295 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4298 pos.type = 0; /* clear all type flags */
4300 g_message(" choice [push], %c%d, %s",
4301 tag_class[info->tclass], info->tag, GETNAME);
4302 pos.node = makechoice(pos.node, class, tag);
4303 if (pos.node == 0) {
4305 out->flags |= OUT_FLAG_noname;
4312 g_message(" '%s' %c%d will be used",
4313 ret, tag_class[info->tclass], info->tag);
4315 case TBL_CHOICE_done:
4321 if (asn1_verbose) g_message(" typeref [pop,next]");
4323 case TBL_ENUMERATED:
4325 /* skip named numbers now, call to PDUenum() will retrieve a name */
4328 case TBL_CHOICE_immediate:
4329 if (asn1_verbose) g_message(" immediate choice [no next]");
4338 if (pos.node == 0) {
4339 ret = "*no-name-2*";
4340 if (asn1_verbose) g_message(" return '%s'", ret);
4342 out->flags |= OUT_FLAG_noname;
4346 ret = pos.name = GETNAME;
4347 pos.type = GETTYPE | (pos.type & ~TBL_TYPEmask);
4350 /* pos now points to the prospective current node, go check it ********************/
4351 if (asn1_verbose) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4352 (ISOPTIONAL)?", optional":empty,
4353 (ISIMPLICIT)?", implicit":empty,
4354 tag_class[info->tclass], info->tag );
4356 if (ISOPTIONAL) { /* must check the tag */
4357 while(! MATCH) { /* check optional here again...? */
4359 g_message(" got %c%d, found %c%d", tag_class[class], tag,
4360 tag_class[info->tclass], info->tag);
4362 if (pos.node == 0) {
4365 pos = save_pos; /* reset for next time */
4366 pos.type |= TBL_SEQUENCE_done;
4368 pos.type &= ~TBL_SEQUENCE_done;
4370 out->flags |= OUT_FLAG_dontshow;
4372 g_message(" end of optional list, constructed, expect value next time");
4375 out->flags |= OUT_FLAG_noname;
4377 g_message(" *end of optional list...");
4378 info = 0; /* this is not valid any more... */
4380 break; /* end of list */
4383 if (asn1_verbose) g_message(" optional, %s", GETNAME);
4385 if (pos.node && ! cons_handled) {
4386 ret = pos.name = GETNAME;
4389 /* pos now refers to node with name we want, optional nodes skipped */
4392 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4393 pos2 = pos; /* save current state */
4397 g_message(" already pushed, skip next push");
4399 typeflags &= ~TBL_CHOICE_made;
4403 g_message(" immediate choice [push], %c%d, %s",
4404 tag_class[info->tclass], info->tag, GETNAME);
4405 pos.node = makechoice(pos.node, class, tag);
4406 if (pos.node == 0) {
4412 out->type = (pos.type & TBL_TYPEmask);
4413 out->flags |= OUT_FLAG_type;
4415 sprintf(namestr, "%s!%s", ret, GETNAME);
4418 g_message(" %s:%s will be used", TBLTYPE(pos.type), ret);
4419 if (typeflags & TBL_REPEAT) {
4420 pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
4422 pos.type |= TBL_SEQUENCE_choice;
4425 g_message(" return from immediate choice [%s] '%s'",
4426 TBLTYPE(pos.type), ret);
4428 out->data = pos.node; /* for access to named numbers... */
4430 out->type = (pos.type & TBL_TYPEmask);
4433 out->typename = info->typename;
4434 out->fullname = info->fullname;
4435 out->value_id = info->value_id;
4436 out->type_id = info->type_id;
4441 typeflags |= TBL_CHOICE_made;
4444 if (asn1_verbose) g_message(" matching choice '%s'", ret);
4446 if ( ! cons ) { /* ISIMPLICIT was not OK for all */
4447 pos = pos2; /* reset for continuation */
4452 g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4453 (ISOPTIONAL)?", optional":empty,
4454 (ISIMPLICIT)?", implicit":empty,
4455 tag_class[info->tclass], info->tag );
4457 g_message(" using: unknown '%s'", ret);
4460 /* must follow references now */
4461 if (pos.type == TBL_TYPEREF) {
4462 out->typename = info->typename;
4463 out->type_id = info->typenum;
4464 out->flags |= OUT_FLAG_typename;
4466 PUSHNODE(pos); /* remember where we were */
4467 if (asn1_verbose) g_message(" typeref [push]");
4468 typeflags |= TBL_REFERENCE;
4469 if (info->reference == 0) { /* resolved ref to universal type.... */
4470 /* showNode(pos.node, 3, 4); */
4471 pos.type = GETTYPE; /* the resulting type */
4473 tmp = "inknown tag";
4474 if ((info->tclass == ASN1_UNI) && (info->tag < 31)) {
4475 tmp = asn1_tag[info->tag];
4476 pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
4479 g_message(" indirect typeref to %s:%s, %s [%c%d]",
4480 TBLTYPE(pos.type), info->typename, tmp,
4481 tag_class[info->tclass], info->tag );
4483 out->fullname = info->fullname;
4484 donext = (ISANONYMOUS); /* refereing entity has no name ? */
4485 pos.node = info->reference;
4489 g_message(" typeref %s %s", TBLTYPE(pos.type), GETNAME);
4490 /* keep name from before going through the reference, unless anonymous */
4491 if (donext) /* refering entity has no name */
4492 ret = GETNAME; /* a better name */
4494 /* handle choice here ? !!mm!! */
4496 out->type = (pos.type & TBL_TYPEmask);
4497 out->flags |= OUT_FLAG_type;
4498 /* showNode(pos.node, 3, 4); */
4501 out->data = pos.node;
4502 out->flags |= OUT_FLAG_data;
4504 g_message(" typeref set named number list node %p", pos.node);
4508 pos.type = TBL_TYPEREF_nopop;
4509 if (asn1_verbose) g_message(" typeref pop");
4510 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
4511 /* do not enter the named-number list */
4513 pos.type = TBL_TYPEREF_nopop;
4514 if (asn1_verbose) g_message(" typeref [pop]");
4516 typeflags |= TBL_REFERENCE;
4521 if (cons && ! cons_handled) { /* This entity is constructed, expected ? */
4523 case TBL_BOOLEAN: /* these are not expected to be constructed */
4525 case TBL_OCTETSTRING:
4529 case TBL_ENUMERATED:
4531 typeflags |= TBL_CONSTRUCTED;
4532 /* this entry has no extra info, next is the same */
4533 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
4534 if (asn1_verbose) g_message(" dontshow and set constructed flag");
4536 default: /* others, such as sequences, are expected to be constructed */
4543 if (asn1_verbose) g_message(" anonymous: dontshow");
4544 if (asn1_debug) /* this entry has no extra info, next is the same */
4545 out->flags |= OUT_FLAG_dontshow;
4547 out->name = empty; /* show it, but no name */
4550 if (out->name != empty)
4553 if ( ! (out->flags & OUT_FLAG_data))
4554 out->data = pos.node; /* for access to named numbers... */
4556 pos.type |= typeflags;
4559 if ( ! (out->flags & OUT_FLAG_type))
4560 out->type = pos.type;
4562 out->type &= TBL_TYPEmask;
4564 if (ret == noname) {
4566 out->flags |= OUT_FLAG_noname;
4569 if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
4570 out->typename = info->typename;
4571 out->type_id = info->typenum;
4574 if (info && (out->value_id == -1)) {
4575 out->value_id = info->value_id;
4576 out->type_id = info->type_id;
4579 if ((out->fullname == 0) && info)
4580 out->fullname = info->fullname;
4582 if (typeflags & TBL_CONSTRUCTED)
4583 constructed_save = *out;
4586 g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
4587 out->value_id, out->type_id);
4593 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
4598 static char unnamed[] = "*unnamed*";
4600 (void) cls; (void) tag; /* make a reference */
4602 if (props->flags & OUT_FLAG_noname)
4606 list = (GNode *)props->data;
4609 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
4611 return "*list-still-0*";
4614 if ((PDUinfo *)list->data)
4615 name = ((PDUinfo *)list->data)->name;
4619 for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
4620 info = (PDUinfo *)list->data;
4621 if (value == info->tag) {
4630 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
4634 #endif /* READSYNTAX */
4637 proto_register_asn1(void) {
4639 static const enum_val_t type_recursion_opts[] = {
4653 static gint *ett[1+MAX_NEST+MAXPDU];
4655 module_t *asn1_module;
4658 asn1_logfile = get_tempfile_path(ASN1LOGFILE);
4660 current_pduname = g_strdup("ASN1");
4661 asn1_pduname = g_strdup(current_pduname);
4663 proto_asn1 = proto_register_protocol("ASN.1 decoding",
4667 for (i=0, j=1; i<MAX_NEST; i++, j++) {
4668 ett[j] = &ett_seq[i];
4671 for(i=0; i<MAXPDU; i++, j++) {
4672 ett[j] = &ett_pdu[i];
4676 proto_register_subtree_array(ett, array_length(ett));
4678 asn1_module = prefs_register_protocol(proto_asn1,
4679 proto_reg_handoff_asn1);
4680 prefs_register_uint_preference(asn1_module, "tcp_port",
4682 "The TCP port on which "
4683 "ASN.1 packets will be read",
4684 10, &global_tcp_port_asn1);
4685 prefs_register_uint_preference(asn1_module, "udp_port",
4687 "The UDP port on which "
4688 "ASN.1 packets will be read",
4689 10, &global_udp_port_asn1);
4690 prefs_register_bool_preference(asn1_module, "desegment_messages",
4692 "Desegment ASN.1 messages that span TCP segments",
4695 old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
4697 bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
4700 prefs_register_string_preference(asn1_module, "file",
4701 "ASN.1 type table file",
4702 "Compiled ASN.1 description of ASN.1 types",
4704 prefs_register_string_preference(asn1_module, "pdu_name",
4706 "Name of top level PDU",
4708 prefs_register_uint_preference(asn1_module, "first_pdu_offset",
4709 "Offset to first PDU in first tcp packet",
4710 "Offset for non-reassembled packets, "
4711 "wrong if this happens on other than the first packet!",
4712 10, &first_pdu_offset);
4713 prefs_register_bool_preference(asn1_module, "flat",
4715 "Show full names for all values",
4717 prefs_register_enum_preference(asn1_module, "type_recursion",
4718 "Eliminate references to level",
4719 "Allow this recursion level for eliminated type references",
4720 &type_recursion_level,
4721 type_recursion_opts, FALSE);
4722 prefs_register_bool_preference(asn1_module, "debug",
4724 "Extra output useful for debuging",
4727 prefs_register_bool_preference(asn1_module, "message_win",
4729 "show full message description",
4731 prefs_register_bool_preference(asn1_module, "verbose_log",
4732 "Write very verbose log",
4733 "log to file $TMP/" ASN1LOGFILE,
4737 /* The registration hand-off routing */
4740 proto_reg_handoff_asn1(void) {
4741 static int asn1_initialized = FALSE;
4742 static dissector_handle_t asn1_handle;
4746 if (asn1_verbose) g_message("prefs change: tcpport=%d, udpport=%d, desegnment=%d, asn1file=%s, "
4747 "pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
4748 global_tcp_port_asn1, global_udp_port_asn1, asn1_desegment, asn1_filename,
4749 asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
4751 if(!asn1_initialized) {
4752 asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
4753 asn1_initialized = TRUE;
4755 dissector_delete("tcp.port", tcp_port_asn1, asn1_handle);
4756 dissector_delete("udp.port", udp_port_asn1, asn1_handle);
4759 tcp_port_asn1 = global_tcp_port_asn1;
4760 udp_port_asn1 = global_udp_port_asn1;
4762 dissector_add("tcp.port", global_tcp_port_asn1, asn1_handle);
4763 dissector_add("udp.port", global_udp_port_asn1, asn1_handle);
4765 if ( g_strcmp(asn1_filename, current_asn1) != 0) { /* new defintions, parse it */
4766 /* !!! should be postponed until we really need it !!! */
4768 read_asn1_type_table(asn1_filename);
4769 #endif /* READSYNTAX */
4770 g_free(current_asn1);
4771 current_asn1 = g_strdup(asn1_filename);
4773 if (g_strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
4774 if (build_pdu_tree(asn1_pduname)) {
4775 g_free(current_pduname);
4776 current_pduname = g_strdup(asn1_pduname);
4780 if (asn1_message_win) { /* show what we are prepared to recognize */
4782 gtk_widget_destroy (window);
4785 create_message_window();
4787 #endif /* SHOWPDU */
4790 /* Start the functions we need for the plugin stuff */
4792 #ifndef ENABLE_STATIC
4794 G_MODULE_EXPORT void
4795 plugin_reg_handoff(void){
4796 proto_reg_handoff_asn1();
4799 G_MODULE_EXPORT void
4800 plugin_init(plugin_address_table_t *pat
4801 #ifndef PLUGINS_NEED_ADDRESS_TABLE
4806 /* initialise the table of pointers needed in Win32 DLLs */
4807 plugin_address_table_init(pat);
4808 /* register the new protocol, protocol fields, and subtrees */
4809 if (proto_asn1 == -1) { /* execute protocol initialization only once */
4810 proto_register_asn1();
4816 /* End the functions we need for plugin stuff */