1 /******************************************************************************************************/
4 * Copyright (c) 2003 by Matthijs Melchior <matthijs.melchior@xs4all.nl>
10 * Ethereal - Network traffic analyzer
11 * By Gerald Combs <gerald@ethereal.com>
12 * Copyright 1999 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 /**************************************************************************
31 * This plugin will dissect BER encoded ASN.1 messages in UDP packets or in
32 * a TCP stream. It relies on ethereal to do defragmentation and re-assembly
33 * to construct complete messages.
35 * To produce packet display with good annotations it needs to know about
36 * the ASN.1 definition of the messages it reads. To this end, it can read
37 * the 'type-table' output file of the ASN.1 to C compiler 'snacc'. The
38 * version I have used came from: http://packages.debian.org/testing/devel/snacc.html
40 * The type-table files produced by snacc are themselves ASN.1 BER encoded
41 * data structures. Knowledge of the structure of that table, as specified
42 * in the tbl.asn1 file in the snacc distribution, is hand coded in some
43 * functions in this plugin.
45 * This also means that this dissector can show its own specification.
46 * On a unix machine, do the following to see this in action:
48 * - snacc -u /usr/include/snacc/asn1/asn-useful.asn1 -T tbl.tt /usr/include/snacc/asn1/tbl.asn1
49 * - od -Ax -tx1 tbl.tt | text2pcap -T 801,801 - tbl.tt.pcap
50 * - ethereal tbl.tt.pcap
51 * GUI: Edit->Preferences->Protocols->ASN1
52 * type table file: /tmp/tbl.tt
55 * you can now browse the tbl.tt definition.
66 #include <sys/types.h>
70 #include "moduleinfo.h"
78 #include <epan/packet.h>
79 #include <epan/addr_resolv.h>
80 #include <epan/prefs.h>
81 #include <epan/strutil.h>
82 #include <epan/filesystem.h>
83 #include <epan/report_err.h>
84 #include <epan/dissectors/packet-tcp.h>
85 #include <epan/asn1.h>
86 #include "file_util.h"
88 #ifdef DISSECTOR_WITH_GUI
92 #include <epan/ipproto.h>
94 /* Define version if we are not building ethereal statically */
97 G_MODULE_EXPORT const gchar version[] = VERSION;
105 /* Define default ports */
107 #define TCP_PORT_ASN1 801
108 #define UDP_PORT_ASN1 801
109 #define SCTP_PORT_ASN1 801
111 void proto_reg_handoff_asn1(void);
113 /* Define the asn1 proto */
115 static int proto_asn1 = -1;
117 /* Define the tree for asn1*/
119 static int ett_asn1 = -1;
121 #define MAXPDU 64 /* max # PDU's in one packet */
122 static int ett_pdu[MAXPDU];
124 #define MAX_NEST 32 /* max nesting level for ASN.1 elements */
125 static int ett_seq[MAX_NEST];
128 * Global variables associated with the preferences for asn1
132 static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
133 static guint global_udp_port_asn1 = UDP_PORT_ASN1;
134 static guint global_sctp_port_asn1 = SCTP_PORT_ASN1;
135 static guint tcp_port_asn1 = TCP_PORT_ASN1;
136 static guint udp_port_asn1 = UDP_PORT_ASN1;
137 static guint sctp_port_asn1 = SCTP_PORT_ASN1;
139 static range_t *global_tcp_ports_asn1;
140 static range_t *global_udp_ports_asn1;
141 static range_t *global_sctp_ports_asn1;
143 static range_t *tcp_ports_asn1;
144 static range_t *udp_ports_asn1;
145 static range_t *sctp_ports_asn1;
146 #endif /* JUST_ONE_PORT */
148 static gboolean asn1_desegment = TRUE;
149 static const char *asn1_filename = NULL;
150 static char *old_default_asn1_filename = NULL;
151 #define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
153 #define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
154 static char *bad_separator_old_default_asn1_filename = NULL;
156 static char *current_asn1 = NULL;
157 static const char *asn1_pduname = NULL;
158 static char *current_pduname = NULL;
159 static gboolean asn1_debug = FALSE;
160 static guint first_pdu_offset = 0;
161 static gboolean asn1_message_win = FALSE;
162 static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
163 static gboolean asn1_full = FALSE; /* show full names */
164 static guint type_recursion_level = 1; /* eliminate 1 level of references */
165 static char *asn1_logfile = NULL;
167 #define ASN1LOGFILE "ethereal.log"
169 /* PDU counter, for correlation between GUI display and log file in debug mode */
170 static int pcount = 0;
172 static tvbuff_t *asn1_desc; /* the PDU description */
173 static GNode *asn1_nodes = 0; /* GNode tree pointing to every asn1 data element */
174 static GNode *data_nodes = 0; /* GNode tree describing the syntax data */
175 static GNode *PDUtree = 0; /* GNode tree describing the expected PDU format */
177 static guint PDUerrcount = 0; /* count of parse errors in one ASN.1 message */
179 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
182 static char pabbrev[] = "asn1"; /* field prefix */
184 static char fieldname[512]; /* for constructing full names */
185 static guint pabbrev_pdu_len; /* length initial part of fieldname with 'abbrev.asn1pdu.' */
188 * Text strings describing the standard, universal, ASN.1 names.
191 #define ASN1_EOI 4 /* this is in the class number space... */
192 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
194 static const char tag_class[] = "UACPX";
196 static const char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
198 static const char *asn1_con[] = { "Primitive", "Constructed" };
200 static const char *asn1_tag[] = {
201 /* 0 */ "EOC", "Boolean", "Integer", "BitString",
202 /* 4 */ "OctetString", "Null", "ObjectIdentifier", "ObjectDescriptor",
203 /* 8 */ "External", "Real", "Enumerated", "tag11",
204 /* 12 */ "UTF8String", "tag13", "tag14", "tag15",
205 /* 16 */ "Sequence", "Set", "NumericString", "PrintableString",
206 /* 20 */ "TeletexString", "VideotexString", "IA5String", "UTCTime",
207 /* 24 */ "GeneralTime", "GraphicString", "ISO646String", "GeneralString",
208 /* 28 */ "UniversalString", "tag29", "BMPString", "Long tag prefix"
209 /* TT61 == TELETEX */
210 /* ISO646 == VISIBLE*/
213 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
214 static gboolean tbl_types_verified = FALSE;
216 typedef enum { /* copied from .../snacc/c-lib/boot/tbl.h */
225 TBL__SIMPLE = 8, /* values smaller than this can have a value */
233 TBL_SEQUENCEOF_start, /* to mark potential sequence-of repeat */
234 TBL_TYPEREF_nopop, /* typeref has been handled immediately */
235 TBL_CHOICE_done, /* choice is finished */
236 TBL_reserved, /* this sequence has been visited */
237 TBL_CHOICE_immediate, /* immediate choice, no next */
239 TBL_INVALID /* incorrect value for this enum */
242 /* Universal tags mapped to snacc ASN.1 table types */
243 static int asn1_uni_type[] = {
244 /* 0 */ TBL_INVALID, TBL_BOOLEAN, TBL_INTEGER, TBL_BITSTRING,
245 /* 4 */ TBL_OCTETSTRING, TBL_NULL, TBL_OID, TBL_INVALID,
246 /* 8 */ TBL_INVALID, TBL_REAL, TBL_ENUMERATED, TBL_INVALID,
247 /* 12 */ TBL_OCTETSTRING, TBL_INVALID, TBL_INVALID, TBL_INVALID,
248 /* 16 */ TBL_SEQUENCE, TBL_SET, TBL_OCTETSTRING, TBL_OCTETSTRING,
249 /* 20 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
250 /* 24 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
251 /* 28 */ TBL_OCTETSTRING, TBL_INVALID, TBL_OCTETSTRING, TBL_INVALID,
255 #define TBL_REPEAT 0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
256 #define TBL_REPEAT_choice 0x00020000 /* repeating a choice */
257 #define TBL_CHOICE_made 0x00040000 /* This was a choice entry */
258 #define TBL_SEQUENCE_done 0x00080000 /* children have been processed */
259 #define TBL_CHOICE_repeat 0x00100000 /* a repeating choice */
260 #define TBL_REFERENCE 0x00200000 /* This entry is result of a typeref */
261 #define TBL_REFERENCE_pop 0x00400000 /* reference handled, do pop i.s.o. next */
262 #define TBL_SEQUENCE_choice 0x00800000 /* this sequence is a first of a repeating choice */
263 #define TBL_CONSTRUCTED 0x01000000 /* unexpectedly constructed entry */
264 #define TBL_TYPEmask 0x0000FFFF /* Mask just the type */
267 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
269 /* text tables for debugging and GUI */
270 static const char *tbl_types[] = {
271 /* 0 */ "tbl-boolean",
272 /* 1 */ "tbl-integer",
273 /* 2 */ "tbl-bitstring",
274 /* 2 */ "tbl-octetstring",
278 /* 7 */ "tbl-enumerated",
279 /* 8 */ "tbl-sequence",
281 /* 10 */ "tbl-sequenceof",
282 /* 11 */ "tbl-setof",
283 /* 12 */ "tbl-choice",
284 /* 13 */ "tbl-typeref",
286 /* 14 */ "tbl-sequenceof-start",
287 /* 15 */ "tbl-typeref-nopop",
288 /* 16 */ "tbl-choice-done",
289 /* 17 */ "tbl-reserved",
290 /* 18 */ "tbl-choice-immediate",
292 /* 19 */ "tbl-invalid",
294 static const char *tbl_types_asn1[] = {
298 /* 2 */ "OCTET STRING",
300 /* 5 */ "OBJECT IDENTIFIER",
302 /* 7 */ "ENUMERATED",
305 /* 10 */ "SEQUENCE OF",
310 /* 14 */ "start-SEQUENCE OF",
311 /* 15 */ "TYPEREF nopop",
312 /* 16 */ "CHOICE done",
314 /* 18 */ "CHOICE immediate",
316 /* 19 */ "INVALID entry",
318 /* conversion from snacc type to appropriate ethereal type */
319 static guint tbl_types_ethereal[] = {
320 /* 0 */ FT_BOOLEAN, /* TBL_BOOLEAN */
321 /* 1 */ FT_UINT32, /* TBL_INTEGER */
322 /* 2 */ FT_UINT32, /* TBL_BITSTRING */
323 /* 2 */ FT_STRINGZ, /* TBL_OCTETSTRING */
324 /* 4 */ FT_NONE, /* TBL_NULL */
325 /* 5 */ FT_BYTES, /* TBL_OID */
326 /* 6 */ FT_DOUBLE, /* TBL_REAL */
327 /* 7 */ FT_UINT32, /* TBL_ENUMERATED */
328 /* 8 */ FT_NONE, /* TBL_SEQUENCE */
329 /* 9 */ FT_NONE, /* TBL_SET */
330 /* 10 */ FT_NONE, /* TBL_SEQUENCEOF */
331 /* 11 */ FT_NONE, /* TBL_SETOF */
332 /* 12 */ FT_NONE, /* TBL_CHOICE */
333 /* 13 */ FT_NONE, /* TBL_TYPEREF */
335 /* 14 */ FT_NONE, /* TBL_SEQUENCEOF_start */
336 /* 15 */ FT_NONE, /* TBL_TYPEREF_nopop */
337 /* 16 */ FT_NONE, /* TBL_CHOICE_done */
338 /* 17 */ FT_NONE, /* TBL_reserved */
339 /* 18 */ FT_NONE, /* TBL_CHOICE_immediate */
341 /* 19 */ FT_NONE, /* TBL_INVALID */
344 static const char *tbl_types_ethereal_txt[] = {
345 /* 0 */ "FT_BOOLEAN", /* TBL_BOOLEAN */
346 /* 1 */ "FT_UINT32", /* TBL_INTEGER */
347 /* 2 */ "FT_UINT32", /* TBL_BITSTRING */
348 /* 2 */ "FT_STRINGZ", /* TBL_OCTETSTRING */
349 /* 4 */ "FT_NONE", /* TBL_NULL */
350 /* 5 */ "FT_BYTES", /* TBL_OID */
351 /* 6 */ "FT_DOUBLE", /* TBL_REAL */
352 /* 7 */ "FT_UINT32", /* TBL_ENUMERATED */
353 /* 8 */ "FT_NONE", /* TBL_SEQUENCE */
354 /* 9 */ "FT_NONE", /* TBL_SET */
355 /* 10 */ "FT_NONE", /* TBL_SEQUENCEOF */
356 /* 11 */ "FT_NONE", /* TBL_SETOF */
357 /* 12 */ "FT_NONE", /* TBL_CHOICE */
358 /* 13 */ "FT_NONE", /* TBL_TYPEREF */
360 /* 14 */ "FT_NONE", /* TBL_SEQUENCEOF_start */
361 /* 15 */ "FT_NONE", /* TBL_TYPEREF_nopop */
362 /* 16 */ "FT_NONE", /* TBL_CHOICE_done */
363 /* 17 */ "FT_NONE", /* TBL_reserved */
364 /* 18 */ "FT_NONE", /* TBL_CHOICE_immediate */
366 /* 19 */ "FT_NONE", /* TBL_INVALID */
369 typedef struct _PDUinfo PDUinfo;
373 const char *typename;
374 const char *fullname;
380 gint basetype; /* parent type */
381 gint mytype; /* original type number, typenum may have gone through a reference */
382 gint value_id; /* ethereal field id for the value in this PDU */
383 gint type_id; /* ethereal field id for the type of this PDU */
384 hf_register_info value_hf; /* ethereal field info for this value */
388 /* bits in the flags collection */
389 #define PDU_OPTIONAL 1
390 #define PDU_IMPLICIT 2
391 #define PDU_NAMEDNUM 4
392 #define PDU_REFERENCE 8
393 #define PDU_TYPEDEF 0x10
394 #define PDU_ANONYMOUS 0x20
395 #define PDU_TYPETREE 0x40
397 #define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
399 static guint PDUinfo_initflags = 0; /* default flags for newly allocated PDUinfo structs */
401 /* description of PDU properties as passed from the matching routine
402 * to the decoder and GUI.
404 typedef struct _PDUprops PDUprops;
406 guint type; /* value from enum TBLTypeId */
408 const char *typename;
409 const char *fullname;
415 /* flags defined in PDUprops.flags */
416 #define OUT_FLAG_type 1
417 #define OUT_FLAG_data 2
418 #define OUT_FLAG_typename 4
419 #define OUT_FLAG_dontshow 8
420 #define OUT_FLAG_noname 0x10
421 #define OUT_FLAG_constructed 0x20
423 static PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
424 static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
426 static const char empty[] = ""; /* address of the empt string, avoids many tests for NULL */
427 #define MAX_OTSLEN 256 /* max printed size for an octet string */
430 #undef NEST /* show nesting of asn.1 enties */
432 #ifdef NEST /* only for debugging */
433 /* show nesting, only for debugging... */
434 #define MAXTAGS MAX_NEST
440 static char *showtaglist(guint level)
442 static char tagtxt[BUFLM];
447 for(i=0; i<= level; i++) {
448 switch(taglist[i].cls) {
449 case ASN1_UNI: *p++ = 'U'; break;
450 case ASN1_APL: *p++ = 'A'; break;
451 case ASN1_CTX: *p++ = 'C'; break;
452 case ASN1_PRV: *p++ = 'P'; break;
453 default: *p++ = 'x'; break;
455 p += sprintf(p, "%d.", taglist[i].tag);
457 #else /* only context tags */
459 for(i=0; i<= level; i++) {
460 if (taglist[i].cls == ASN1_CTX) {
461 p += sprintf(p, "%d.", taglist[i].tag);
465 *--p = 0; /* remove trailing '.' */
470 get_context(guint level)
475 for(i=0; i<=level; i++) {
476 if (taglist[i].cls == ASN1_CTX)
477 ctx = (ctx << 8) | taglist[i].tag;
481 #endif /* NEST, only for debugging */
484 /* Convert a bit string to an ascii representation for printing
485 * -- not thread safe ...
487 static const char *showbits(guchar *val, guint count)
489 static char str[BUFLM];
494 return "*too many bits*";
497 for(i=0; i<count; i++) {
498 if (i && ((i & 7) == 0)) *p++ = ' ';
499 *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
506 /* get bitnames string for bits set */
508 showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
510 static char str[BUFLL];
514 if (props->flags & OUT_FLAG_noname)
518 return "*too many bits, no names...*";
521 for(i=0; i<count; i++) {
522 if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
523 p += sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
527 --p; /* remove terminating , */
535 /* Convert an oid to its conventional text representation
536 * -- not thread safe...
538 static char *showoid(subid_t *oid, guint len)
540 static char str[BUFLM];
545 for(i=0; i<len; i++) {
547 p += sprintf(p, "%lu", (unsigned long)oid[i]);
554 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
556 showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
561 const char *endstr = empty;
567 for (i=0; i<len; i++) {
568 if (!isprint(octets[i])) /* maybe isblank() as well ... */
571 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
573 endstr = "...."; /* this is 5 bytes !! */
576 str = p = g_malloc(len*2 + 5);
577 for (i=0; i<len; i++) {
578 p += sprintf(p, "%2.2X", octets[i]);
582 if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
583 str = p = g_malloc(len*3+2);
584 for (i=0; i<len; i++) {
585 p += sprintf(p, "%2.2X", octets[i]);
587 *p++ = ' '; /* insert space */
588 strncpy(p, octets, len);
591 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
592 str = g_malloc(len+5);
593 strncpy(str, octets, len);
594 strcpy(&str[len], endstr);
601 /* allow NULL pointers in strcmp, handle them as empty strings */
603 g_strcmp(gconstpointer a, gconstpointer b)
605 if (a == 0) a = empty;
606 if (b == 0) b = empty;
610 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
611 /* WARNING WARNING WARNING WARNING WARNING WARNING */
613 /* Most of the following routine is guesswork in order to */
614 /* speed up resynchronisation if the dissector lost the */
615 /* encoding due to incomplete captures, or a capture that */
616 /* starts in the middle of a fragmented ip packet */
617 /* If this poses to many problems, these settings can be */
618 /* made part of the protocol settings in the user interface */
619 /*************************************************************/
621 /* check length for a reasonable value, return a corrected value */
623 checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
628 g_snprintf(lenstr, strmax, "indefinite");
632 if (len < 0) /* negative ..... */
635 if (cls != ASN1_UNI) { /* don't know about the tags */
640 case ASN1_EOC: /* End Of Contents */
641 case ASN1_NUL: /* Null */
644 case ASN1_BOL: /* Boolean */
647 case ASN1_INT: /* Integer */
648 case ASN1_ENUM: /* Enumerated */
652 case ASN1_BTS: /* Bit String */
656 case ASN1_OTS: /* Octet String */
657 case ASN1_NUMSTR: /* Numerical String */
658 case ASN1_PRNSTR: /* Printable String */
659 case ASN1_TEXSTR: /* Teletext String */
660 case ASN1_VIDSTR: /* Video String */
661 case ASN1_IA5STR: /* IA5 String */
662 case ASN1_GRASTR: /* Graphical String */
663 case ASN1_VISSTR: /* Visible String */
664 case ASN1_GENSTR: /* General String */
668 case ASN1_OJI: /* Object Identifier */
669 case ASN1_OJD: /* Description */
670 case ASN1_EXT: /* External */
674 case ASN1_REAL: /* Real */
678 case ASN1_SEQ: /* Sequence */
679 case ASN1_SET: /* Set */
683 case ASN1_UNITIM: /* Universal Time */
684 case ASN1_GENTIM: /* General Time */
697 /* a change was needed.... */
698 g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
700 g_snprintf(lenstr, strmax, "%d", len);
705 static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
706 static void PDUreset(int count, int counr2);
709 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
712 guint cls, con, tag, def, len, offset, reassembled;
717 const char *name, *tname;
718 volatile guint boffset;
719 volatile int i = 0; /* PDU counter */
720 proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
722 static guint lastseq;
727 reassembled = 1; /* UDP is not a stream, and thus always reassembled .... */
728 if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
729 struct tcpinfo *info = (struct tcpinfo *)pinfo->private_data;
730 gint delta = info->seq - lastseq;
731 reassembled = info->is_reassembled;
735 g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
736 info->seq, delta, reassembled);
739 g_message("dissect_asn1: udp");
742 /* Set the protocol column */
743 if(check_col(pinfo->cinfo, COL_PROTOCOL)){
744 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
747 if(check_col(pinfo->cinfo, COL_INFO))
748 col_clear(pinfo->cinfo, COL_INFO);
752 if ((first_pdu_offset > 0) && !reassembled) {
753 boffset = first_pdu_offset;
754 g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
757 /* open BER decoding */
758 asn1_open(&asn1, tvb, boffset);
760 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
762 asn1_close(&asn1, &offset);
764 PDUreset(pcount, 0); /* arguments are just for debugging */
765 getPDUprops(&props, boffset, cls, tag, con);
767 tname = props.typename;
769 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
773 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
775 g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
782 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
788 if (props.flags & OUT_FLAG_noname) {
789 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
790 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
792 g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
795 /* Set the info column */
796 if(check_col(pinfo->cinfo, COL_INFO)){
797 col_add_str(pinfo->cinfo, COL_INFO, headstr );
801 * If we have a non-null tree (ie we are building the proto_tree
802 * instead of just filling out the columns ), then add a BER
806 /* ignore the tree here, must decode BER to know how to reassemble!! */
809 TRY { /* catch incomplete PDU's */
811 ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
812 def? (int) (offset - boffset + len) : -1,
813 "ASN.1 %s", current_pduname);
815 tree2 = proto_item_add_subtree(ti, ett_asn1);
817 proto_tree_add_item_hidden(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
818 def? (int) (offset - boffset + len) : -1, TRUE);
820 offset = boffset; /* the first packet */
821 while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
824 /* open BER decoding */
825 asn1_open(&asn1, tvb, offset);
826 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
827 asn1_close(&asn1, &offset);
829 PDUreset(pcount, i+1);
830 getPDUprops(&props, boffset, cls, tag, con);
832 tname = props.typename;
835 len = tvb_length_remaining(tvb, offset);
837 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
841 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
843 g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
846 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
849 tvb_length_remaining(tvb, offset) );
851 if (props.value_id == -1)
852 ti2 = proto_tree_add_text(tree2, tvb, boffset,
853 def? (int) (offset - boffset + len) : -1,
854 "%s: (%s)%s %d-%d %s", current_pduname,
855 tname, name, pcount, i+1, headstr);
857 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
858 def? (int) (offset - boffset + len) : -1,
859 "%s: (%s)%s %d-%d %s ~", current_pduname,
860 tname, name, pcount, i+1, headstr);
862 if (props.type_id != -1)
863 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
864 def? (int) (offset - boffset + len) : -1, TRUE);
868 if (props.flags & OUT_FLAG_noname) {
869 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
870 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
872 if (props.value_id == -1)
873 ti2 = proto_tree_add_text(tree2, tvb, boffset,
874 def? (int) (offset - boffset + len) : -1,
875 "%s: (%s)%s", current_pduname, tname, name);
877 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
878 def? (int) (offset - boffset + len) : -1,
879 "%s: (%s)%s ~", current_pduname, tname, name);
880 if (props.type_id != -1)
881 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
882 def? (int) (offset - boffset + len) : -1, TRUE);
885 asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
888 taglist[0].cls = cls;
889 taglist[0].tag = tag;
892 if (!def) len++; /* make sure we get an exception if we run off the end! */
894 offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
896 proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
898 i++; /* one more full message handled */
900 if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
901 proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
903 if(check_col(pinfo->cinfo, COL_INFO))
904 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
906 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
911 CATCH(ReportedBoundsError) {
912 if(check_col(pinfo->cinfo, COL_INFO))
913 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
915 proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
917 proto_item_append_text(ti2, " (incomplete)");
918 if (asn1_desegment) {
919 pinfo->desegment_offset = boffset;
920 pinfo->desegment_len = 1;
922 g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
923 boffset, 1, pinfo->can_desegment);
931 g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
932 pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
935 /* decode an ASN.1 sequence, until we have consumed the specified length */
937 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
940 guint ret, cls, con, tag, def, len, boffset, soffset, eos;
942 const char *clsstr, *constr, *tagstr;
946 proto_tree *ti, *pt2;
947 guchar *octets, *bits, unused;
949 /* the debugging formats */
950 static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s"; /* decimal */
951 static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s"; /* enum */
952 static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s"; /* octet string */
953 static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s"; /* bit field */
954 static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s"; /* constructed */
955 static char matchind[] = " ~"; /* indication of possible match */
956 const char *name, *ename, *tname;
960 ti = 0; /* suppress gcc warning */
962 soffset = offset; /* where this sequence starts */
964 while (offset < eos) { /* while this entity has not ended... */
966 asn1_open(&asn1, tvb, offset);
967 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
968 asn1_close(&asn1, &offset); /* mark current position */
969 if (ret != ASN1_ERR_NOERROR) {
970 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
974 getPDUprops(&props, boffset, cls, tag, con);
976 tname = props.typename;
978 name = &props.fullname[pabbrev_pdu_len]; /* no abbrev.pduname */
979 if (asn1_debug) { /* show both names */
980 sprintf(fieldname, "%s[%s]", props.name, props.fullname);
984 clsstr = asn1_cls[cls];
985 constr = asn1_con[con];
986 if ((cls == ASN1_UNI) && ( tag < 32 )) {
987 tagstr = asn1_tag[tag];
989 g_snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
993 len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
996 g_snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
998 strncpy(nnbuf, "NN-", sizeof(nnbuf));
999 /* make sure we get an exception if we run off the end! */
1000 len = tvb_length_remaining(tvb, offset) + 1;
1002 if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
1003 /* just give type name if we don't know any better */
1005 name = nnbuf; /* this is better than just empty.... */
1009 taglist[level].cls = cls;
1010 taglist[level].tag = tag;
1014 if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
1017 oname = g_malloc(strlen(name) + 32);
1018 sprintf(oname, "%s ** nesting cut off **", name);
1022 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
1025 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1026 asn1_close(&asn1, &offset); /* mark where we are now */
1028 if ( (props.value_id == -1) ||
1029 (tbl_types_ethereal[props.type] != FT_UINT32) )
1030 /* unknown or unexpected: just text */
1031 proto_tree_add_text(pt, tvb, boffset,
1032 offset - boffset, textfmt_d, boffset,
1033 clsstr, constr, tagstr, tname, name, value,
1036 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1037 offset - boffset, value, textfmt_d, boffset,
1038 clsstr, constr, tagstr, tname, name, value,
1040 if (props.type_id != -1)
1041 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1042 boffset, offset - boffset, value);
1045 if ( (props.value_id == -1) ||
1046 (tbl_types_ethereal[props.type] != FT_UINT32) )
1047 /* unknown or unexpected, just text */
1048 proto_tree_add_text(pt, tvb, boffset,
1050 "(%s)%s: %d", tname, name, value);
1052 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1053 offset - boffset, value,
1054 "(%s)%s: %d ~", tname, name, value);
1055 if (props.type_id != -1)
1056 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1057 boffset, offset - boffset, value);
1063 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1064 asn1_close(&asn1, &offset); /* mark where we are now */
1065 ename = getPDUenum(&props, boffset, cls, tag, value);
1067 if ( (props.value_id == -1) ||
1068 (tbl_types_ethereal[props.type] != FT_UINT32) )
1069 /* unknown or unexpected, just text */
1070 proto_tree_add_text(pt, tvb, boffset,
1072 textfmt_e, boffset, clsstr, constr, tagstr,
1073 tname, name, value, ename, empty);
1075 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1076 offset - boffset, value,
1077 textfmt_e, boffset, clsstr, constr, tagstr,
1078 tname, name, value, ename, matchind);
1079 if (props.type_id != -1)
1080 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1081 boffset, offset - boffset, value);
1084 if ( (props.value_id == -1) ||
1085 (tbl_types_ethereal[props.type] != FT_UINT32) )
1086 /* unknown or unexpected, just text */
1087 proto_tree_add_text(pt, tvb, boffset,
1089 "(%s)%s: %d:%s", tname, name, value, ename);
1091 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1092 offset - boffset, value,
1093 "(%s)%s: %d:%s ~", tname, name, value, ename);
1094 if (props.type_id != -1)
1095 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1096 boffset, offset - boffset, value);
1102 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1103 asn1_close(&asn1, &offset); /* mark where we are now */
1105 if ( (props.value_id == -1) ||
1106 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1107 /* unknown or unexpected, just text */
1108 proto_tree_add_text(pt, tvb, boffset,
1110 textfmt_s, boffset, clsstr, constr, tagstr,
1111 tname, name, value? "true" : "false", empty);
1113 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1114 offset - boffset, value != 0,
1115 textfmt_s, boffset, clsstr, constr, tagstr,
1116 tname, name, value? "true" : "false", matchind);
1117 if (props.type_id != -1)
1118 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1119 boffset, offset - boffset, value != 0);
1122 if ( (props.value_id == -1) ||
1123 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1124 /* unknown or unexpected, just text */
1125 proto_tree_add_text(pt, tvb, boffset,
1127 "(%s)%s: %s", tname, name,
1128 value? "true" : "false");
1130 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1131 offset - boffset, value != 0,
1132 "(%s)%s: %s ~", tname, name,
1133 value? "true" : "false");
1134 if (props.type_id != -1)
1135 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1136 boffset, offset - boffset, value != 0);
1149 /* read value, \0 terminated */
1150 ret = asn1_string_value_decode(&asn1, len, &octets);
1151 asn1_close(&asn1, &offset); /* mark where we are now */
1152 ename = showoctets(octets, len, (tag == ASN1_OTS) ? 4 : 0 );
1154 if ( (props.value_id == -1) ||
1155 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1156 /* unknown or unexpected, just text */
1157 proto_tree_add_text(pt, tvb, boffset,
1159 textfmt_s, boffset, clsstr, constr, tagstr,
1160 tname, name, ename, empty);
1162 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1163 offset - boffset, octets, /* \0 termnated */
1164 textfmt_s, boffset, clsstr, constr, tagstr,
1165 tname, name, ename, matchind);
1166 if (props.type_id != -1)
1167 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1168 boffset, offset - boffset, octets);
1171 if ( (props.value_id == -1) ||
1172 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1173 /* unknown or unexpected, just text */
1174 proto_tree_add_text(pt, tvb, boffset,
1176 "(%s)%s: %s", tname, name, ename);
1178 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1179 offset - boffset, octets, /* \0 terminated */
1180 "(%s)%s: %s ~", tname, name, ename);
1181 if (props.type_id != -1)
1182 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1183 boffset, offset - boffset, octets);
1191 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1192 asn1_close(&asn1, &offset); /* mark where we are now */
1193 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1195 if ( (props.value_id == -1) ||
1196 (tbl_types_ethereal[props.type] != FT_UINT32) )
1197 /* unknown or unexpected, just text */
1198 proto_tree_add_text(pt, tvb, boffset,
1200 textfmt_b, boffset, clsstr, constr, tagstr,
1202 showbits(bits, (con*8)-unused), ename, empty);
1204 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1205 offset - boffset, *bits, /* XXX length ? XXX */
1206 textfmt_b, boffset, clsstr, constr, tagstr,
1208 showbits(bits, (con*8)-unused),ename, matchind);
1209 if (props.type_id != -1)
1210 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1211 boffset, offset - boffset, *bits);
1215 if ( (props.value_id == -1) ||
1216 (tbl_types_ethereal[props.type] != FT_UINT32) )
1217 /* unknown or unexpected, just text */
1218 proto_tree_add_text(pt, tvb, boffset,
1220 "(%s)%s: %s:%s", tname, name,
1221 showbits(bits, (con*8)-unused), ename);
1223 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1224 offset - boffset, *bits, /* XXX length ? XXX */
1225 "(%s)%s: %s:%s ~", tname, name,
1226 showbits(bits, (con*8)-unused), ename);
1227 if (props.type_id != -1)
1228 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1229 boffset, offset - boffset, *bits);
1237 /* show full sequence length */
1240 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1242 if ( (props.flags & OUT_FLAG_constructed))
1243 ename = ", unexpected constructed";
1245 if (props.value_id == -1)
1246 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1247 textfmt_c, boffset, clsstr, constr, tagstr,
1248 tname, name, ename, empty);
1250 ti = proto_tree_add_item(pt, props.value_id, tvb,
1252 /* change te text to to what I really want */
1253 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1254 tagstr, tname, name, ename, matchind);
1255 if (props.type_id != -1)
1256 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1260 if (props.value_id == -1) {
1261 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1262 ti = proto_tree_add_text(pt, tvb, boffset,
1263 offset - boffset + len,
1264 "(%s)%s", tname, name);
1266 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1267 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1268 boffset, offset - boffset + len,
1269 "(%s)%s ~", tname, name);
1271 /* don't care about the text */
1272 ti = proto_tree_add_item_hidden(pt, props.value_id, tvb,
1275 if (props.type_id != -1)
1276 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1280 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1282 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1283 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1287 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1289 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1290 proto_item_set_len(ti, offset - boffset);
1295 if (asn1_debug) { /* don't show if not debugging */
1296 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1297 boffset, clsstr, constr, tagstr, tname, name,
1298 offset - soffset, empty);
1300 getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1304 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1305 asn1_close(&asn1, &offset); /* mark where we are now */
1306 ename = showoid(oid, con);
1308 if ( (props.value_id == -1) ||
1309 (tbl_types_ethereal[props.type] != FT_BYTES) )
1310 /* unknown or unexpected, just text */
1311 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1312 boffset, clsstr, constr, tagstr, tname, name,
1315 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1316 offset - boffset, ename,/* XXX length?*/
1317 "(%s)%s: %s ~", tname, name, ename);
1318 if (props.type_id != -1)
1319 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1320 boffset, offset - boffset, ename);
1323 if ( (props.value_id == -1) ||
1324 (tbl_types_ethereal[props.type] != FT_BYTES) )
1325 /* unknown or unexpected, just text */
1326 proto_tree_add_text(pt, tvb, boffset,
1328 "(%s)%s: %s", tname, name, ename);
1330 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1331 offset - boffset, ename, /* XXX length ? */
1332 "(%s)%s: %s ~", tname, name, ename);
1333 if (props.type_id != -1)
1334 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1335 boffset, offset - boffset, ename);
1343 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1344 boffset, clsstr, constr, tagstr, tname, name,
1347 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1348 "(%s)%s: [NULL]", tname, name);
1350 offset += len; /* skip value ... */
1362 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1363 textfmt_s, boffset, clsstr, constr, tagstr,
1364 tname, name, lenbuf, empty);
1366 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1367 "(%s)%s: %s bytes", tname, name, lenbuf);
1369 proto_item_append_text(ti, " *"); /* indicate default is used */
1370 offset += len; /* skip value ... */
1375 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1376 case ASN1_APL: /* fprintf(stderr, "Application\n"); */
1377 case ASN1_PRV: /* fprintf(stderr, "Private\n"); */
1380 if (props.value_id == -1) /* type unknown, handle as string */
1382 switch(props.type) {
1383 /* this is via the asn1 description, don't trust the length */
1387 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1388 asn1_close(&asn1, &offset); /* mark where we are now */
1390 if ( (props.value_id == -1) ||
1391 (tbl_types_ethereal[props.type] != FT_UINT32) )
1392 /* unknown or unexpected, just text */
1393 proto_tree_add_text(pt, tvb,
1394 boffset, offset - boffset,
1395 textfmt_d, boffset, clsstr, constr,
1396 tagstr, tname, name, value, empty);
1398 proto_tree_add_uint_format(pt, props.value_id, tvb,
1399 boffset, offset - boffset, value,
1400 textfmt_d, boffset, clsstr, constr,
1401 tagstr, tname, name, value, matchind);
1402 if (props.type_id != -1)
1403 proto_tree_add_uint_hidden(pt, props.type_id,
1404 tvb, boffset, offset - boffset, value);
1407 if ( (props.value_id == -1) ||
1408 (tbl_types_ethereal[props.type] != FT_UINT32) )
1409 /* unknown or unexpected, just text */
1410 proto_tree_add_text(pt, tvb,
1411 boffset, offset - boffset,
1412 "(%s)%s: %d", tname, name, value);
1414 proto_tree_add_uint_format(pt, props.value_id, tvb,
1415 boffset, offset - boffset, value,
1416 "(%s)%s: %d ~", tname, name, value);
1417 if (props.type_id != -1)
1418 proto_tree_add_uint_hidden(pt, props.type_id,
1419 tvb, boffset, offset - boffset, value);
1424 case TBL_ENUMERATED:
1427 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1428 asn1_close(&asn1, &offset); /* mark where we are now */
1429 ename = getPDUenum(&props, boffset, cls, tag, value);
1431 if ( (props.value_id == -1) ||
1432 (tbl_types_ethereal[props.type] != FT_UINT32) )
1433 /* unknown or unexpected, just text */
1434 proto_tree_add_text(pt, tvb,
1435 boffset, offset - boffset,
1436 textfmt_e, boffset, clsstr, constr,
1437 tagstr, tname, name, value, ename, empty);
1439 proto_tree_add_uint_format(pt, props.value_id, tvb,
1440 boffset, offset - boffset, value,
1441 textfmt_e, boffset, clsstr, constr,
1442 tagstr, tname, name, value, ename, matchind);
1443 if (props.type_id != -1)
1444 proto_tree_add_uint_hidden(pt, props.type_id,
1445 tvb, boffset, offset - boffset, value);
1448 if ( (props.value_id == -1) ||
1449 (tbl_types_ethereal[props.type] != FT_UINT32) )
1450 /* unknown or unexpected, just text */
1451 proto_tree_add_text(pt, tvb,
1452 boffset, offset - boffset,
1453 "(%s)%s: %d:%s", tname, name, value, ename);
1455 proto_tree_add_uint_format(pt, props.value_id, tvb,
1456 boffset, offset - boffset, value,
1457 "(%s)%s: %d:%s ~", tname, name, value, ename);
1458 if (props.type_id != -1)
1459 proto_tree_add_uint_hidden(pt, props.type_id,
1460 tvb, boffset, offset - boffset, value);
1465 if (len > (1+4)) /* max 32 bits ...?.. */
1468 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1469 asn1_close(&asn1, &offset); /* mark where we are now */
1470 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1472 if ( (props.value_id == -1) ||
1473 (tbl_types_ethereal[props.type] != FT_UINT32) )
1474 /* unknown or unexpected, just text */
1475 proto_tree_add_text(pt, tvb,
1476 boffset, offset - boffset,
1477 textfmt_b, boffset, clsstr, constr,
1478 tagstr, tname, name,
1479 showbits(bits, (con*8)-unused), ename,
1482 proto_tree_add_uint_format(pt, props.value_id, tvb,
1483 boffset, offset - boffset, *bits,
1484 textfmt_b, boffset, clsstr, constr,
1485 tagstr, tname, name,
1486 showbits(bits, (con*8)-unused), ename,
1488 if (props.type_id != -1)
1489 proto_tree_add_uint_hidden(pt, props.type_id,
1490 tvb, boffset, offset - boffset, *bits);
1493 if ( (props.value_id == -1) ||
1494 (tbl_types_ethereal[props.type] != FT_UINT32) )
1495 /* unknown or unexpected, just text */
1496 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1497 "(%s)%s: %s:%s", tname, name,
1498 showbits(bits, (con*8)-unused), ename);
1500 proto_tree_add_uint_format(pt, props.value_id, tvb,
1501 boffset, offset - boffset, *bits,
1502 "(%s)%s: %s:%s ~", tname, name,
1503 showbits(bits, (con*8)-unused), ename);
1504 if (props.type_id != -1)
1505 proto_tree_add_uint_hidden(pt, props.type_id,
1506 tvb, boffset, offset - boffset, *bits);
1514 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1515 asn1_close(&asn1, &offset); /* mark where we are now */
1517 if ( (props.value_id == -1) ||
1518 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1519 /* unknown or unexpected, just text */
1520 proto_tree_add_text(pt, tvb,
1521 boffset, offset - boffset,
1522 textfmt_s, boffset, clsstr, constr,
1523 tagstr, tname, name,
1524 value? "true" : "false", empty);
1526 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1527 boffset, offset - boffset, value != 0,
1528 textfmt_s, boffset, clsstr, constr,
1529 tagstr, tname, name,
1530 value? "true" : "false", matchind);
1531 if (props.type_id != -1)
1532 proto_tree_add_boolean_hidden(pt, props.type_id,
1533 tvb, boffset, offset - boffset, value != 0);
1536 if ( (props.value_id == -1) ||
1537 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1538 /* unknown or unexpected, just text */
1539 proto_tree_add_text(pt, tvb,
1540 boffset, offset - boffset,
1541 "(%s)%s: %s", tname, name,
1542 value? "true" : "false");
1544 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1545 boffset, offset - boffset, value != 0,
1546 "(%s)%s: %s ~", tname, name,
1547 value? "true" : "false");
1548 if (props.type_id != -1)
1549 proto_tree_add_boolean_hidden(pt, props.type_id,
1550 tvb, boffset, offset - boffset, value != 0);
1558 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1559 textfmt_s, boffset, clsstr, constr,
1560 tagstr, tname, name, "[NULL]", empty);
1562 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1563 "(%s)%s: [NULL]", tname, name);
1565 offset += len; /* skip value ... */
1569 props.value_id = -1; /* unlikely this is correct, dont use it */
1571 case TBL_OCTETSTRING:
1572 /* defined length, not constructed, must be a string.... */
1573 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1574 asn1_close(&asn1, &offset); /* mark where we are now */
1575 ename = showoctets(octets, len, 2); /* convert octets to printable */
1577 if ( (props.value_id == -1) ||
1578 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1579 /* unknown or unexpected, just text */
1580 proto_tree_add_text(pt, tvb,
1581 boffset, offset - boffset,
1582 textfmt_s, boffset, clsstr, constr,
1583 tagstr, tname, name, ename, empty);
1585 proto_tree_add_string_format(pt, props.value_id, tvb,
1586 boffset, offset - boffset, octets, /* XXX */
1587 textfmt_s, boffset, clsstr, constr,
1588 tagstr, tname, name, ename, matchind);
1589 if (props.type_id != -1)
1590 proto_tree_add_string_hidden(pt, props.type_id,
1591 tvb, boffset, offset - boffset, octets);
1594 if ( (props.value_id == -1) ||
1595 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1596 /* unknown or unexpected, just text */
1597 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1598 "(%s)%s: %s", tname, name, ename);
1600 proto_tree_add_string_format(pt, props.value_id, tvb,
1601 boffset, offset - boffset, octets, /* XXX */
1602 "(%s)%s: %s ~", tname, name, ename);
1603 if (props.type_id != -1)
1604 proto_tree_add_string_hidden(pt, props.type_id,
1605 tvb, boffset, offset - boffset, octets);
1613 /* indefinite length or constructed.... must be a sequence .... */
1614 /* show full sequence length */
1617 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1619 if ( (props.flags & OUT_FLAG_constructed))
1620 ename = ", unexpected constructed";
1622 if (props.value_id == -1)
1623 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1624 textfmt_c, boffset, clsstr, constr,
1625 tagstr, tname, name, ename, empty);
1627 ti = proto_tree_add_item(pt, props.value_id, tvb,
1629 /* change te text to to what I really want */
1631 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1632 tagstr, tname, name, ename, matchind);
1633 if (props.type_id != -1)
1634 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1637 ti = proto_tree_add_text(pt, tvb, boffset,
1638 offset - boffset + len,
1639 textfmt_c, boffset, clsstr, constr,
1640 tagstr, tname, name, ename, empty);
1644 if (props.value_id == -1) {
1645 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1646 ti = proto_tree_add_text(pt, tvb, boffset,
1647 offset - boffset + len, "(%s)%s", tname, name);
1649 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1650 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1652 "(%s)%s ~", tname, name);
1654 /* don't care about the text */
1655 ti = proto_tree_add_item_hidden(pt, props.value_id,
1656 tvb, boffset, 1, TRUE);
1658 if (props.type_id != -1)
1659 proto_tree_add_item_hidden(pt, props.type_id,
1660 tvb, boffset, 1, TRUE);
1664 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1666 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1667 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1671 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1673 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1674 proto_item_set_len(ti, offset - boffset);
1678 default: /* fprintf(stderr, "Other\n"); */
1680 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1681 textfmt_s, boffset, clsstr, constr, tagstr,
1682 tname, name, lenbuf, empty);
1684 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1685 "(%s)%s: %s bytes %s data", tname, name,
1688 proto_item_append_text(ti, " *"); /* indicate default is used */
1689 offset += len; /* skip value ... */
1692 g_free(oname); /* XXX, memory management ? */
1694 /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1696 getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1703 /************************************************************************************************/
1704 /* search throug the ASN.1 description for appropriate names */
1705 /************************************************************************************************/
1707 guint lev_limit = G_MAXINT;
1709 int icount = 0; /* item counter */
1712 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1715 guint eos, ret, cls, con, tag, def, len, value;
1716 guchar *octets, *bits, unused;
1718 const char *clsstr, *constr, *tagstr;
1721 GNode *cur_node = 0;
1723 eos = offset + size;
1725 if (level > lev_limit)
1728 while(offset < eos) {
1729 if (ptr) /* build pointer tree to all asn1 enteties */
1730 cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
1732 asn1_open(&asn1, tvb, offset);
1733 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1734 asn1_close(&asn1, &offset); /* mark where we are */
1736 clsstr = asn1_cls[cls];
1737 constr = asn1_con[con];
1738 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1739 tagstr = asn1_tag[tag];
1741 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1745 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1747 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1748 len = tvb_length_remaining(tvb, offset);
1752 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
1756 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1757 asn1_close(&asn1, &offset); /* mark where we are */
1761 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1762 asn1_close(&asn1, &offset); /* mark where we are */
1773 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1774 asn1_close(&asn1, &offset); /* mark where we are */
1779 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1780 asn1_close(&asn1, &offset); /* mark where we are */
1786 if (len == 0) /* don't recurse if offset isn't going to change */
1789 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1796 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1797 asn1_close(&asn1, &offset); /* mark where we are */
1813 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1814 offset += len; /* skip value ... */
1819 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1821 g_snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
1823 /* defined length, not constructed, must be a string.... */
1824 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1825 asn1_close(&asn1, &offset); /* mark where we are */
1828 /* indefinite length or constructed.... must be a sequence .... */
1829 if (len == 0) /* don't recurse if offset isn't going to change */
1832 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1836 default: /* fprintf(stderr, "Other\n"); */
1837 if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1838 offset += len; /* skip value ... */
1845 static void showGNodes(GNode *p, int n);
1849 myLeaf(GNode *node, gpointer data)
1852 guint ret, cls, con, tag, def, len;
1853 char *clsstr, *constr, *tagstr;
1857 (void) data; /* make a reference */
1858 asn1_open(&asn1, asn1_desc, (int)node->data);
1860 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1862 clsstr = asn1_cls[cls];
1863 constr = asn1_con[con];
1864 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1865 tagstr = asn1_tag[tag];
1867 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1871 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1873 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1877 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1885 if (asn1_verbose) g_message("build GNode tree:");
1886 showGNodes(g_node_first_child(asn1_nodes), 0);
1887 if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1888 g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1889 g_node_max_height (asn1_nodes),
1890 g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1891 g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1893 g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1899 tt_build_tree(void) /* build a GNode tree with all offset's to ASN.1 entities */
1902 g_node_destroy(asn1_nodes);
1903 asn1_nodes = g_node_new(0);
1905 parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1909 /*****************************************************************************************************/
1911 static guint anonCount; /* for naming anonymous types */
1913 typedef struct _TBLModule TBLModule;
1914 typedef struct _TBLTypeDef TBLTypeDef;
1915 typedef struct _TBLTag TBLTag;
1916 typedef struct _TBLType TBLType;
1917 typedef struct _TBLTypeRef TBLTypeRef;
1918 typedef struct _TBLNamedNumber TBLNamedNumber;
1919 typedef struct _TBLRange TBLRange;
1927 TBLTYPE_NamedNumber,
1930 typedef enum _tbl_t tbl_t;
1931 /* text for 'tbl_t' type for debugging */
1932 static const char *data_types[] = {
1942 enum _TBLTypeContent_t {
1944 TBLTYPETYPE_Primitive,
1945 TBLTYPETYPE_Elements,
1948 typedef enum _TBLTypeContent_t TBLTypeContent_t;
1950 struct _TBLNamedNumber {
1962 struct _TBLTypeRef {
1978 TBLTypeContent_t content;
1981 gboolean constraint;
1984 struct _TBLTypeDef {
1999 guint totalNumModules;
2000 guint totalNumTypeDefs;
2001 guint totalNumTypes;
2003 guint totalNumStrings;
2004 guint totalLenStrings;
2007 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2010 get_asn1_int(guint want_tag, guint offset)
2013 guint ret, cls, con, tag, def, len;
2016 /* g_message("%d get_asn1_int", offset); */
2018 asn1_open(&asn1, asn1_desc, offset);
2020 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2021 if (ret == ASN1_ERR_NOERROR) {
2022 /* do not check class, both Unversal and Context are OK */
2023 if (con == ASN1_PRI && tag == want_tag) {
2025 asn1_uint32_value_decode(&asn1, len, &value);
2028 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2030 ret = ASN1_ERR_WRONG_TYPE;
2032 g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2037 static subid_t * /* with prepended length ..... */
2038 get_asn1_oid(guint want_tag, guint offset)
2041 guint ret, cls, con, tag, def, len;
2044 /* g_message("%d get_asn1_oid", offset); */
2046 asn1_open(&asn1, asn1_desc, offset);
2048 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2049 if (ret == ASN1_ERR_NOERROR) {
2050 /* do not check class, both Unversal and Context are OK */
2051 if ((con == ASN1_PRI) && (tag == want_tag)) {
2053 asn1_oid_value_decode(&asn1, len, &oid, &con);
2054 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2055 memmove(&oid[1], oid, con*sizeof(guint));
2059 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2061 ret = ASN1_ERR_WRONG_TYPE;
2063 g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2068 static guchar * /* 0 terminated string */
2069 get_asn1_string(guint want_tag, guint offset)
2072 guint ret, cls, con, tag, def, len;
2075 /* g_message("%d get_asn1_string", offset); */
2077 asn1_open(&asn1, asn1_desc, offset);
2079 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2080 if (ret == ASN1_ERR_NOERROR) {
2081 /* do not check class, both Unversal and Context are OK */
2082 if ((con == ASN1_PRI) && (tag == want_tag)) {
2084 asn1_string_value_decode(&asn1, len, &octets);
2085 octets = g_realloc(octets, len+1); /* need space for sentinel */
2089 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2091 ret = ASN1_ERR_WRONG_TYPE;
2093 g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2099 get_asn1_uint(guint offset)
2102 guint ret, len, value;
2104 /* g_message( "%d get_asn1_uint", offset); */
2106 asn1_open(&asn1, asn1_desc, offset);
2108 ret = asn1_uint32_decode(&asn1, &value, &len);
2110 if (ret != ASN1_ERR_NOERROR) {
2111 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2118 check_tag(guint want_tag, guint offset)
2121 guint ret, cls, con, tag, def, len;
2123 asn1_open(&asn1, asn1_desc, offset);
2125 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2126 if (ret == ASN1_ERR_NOERROR) {
2127 ret = (tag == want_tag) ? TRUE : FALSE;
2128 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2131 g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2138 constructed(guint offset)
2141 guint ret, cls, con, tag, def, len;
2143 /* g_message("%d constructed?", offset); */
2145 asn1_open(&asn1, asn1_desc, offset);
2147 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2148 if (ret == ASN1_ERR_NOERROR) {
2154 /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2161 define_constraint(GNode *p, GNode *q)
2163 TBLRange *range = g_malloc(sizeof(TBLRange));
2164 g_node_append_data(q, range);
2166 range->type = TBLTYPE_Range;
2168 /* g_message("define_constraint %p, %p", p, q); */
2170 p = g_node_first_child(p);
2172 range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2173 p = g_node_next_sibling(p);
2175 range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2180 define_namednumber(GNode *p, GNode *q)
2182 TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2183 g_node_append_data(q, num);
2185 num->type = TBLTYPE_NamedNumber;
2187 /* g_message("define_namednumber %p, %p", p, q); */
2189 p = g_node_first_child(p);
2191 num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2192 p = g_node_next_sibling(p);
2194 num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2198 define_typeref(GNode *p, GNode *q)
2200 TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2201 g_node_append_data(q, ref);
2203 ref->type = TBLTYPE_TypeRef;
2205 /* g_message("define_typeref %p, %p", p, q); */
2207 p = g_node_first_child(p);
2209 ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2210 p = g_node_next_sibling(p);
2212 ref->implicit = get_asn1_int(ASN1_BOL, GPOINTER_TO_UINT(p->data));
2216 define_tag(GNode *p, GNode *q)
2218 TBLTag *type = g_malloc(sizeof(TBLTag));
2219 g_node_append_data(q, type);
2221 type->type = TBLTYPE_Tag;
2223 /* g_message("define_tag %p, %p", p, q); */
2225 p = g_node_first_child(p);
2227 type->tclass = get_asn1_int(ASN1_ENUM, GPOINTER_TO_UINT(p->data));
2228 p = g_node_next_sibling(p);
2230 type->code = get_asn1_int(ASN1_INT, GPOINTER_TO_UINT(p->data));
2235 define_type(GNode *p, GNode *q)
2238 TBLType *type = g_malloc(sizeof(TBLType));
2240 GNode *t = g_node_append_data(q, type);
2242 type->type = TBLTYPE_Type;
2244 /* g_message("define_type %p, %p", p, q); */
2246 type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2247 p = g_node_next_sibling(p);
2249 type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2250 p = g_node_next_sibling(p);
2252 if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
2253 r = g_node_first_child(p);
2256 r = g_node_next_sibling(r);
2258 p = g_node_next_sibling(p);
2261 if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
2262 g_warning("expect tag 3, ERROR");
2264 r = g_node_first_child(p);
2266 type->content = TBLTYPETYPE_None;
2267 if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
2268 if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
2269 if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
2270 switch(type->content) {
2271 case TBLTYPETYPE_Primitive:
2273 case TBLTYPETYPE_Elements:
2274 r = g_node_first_child(r);
2276 define_type(g_node_first_child(r), t);
2277 r = g_node_next_sibling(r);
2280 case TBLTYPETYPE_TypeRef:
2281 define_typeref(r, t);
2283 case TBLTYPETYPE_None:
2284 g_warning("expected a contents choice, error");
2287 p = g_node_next_sibling(p);
2289 type->fieldName = 0;
2290 type->anonymous = FALSE;
2291 if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
2292 type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
2293 p = g_node_next_sibling(p);
2295 type->anonymous = TRUE;
2298 type->constraint = FALSE;
2299 if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
2300 type->constraint = TRUE;
2301 define_constraint(p, t);
2302 p = g_node_next_sibling(p);
2305 if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
2306 r = g_node_first_child(p);
2308 define_namednumber(r, t);
2309 r = g_node_next_sibling(r);
2315 define_typedef(GNode *p, GNode *q)
2317 TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2319 GNode *t = g_node_append_data(q, type_def);
2321 /* g_message("define_typedef %p, %p", p, q); */
2323 type_def->type = TBLTYPE_TypeDef;
2325 p = g_node_first_child(p);
2327 type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2328 p = g_node_next_sibling(p);
2330 type_def->typeName = get_asn1_string(ASN1_PRNSTR, GPOINTER_TO_UINT(p->data));
2331 p = g_node_next_sibling(p);
2333 define_type(g_node_first_child(p), t);
2334 p = g_node_next_sibling(p);
2336 type_def->isPdu = (p != 0); /* true if it exists, value ignored */
2340 define_module(GNode *p, GNode *q)
2342 TBLModule *module = g_malloc(sizeof(TBLModule));
2344 GNode *m = g_node_append_data(q, module);
2346 /* g_message("define_module %p %p", p, q); */
2348 module->type = TBLTYPE_Module;
2350 p = g_node_first_child(p);
2352 module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2353 p = g_node_next_sibling(p);
2356 if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */
2357 module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
2358 p = g_node_next_sibling(p);
2361 module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
2362 p = g_node_next_sibling(p);
2364 p = g_node_first_child(p);
2366 define_typedef(p, m);
2367 p = g_node_next_sibling(p);
2371 typedef struct _SearchDef SearchDef;
2378 is_typedef(GNode *node, gpointer data)
2380 TBLTypeDef *d = (TBLTypeDef *)node->data;
2381 SearchDef *s = (SearchDef *)data;
2383 if (d == 0) return FALSE;
2384 if (d->type != TBLTYPE_TypeDef) return FALSE;
2385 if (strcmp(s->key, d->typeName) == 0) {
2392 typedef struct _TypeRef TypeRef;
2398 GNode *pdu; /* location in PDU descriptor tree */
2399 guint level; /* recursion counter */
2401 GPtrArray *refs; /* pointers to PDUinfo structures teferencing this entry */
2404 typedef struct _NameDefs NameDefs;
2410 #define ALLOC_INCR 4
2411 #define CLASSREF (ASN1_PRV+1)
2414 is_named(GNode *node, gpointer data)
2416 TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2417 NameDefs *n = (NameDefs *)data;
2420 if (num == 0) return FALSE;
2421 if (num->type != TBLTYPE_NamedNumber) return FALSE;
2423 if (num->value >= n->max) { /* need larger array */
2425 n->max = num->value + ALLOC_INCR;
2426 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2427 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2429 if (num->value > n->used) /* track max used value, there may be holes... */
2430 n->used = num->value;
2432 n->info[num->value].name = num->name;
2438 index_typedef(GNode *node, gpointer data)
2440 TBLTypeDef *d = (TBLTypeDef *)node->data;
2441 NameDefs *n = (NameDefs *)data;
2446 if (d == 0) return FALSE;
2447 if (d->type != TBLTYPE_TypeDef) return FALSE;
2449 if (d->typeDefId >= n->max) { /* need larger array */
2451 n->max = d->typeDefId + ALLOC_INCR;
2452 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2453 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2455 if (d->typeDefId > n->used) /* track max used value, there may be holes... */
2456 n->used = d->typeDefId;
2458 t = &(n->info[d->typeDefId]);
2459 t->name = d->typeName;
2461 t->refs = g_ptr_array_new(); /* collect references here */
2462 node = g_node_first_child(node); /* the real type */
2463 tag = (TBLTag *)node->data;
2464 if ((tag->type == TBLTYPE_Type) && (((TBLType *)tag)->typeId == TBL_CHOICE)) {
2465 /* no reasonable default... ! */
2466 t->defclass = 3; /* Private .... */
2467 t->deftag= 9999; /* a random value */
2469 node = g_node_first_child(node); /* the default tag */
2470 tag = (TBLTag *)node->data;
2473 t->defclass = tag->tclass;
2474 t->deftag = tag->code;
2476 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2477 t->defclass = CLASSREF; /* invalid class.. */
2478 t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2481 g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2482 data_types[tag->type]);
2483 t->defclass = 3; /* Private .... */
2484 t->deftag= 9998; /* another random value */
2492 static TypeRef *typeDef_names = 0;
2493 static guint numTypedefs = 0;
2496 free_node_data(GNode *node, gpointer data _U_)
2503 get_values(void) /* collect values from ASN.1 tree */
2504 /* coded according to the tbl.asn1 description of snacc output */
2505 { /* This routine does not leave references to the tvbuff or */
2506 /* to the asn1_nodes, both can be freed by the caller of this.*/
2512 const char *t, *s, *E;
2513 static char missing[] = " **missing** ";
2515 if (asn1_verbose) g_message("interpreting tree");
2516 typeDef_names = 0; /* just forget allocated any data .... */
2519 g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2520 free_node_data, NULL);
2521 g_node_destroy(data_nodes);
2524 data_nodes = g_node_new(0);
2526 p = g_node_first_child(asn1_nodes); /* top of the data tree */
2528 p = g_node_first_child(p);
2529 TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2530 p = g_node_next_sibling(p);
2531 TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2532 p = g_node_next_sibling(p);
2533 TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2534 p = g_node_next_sibling(p);
2535 TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2536 p = g_node_next_sibling(p);
2537 TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2538 p = g_node_next_sibling(p);
2539 TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2540 p = g_node_next_sibling(p);
2542 p = g_node_first_child(p);
2544 define_module(p, data_nodes);
2545 p = g_node_next_sibling(p);
2548 /* g_message("finished with tree"); */
2550 if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2551 sd.key = "TBLTypeId";
2553 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2554 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", sd.here);
2558 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2559 g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2561 if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, nd.info);
2563 for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2566 s = nd.info[i].name;
2567 if (s == 0) s = missing;
2568 if (g_strcmp(t, s) == 0) { /* OK ! */
2572 E = ", X with errors X";
2574 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2576 if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2578 tbl_types_verified = TRUE;
2580 /* build table with typedef names */
2583 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2584 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2585 if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, nd.info);
2587 for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2588 TypeRef *ref = &(nd.info[i]);
2591 t = ref->name = missing;
2592 if (asn1_verbose) g_message(" %3d %s", i, t);
2594 if (asn1_verbose) g_message(" %3d %s, %c%d", i, t,
2595 tag_class[ref->defclass], ref->deftag);
2597 if (ref->pdu) { /* should be 0 */
2598 if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, ref->pdu);
2601 typeDef_names = nd.info;
2603 if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
2608 showGNode(GNode *p, int n)
2611 n *=2; /* 2 spaces per level */
2612 if (p->data) { /* show value ... */
2613 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
2614 switch (((TBLTag *)p->data)->type) {
2615 case TBLTYPE_Module: {
2616 TBLModule *m = (TBLModule *)p->data;
2618 g_message("%*smodule %s%s", n, empty, m->name,
2619 m->isUseful ? ", useful" : empty);
2622 case TBLTYPE_TypeDef: {
2623 TBLTypeDef *t = (TBLTypeDef *)p->data;
2625 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
2626 t->isPdu ? ", isPDU" : empty);
2629 case TBLTYPE_Type: {
2630 TBLType *t = (TBLType *)p->data;
2631 const char *fn, *s = empty;
2634 /* typeId is a value from enum TBLTypeId */
2635 fn = TBLTYPE(t->typeId);
2636 if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
2637 t->optional ? " opt" : empty, s );
2641 TBLTag *t = (TBLTag *)p->data;
2642 const char *s = empty;
2643 if ((t->tclass == ASN1_UNI) && (t->code < 32))
2644 s = asn1_tag[t->code];
2645 if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
2646 tag_class[t->tclass], t->code, s);
2649 case TBLTYPE_NamedNumber: {
2650 TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
2651 if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
2652 nn->value, nn->name);
2655 case TBLTYPE_Range: {
2656 TBLRange *r = (TBLRange *)p->data;
2657 if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
2661 case TBLTYPE_TypeRef: {
2662 TBLTypeRef *r = (TBLTypeRef *)p->data;
2663 const char *s = empty;
2665 s = typeDef_names[r->typeDefId].name;
2666 if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
2667 r->typeDefId, s, r->implicit ? ", implicit" : empty );
2671 TBLTag *x = (TBLTag *)p->data;
2672 if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
2676 } else { /* just show tree */
2678 g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
2679 n, empty, p, p->data, p->next, p->prev, p->parent, p->children);
2684 showGNodes(GNode *p, int n)
2688 showGNodes(p->children, n+1);
2689 showGNodes(p->next, n);
2692 static void showGenv(GNode *p, int n, int m)
2698 if (asn1_verbose) g_message("%*s.....", n*2, empty);
2702 for(i=0; p && (i < 3); p = p->next, i++) {
2704 showGenv(p->children, n+1, m);
2706 if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
2711 debug_dump_TT(void) /* dump contents of TT struct, for debugging */
2714 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
2716 TT.totalNumTypeDefs,
2720 TT.totalLenStrings);
2724 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
2725 const gchar *message, gpointer user_data)
2727 static FILE* logf = 0;
2728 static char eol[] = "\r\n";
2730 (void) log_domain; (void) log_level; (void) user_data; /* make references */
2732 if (logf == NULL && asn1_logfile) {
2733 logf = eth_fopen(asn1_logfile, "w");
2736 fputs(message, logf);
2738 fflush(logf); /* debugging ... */
2743 read_asn1_type_table(const char *filename)
2750 if ((filename == 0) || (strlen(filename) == 0))
2751 return; /* no filename provided */
2753 f = eth_fopen(filename, "rb");
2756 * Ignore "file not found" errors if it's the old default
2757 * ASN.1 file name, as we never shipped such a file.
2758 * Also, on Win32, ignore the earlier default, which
2759 * had a "/" rather than a "\" as the last pathname
2762 if ((strcmp(filename, old_default_asn1_filename) != 0
2764 && strcmp(filename, bad_separator_old_default_asn1_filename) != 0
2766 ) || errno != ENOENT)
2767 report_open_failure(filename, errno, FALSE);
2770 fstat(fileno(f), &stat);
2771 size = (int)stat.st_size;
2773 if (asn1_verbose) g_message("file %s is empty, ignored", filename);
2777 if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
2779 data = g_malloc(size);
2780 if (fread(data, size, 1, f) < 1) {
2781 g_warning("error reading %s, %s", filename, strerror(errno));
2786 /* ***** from the time when logging was just in a console... *****
2787 * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
2788 * " Sleep 5 sec...");
2792 static guint mylogh = 0;
2794 g_message("logging to file %s", asn1_logfile);
2797 mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2798 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
2802 asn1_desc = tvb_new_real_data(data, size, size);
2805 if (asn1_verbose) g_message("read %d items from %s", icount, filename);
2813 g_node_destroy(asn1_nodes); asn1_nodes = 0;
2814 #ifndef _WIN32 /* tvb_free not yet exported to plugins... */
2815 tvb_free(asn1_desc);
2818 g_free(data); data = 0;
2820 showGNodes(data_nodes, 0);
2826 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
2827 g_warning("**** unexpected type %s, want %s, at line %d", \
2828 data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
2832 save_reference(PDUinfo *p)
2839 g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
2843 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex);
2847 /* evaluate typeref, pointer to current pdu node and typedef */
2849 tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
2852 PDUinfo *p = (PDUinfo *)pdu->data, *p1;
2856 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
2857 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
2861 CHECKTYPE(tree, TBLTYPE_TypeDef);
2863 if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
2864 p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2866 p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
2867 p->flags |= PDU_TYPEDEF;
2869 tree = g_node_first_child(tree); /* move to its underlying type */
2870 CHECKTYPE(tree, TBLTYPE_Type);
2871 p->type = ((TBLType *)tree->data)->typeId;
2873 q = g_node_first_child(tree); /* the tag of this type entry ... is optional... */
2874 if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
2875 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
2879 /* XXX -- hack -- hack -- hack -- hack -- hack --
2880 * only change tag when class+tag == EOC,
2881 * or class is a reference,
2882 * or new class is not universal.
2884 if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
2885 (((TBLTag *)q->data)->tclass != ASN1_UNI) ) {
2886 p->tclass = ((TBLTag *)q->data)->tclass;
2887 p->tag = ((TBLTag *)q->data)->code;
2889 g_message("%*s*change typeref tag from %c%d to %c%d",
2893 tag_class[p->tclass],
2897 g_message("%*sNOT changing tag from %c%d to %c%d",
2901 tag_class[((TBLTag *)q->data)->tclass],
2902 ((TBLTag *)q->data)->code);
2910 if (p->tclass==CLASSREF)
2911 g_snprintf(ss, 128, ", CLASSREF %d", p->tag);
2912 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
2914 if (p->tclass==CLASSREF) {
2916 int i = p->basetype;
2917 /* CLASSREF....., get it defined using type of the reference */
2919 /* p->basetype may be -1 .... ? XXX */
2922 tr = &typeDef_names[i];
2924 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
2925 p->tag, tr->name, tr->pdu);
2927 tbl_typeref(n+1, pdu, tr->type, fullindex);
2934 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
2935 p->name, p->typename, p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2939 case TBL_ENUMERATED:
2940 /* names do not have a fullname */
2941 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
2942 /* read the enumeration [save min-max somewhere ?] */
2943 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type]; /* XXX change field type... */
2945 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2950 g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2951 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2952 p->name, p->fullname,
2953 tbl_types_ethereal_txt[p->type], p->value_id);
2956 while((q = g_node_next_sibling(q))) {
2957 CHECKTYPE(q, TBLTYPE_NamedNumber);
2958 p = g_malloc0(sizeof(PDUinfo));
2960 p->type = TBL_ENUMERATED;
2961 p->name = (((TBLNamedNumber *)q->data)->name);
2962 p->tag = (((TBLNamedNumber *)q->data)->value);
2963 p->flags = PDU_NAMEDNUM;
2964 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
2965 g_node_append_data(pdu, p);
2968 /* list all enum values in the field structure for matching */
2969 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
2970 q = g_node_first_child(pdu);
2973 p = (PDUinfo *)q->data;
2974 v[nvals].value = p->tag;
2975 v[nvals].strptr = p->name;
2976 /* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
2978 q = g_node_next_sibling(q);
2980 /* last entry is already initialized to { 0, NULL } */
2985 if (p->value_id == -1) { /* not yet registered ..... */
2986 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
2987 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2992 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2993 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2994 p->name, p->fullname,
2995 tbl_types_ethereal_txt[p->type], p->value_id);
2997 tbl_type(n, pdu, q, fullindex);
3001 if (p->value_id == -1) { /* not yet registered ..... */
3002 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
3003 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3008 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3009 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3010 p->name, p->fullname,
3011 tbl_types_ethereal_txt[p->type], p->value_id);
3013 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
3018 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
3026 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
3027 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3031 /* showGenv(list, n, n+1); */
3034 pdu1 = pdu; /* save start location for append */
3035 while (list) { /* handle all entries */
3037 g_message("%*s+handle a %s, list=%p", n*2, empty,
3038 data_types[((TBLTag *)list->data)->type], list);
3040 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
3041 list = g_node_next_sibling(list);
3042 if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
3047 /******* change to positive comparation, but leave comment for reference
3048 * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3049 * CHECKTYPE(list, TBLTYPE_Type);
3052 if (((TBLTag *)list->data)->type == TBLTYPE_Type) {
3053 CHECKTYPE(list, TBLTYPE_Type);
3055 p = g_malloc0(sizeof(PDUinfo));
3056 pdu = g_node_append_data(pdu1, p);
3058 p->type = ((TBLType *)list->data)->typeId;
3059 p->typename = tbl_types_asn1[p->type]; /* the default type */
3062 p->basetype = ((PDUinfo *)pdu1->data)->typenum;
3063 p->flags = PDUinfo_initflags;
3064 p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
3065 p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
3067 if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
3068 /* assign an anonymous name [XXX refer to parent typename...] */
3069 ((TBLType *)list->data)->fieldName =
3070 g_strdup_printf("anon%d", anonCount++);
3072 p->name = ((TBLType *)list->data)->fieldName;
3075 ni += snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
3076 p->fullname = g_strdup(fieldname);
3078 /* initialize field info */
3081 p->value_hf.p_id = &(p->value_id);
3082 p->value_hf.hfinfo.name = p->fullname;
3083 p->value_hf.hfinfo.abbrev = p->fullname;
3084 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
3085 p->value_hf.hfinfo.display = BASE_DEC;
3086 p->value_hf.hfinfo.blurb = p->fullname;
3087 /* all the other fields are already 0 ! */
3089 if (p->type < TBL__SIMPLE) {
3090 /* only register fields with a value here, postpone others */
3091 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3096 g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3097 p->mytype, p->typenum, p->basetype, p->flags,
3098 p->typename, p->name, p->fullname,
3099 tbl_types_ethereal_txt[p->type], p->value_id);
3102 q = g_node_first_child(list);
3104 p = (PDUinfo *)pdu->data;
3109 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
3114 case TBL_OCTETSTRING:
3118 CHECKTYPE(q, TBLTYPE_Tag);
3119 p->tclass = ((TBLTag *)q->data)->tclass;
3120 p->tag = ((TBLTag *)q->data)->code;
3124 case TBL_ENUMERATED:
3125 CHECKTYPE(q, TBLTYPE_Tag);
3126 p->tclass = ((TBLTag *)q->data)->tclass;
3127 p->tag = ((TBLTag *)q->data)->code;
3128 if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
3129 /* read the enumeration [save min-max somewhere ?] */
3132 while((q = g_node_next_sibling(q))) {
3133 CHECKTYPE(q, TBLTYPE_NamedNumber);
3134 p = g_malloc0(sizeof(PDUinfo));
3136 p->type = TBL_ENUMERATED;
3137 p->name = (((TBLNamedNumber *)q->data)->name);
3138 p->tag = (((TBLNamedNumber *)q->data)->value);
3139 p->flags = PDU_NAMEDNUM;
3140 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3141 g_node_append_data(pdu, p);
3144 /* list all enum values in the field structure for matching */
3145 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3146 q = g_node_first_child(pdu);
3149 p = (PDUinfo *)q->data;
3150 v[nvals].value = p->tag;
3151 v[nvals].strptr = p->name;
3152 /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3154 q = g_node_next_sibling(q);
3156 /* last entry is already initialized to { 0, NULL } */
3162 case TBL_SEQUENCEOF:
3165 CHECKTYPE(q, TBLTYPE_Tag);
3166 q = g_node_first_child(list);
3167 tbl_type(n+1, pdu, q, ni);
3170 case TBL_TYPEREF: { /* may have a tag ... */
3173 if ( q && (((TBLTag *)q->data)->type == TBLTYPE_Tag)) {
3174 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3175 p->tclass = ((TBLTag *)q->data)->tclass;
3176 p->tag = ((TBLTag *)q->data)->code;
3178 g_message("%*s*insert type tag %c%d", n*2, empty,
3179 tag_class[p->tclass], p->tag);
3181 q = g_node_next_sibling(q);
3182 } else { /* use default tag for this type */
3183 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3184 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != ASN1_UNI)) ||
3185 ((p->tclass | p->tag) == 0 )) {
3186 /* not implicit, use this tag */
3187 p->tclass = tr->defclass;
3188 p->tag = tr->deftag;
3189 if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3190 tag_class[p->tclass], p->tag);
3193 CHECKTYPE(q, TBLTYPE_TypeRef);
3194 i = ((TBLTypeRef *)q->data)->typeDefId;
3196 tr = &typeDef_names[i];
3198 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, tr->pdu);
3199 p->typename = tr->name;
3201 if (tr->defclass == CLASSREF) {
3203 tr->pdu = pdu; /* remember this reference */
3205 tr = &typeDef_names[i];
3207 g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3208 i, tr->name, tr->pdu);
3210 /* evaluate reference if not done before or when below recursion limit */
3211 if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3214 tr->pdu = pdu; /* save for references we leave */
3216 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3218 g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3220 ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3223 tbl_typeref(n+1, pdu, tr->type, ni);
3227 g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3228 p->name, tr->name, tr->pdu);
3229 p->flags |= PDU_REFERENCE;
3230 p->reference = tr->pdu;
3235 g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3240 g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3241 n*2, empty, p->name, p->typename, p, TBLTYPE(p->type),
3242 tag_class[p->tclass], p->tag);
3244 if (p->value_id == -1) { /* not registered before, do it now */
3245 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3250 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3251 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3252 p->name, p->fullname,
3253 tbl_types_ethereal_txt[p->type], p->value_id);
3255 list = g_node_next_sibling(list);
3260 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
3263 const char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3266 tt = TBLTYPE(info->type);
3268 tn = info->typename;
3269 fn = info->fullname;
3270 if (info->flags & PDU_NAMEDNUM)
3271 txt += sprintf(txt, "name: %2d %s", info->tag, nn);
3273 if (info->flags & PDU_TYPEDEF)
3274 txt += sprintf(txt, "def %d: ", info->typenum);
3276 txt += sprintf(txt, " ");
3277 ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3278 txt += sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3279 tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3280 txt += sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
3281 oo = (info->flags & PDU_OPTIONAL) ? ", optional" : empty;
3282 ii = (info->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3283 nn = (info->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3284 an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3285 txt += sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
3286 if (info->flags & PDU_REFERENCE) {
3287 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3288 tt = TBLTYPE(rinfo->type);
3290 tn = rinfo->typename;
3291 fn = rinfo->fullname;
3292 txt += sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3293 if (rinfo->flags & PDU_TYPEDEF)
3294 txt += sprintf(txt, " T%d", rinfo->typenum);
3295 txt += sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3296 oo = (rinfo->flags & PDU_OPTIONAL) ? ", optional" : empty;
3297 ii = (rinfo->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3298 nn = (rinfo->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3299 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3300 tt = (rinfo->flags & PDU_TYPEDEF) ? ", typedef" : empty;
3301 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3302 tr = (rinfo->flags & PDU_TYPETREE) ? ", typetree" : empty;
3303 txt += sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3307 strcpy(txt, "no info available");
3315 showPDUtree(GNode *p, int n)
3321 info = (PDUinfo *)p->data;
3323 PDUtext(text, info);
3325 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3327 showPDUtree(g_node_first_child(p), n+1);
3329 p = g_node_next_sibling(p);
3336 build_pdu_tree(const char *pduname)
3339 guint pdudef, i, tcount;
3343 if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3346 if (asn1_verbose) g_message("no data nodes");
3351 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3353 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3354 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, sd.here, pdudef);
3356 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3360 /* If there's an existing PDU tree, free it */
3362 g_node_traverse(PDUtree, G_POST_ORDER, G_TRAVERSE_ALL, -1,
3363 free_node_data, NULL);
3364 g_node_destroy(PDUtree);
3367 /* initialize the PDU tree, hand craft the root entry */
3369 info = g_malloc0(sizeof(PDUinfo));
3370 info->name = pduname;
3371 info->typename = pduname;
3372 info->type = TBL_SEQUENCEOF;
3373 info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3374 info->flags = PDUinfo_initflags = 0;
3375 info->value_id = -1;
3377 info->basetype = -1;
3378 info->mytype = pdudef;
3380 info->value_hf.p_id = &(info->value_id);
3381 info->value_hf.hfinfo.name = info->fullname;
3382 info->value_hf.hfinfo.abbrev = info->fullname;
3383 info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
3384 info->value_hf.hfinfo.display = BASE_DEC;
3385 info->value_hf.hfinfo.blurb = info->fullname;
3387 anonCount = 0; /* anonymous types counter */
3389 PDUtree = g_node_new(info);
3390 pabbrev_pdu_len = sprintf(fieldname, "%s.%s.", pabbrev, pduname);
3391 sav_len = pabbrev_pdu_len;
3393 /* Now build the tree for this top level PDU */
3395 g_message("******** Define main type %d, %s", pdudef, pduname);
3396 tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1); /* strip initial . for new names */
3399 g_message("%d anonymous types", anonCount);
3401 /* Now make all types used available for matching */
3403 g_message("Define the types that are actually referenced through the top level PDU");
3404 for (i=0, tcount=0; i<numTypedefs; i++) {
3405 TypeRef *tr = &(typeDef_names[i]);
3407 if (tr->pdu) { /* ignore if not used in main pdu */
3410 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3412 g_message("******** Define type %d, %s", i, tr->name);
3414 /* .... do definition ..... */
3415 info = g_malloc0(sizeof(PDUinfo));
3416 info->name = tr->name;
3417 info->typename = tr->name;
3418 info->tclass = tr->defclass;
3419 info->tag = tr->deftag;
3420 info->type = TBL_TYPEREF;
3421 info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3422 info->flags = PDUinfo_initflags = PDU_TYPETREE;
3423 info->value_id = -1;
3425 info->basetype = -1;
3428 info->value_hf.p_id = &(info->value_id);
3429 info->value_hf.hfinfo.name = info->fullname;
3430 info->value_hf.hfinfo.abbrev = info->fullname;
3431 info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
3432 info->value_hf.hfinfo.display = BASE_DEC;
3433 info->value_hf.hfinfo.blurb = info->fullname;
3435 tr->typetree = g_node_new(info);
3436 pabbrev_pdu_len = sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
3437 tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3441 g_message("%d types used", tcount);
3443 pabbrev_pdu_len = sav_len;
3445 /* and show the result */
3447 g_message("Type index:");
3448 for (i=0; i<numTypedefs; i++) {
3449 TypeRef *tr = &(typeDef_names[i]);
3455 if (tr->pdu == 0) /* skip if not used */
3459 g_message(" %3d %s, %c%d, refs: %d",
3460 i, tr->name, tag_class[tr->defclass], tr->deftag,
3461 g_ptr_array_len(tr->refs));
3463 /* get defining node for this type */
3466 p = (PDUinfo *)(tr->typetree->data);
3467 defid = p->value_id;
3469 g_message(" -- defining id=%d", defid);
3471 for(j=0; j < g_ptr_array_len(tr->refs); j++) { /* show refs, and set type_id */
3472 p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3473 if (p->mytype == (gint)i)
3474 p->type_id = defid; /* normal reference */
3476 if ((p->flags & PDU_TYPETREE) == 0) {
3477 /* we have a primitive value, find its real type */
3478 for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3479 /* look at all refs */
3480 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3481 if ((q->flags & PDU_TYPETREE) == 0)
3482 continue; /* only type trees are interresting */
3483 if (q->type != p->type)
3484 continue; /* must be same types */
3485 if (strcmp(q->name, p->name) == 0) {
3486 /* OK, take the first we find, not entirely
3487 * correct, it may be from a different
3488 * base-base type...... XXX */
3489 p->type_id = q->value_id;
3498 g_message(" %s", text);
3504 g_message("The resulting PDU tree:");
3505 showPDUtree(PDUtree, 0);
3511 #ifdef DISSECTOR_WITH_GUI
3512 /* This cannot work in tethereal.... don't include for now */
3513 #if GTK_MAJOR_VERSION >= 2
3514 #define SHOWPDU /* this needs GTK2 */
3516 #endif /* DISSECTOR_WITH_GUI */
3519 static GtkWidget *window = NULL;
3521 /* the columns in the tree view */
3524 TITLE_COLUMN, /* text in this row */
3525 DEF_COLUMN, /* definition in this row, if any */
3526 REF_COLUMN, /* referennce from this column, if any */
3527 VALUE_COLUMN, /* indicate this is a value */
3528 NAME_COLUMN, /* name of this row */
3532 static FILE *namelist = 0;
3535 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3538 PDUinfo *info, *rinfo;
3545 info = (PDUinfo *)p->data;
3547 gtk_tree_store_append (store, &iter2, iter); /* Acquire iterator */
3549 PDUtext(text, info);
3552 if (info->flags & PDU_TYPEDEF)
3553 def = info->typenum;
3555 if (info->flags & PDU_REFERENCE) {
3556 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3557 ref = rinfo->typenum;
3559 pb = GTK_STOCK_CANCEL;
3560 if (G_NODE_IS_LEAF(p)) {
3561 if (info->flags & PDU_NAMEDNUM)
3562 pb = GTK_STOCK_BOLD;
3566 fprintf(namelist, "%16s %s\n",
3567 &(TBLTYPE(info->type)[4]), info->fullname);
3570 switch (info->type) {
3571 case TBL_ENUMERATED:
3575 fprintf(namelist, "%16s %s\n",
3576 &(TBLTYPE(info->type)[4]), info->fullname);
3583 gtk_tree_store_set (store, &iter2,
3588 NAME_COLUMN, info->fullname,
3591 build_tree_view(store, g_node_first_child(p), &iter2);
3593 p = g_node_next_sibling(p);
3605 #define PATHSTACKMAX 10
3606 static GtkTreePath *pathstack[PATHSTACKMAX];
3607 static gint pathstackp = 0;
3609 static void add_path(GtkTreePath *p)
3611 if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
3612 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
3613 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
3616 pathstack[pathstackp++] = p;
3619 static GtkTreePath *pop_path(void)
3622 return pathstack[--pathstackp];
3627 find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
3631 struct DefFind *df = (struct DefFind *)data;
3633 gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
3635 if (def == df->def) {
3636 df->path = gtk_tree_path_copy (path);
3644 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
3647 GtkTreePath *path, *path2;
3648 gchar *text, *oldpath, *newpath;
3654 path = gtk_tree_path_copy (spath);
3656 gtk_tree_model_get_iter (model, &iter, path);
3657 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
3659 oldpath = gtk_tree_path_to_string(path);
3660 path2 = gtk_tree_path_copy (path);
3662 add_path(gtk_tree_path_copy(path));
3664 if (ref != -1) { /* this is a reference, find matching definition */
3667 gtk_tree_model_foreach (model, find_definition, &df);
3669 gtk_tree_path_free(path);
3672 } else { /* just move to the next entry, if it exists */
3673 gtk_tree_path_next(path2);
3675 if (gtk_tree_model_get_iter (model, &iter, path2)) {
3676 gtk_tree_path_free(path);
3677 path = path2; /* OK */
3679 if (gtk_tree_path_get_depth (path) > 1)
3680 gtk_tree_path_up (path);
3685 gtk_tree_path_free (path2);
3687 gtk_tree_view_expand_to_path (treeview, path);
3688 gtk_tree_view_expand_row (treeview, path, FALSE);
3690 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3692 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3694 newpath = gtk_tree_path_to_string(path);
3697 g_message("my_signal_handler: treeview=%p, moveing from %s to %s",
3698 treeview, oldpath, newpath);
3704 /* gtk_tree_path_free(df.path); */
3709 menuitem_cb (gpointer callback_data,
3710 guint callback_action,
3714 GtkTreeModel *model;
3715 GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
3716 GtkTreeSelection *selection;
3721 gchar *oldpath, *newpath;
3722 GtkTreeViewColumn *focus_column;
3724 selection = gtk_tree_view_get_selection(treeview);
3726 model = gtk_tree_view_get_model(treeview);
3727 gtk_tree_view_get_cursor (treeview, &path, &focus_column);
3729 if (gtk_tree_model_get_iter (model, &iter, path)) {
3731 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
3732 NAME_COLUMN, &name, -1);
3733 oldpath = gtk_tree_path_to_string(path);
3736 switch (callback_action) {
3737 case 0: /* Select */
3738 gtk_tree_selection_select_path (selection, path);
3743 gtk_tree_view_expand_to_path (treeview, path);
3744 gtk_tree_view_expand_row (treeview, path, FALSE);
3746 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3748 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3750 newpath = gtk_tree_path_to_string(path);
3752 gtk_tree_path_free(path);
3754 newpath = g_strdup("** no path **");
3756 g_message("menueitem_cb: treeview=%p, moveing from %s to %s",
3757 treeview, oldpath, newpath);
3761 /* get all non anonymous names to the root */
3764 dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
3765 GTK_DIALOG_DESTROY_WITH_PARENT,
3768 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
3769 gtk_item_factory_path_from_widget (widget),
3770 callback_action, text, oldpath, newpath, name);
3772 /* Close dialog on user response */
3773 g_signal_connect (dialog,
3775 G_CALLBACK (gtk_widget_destroy),
3778 gtk_widget_show (dialog);
3783 if (newpath != empty)
3787 g_message("menuitem_cb: no iterator...");
3790 static GtkItemFactoryEntry menu_items[] = {
3791 { "/Select", NULL, menuitem_cb, 0, NULL, 0 },
3792 { "/Back", "<control>B", menuitem_cb, 1, NULL, 0 },
3793 { "/Find", "<control>F", menuitem_cb, 2, NULL, 0 },
3794 { "/Save", "<control>S", menuitem_cb, 3, NULL, 0 },
3797 static gint button_press_callback( GtkWidget *widget,
3798 GdkEventButton *event,
3801 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
3803 /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
3804 * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
3807 if (event->button == 3) {
3808 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
3815 return FALSE; /* continue handling this event */
3820 create_message_window(void)
3822 GtkCellRenderer *renderer;
3823 GtkTreeStore *model;
3826 GtkWidget *treeview;
3828 GtkItemFactory *item_factory;
3829 GtkAccelGroup *accel_group;
3830 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3834 /* create window, etc */
3835 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3836 gtk_window_set_title (GTK_WINDOW (window), current_pduname);
3837 g_signal_connect (window, "destroy",
3838 G_CALLBACK (gtk_widget_destroyed), &window);
3840 vbox = gtk_vbox_new (FALSE, 8);
3841 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3842 gtk_container_add (GTK_CONTAINER (window), vbox);
3844 text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
3846 gtk_box_pack_start (GTK_BOX (vbox),
3847 gtk_label_new (text),
3851 sw = gtk_scrolled_window_new (NULL, NULL);
3852 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
3853 GTK_SHADOW_ETCHED_IN);
3854 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
3855 GTK_POLICY_AUTOMATIC,
3856 GTK_POLICY_AUTOMATIC);
3857 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3859 model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3860 G_TYPE_STRING, G_TYPE_STRING);
3862 namelist = eth_fopen("namelist.txt", "w");
3863 build_tree_view(model, PDUtree, NULL);
3867 /* create tree view */
3868 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
3869 g_object_unref (model);
3870 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
3871 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
3872 GTK_SELECTION_MULTIPLE);
3874 renderer = gtk_cell_renderer_text_new ();
3876 #if 0 /* testing pango attributes */
3879 PangoAttrList* attr;
3881 attr = pango_attr_list_new();
3882 bg = pango_attr_background_new(50000,55000,50000);
3883 bg->start_index = 0;
3884 bg->end_index = 10000;
3885 pango_attr_list_insert(attr, bg);
3887 g_object_set(renderer, "attributes", attr, NULL);
3889 #endif /* testing pango attributes */
3891 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3892 TITLE_COLUMN, "asn1 entities", renderer,
3893 "text", TITLE_COLUMN, NULL );
3895 /* renderer = gtk_cell_renderer_text_new ();
3896 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3897 * DEF_COLUMN, "type definition", renderer,
3898 * "text", DEF_COLUMN, NULL );
3900 * renderer = gtk_cell_renderer_text_new ();
3901 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3902 * REF_COLUMN, "reference", renderer,
3903 * "text", REF_COLUMN, NULL );
3905 renderer = gtk_cell_renderer_pixbuf_new ();
3906 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3907 VALUE_COLUMN, "value", renderer,
3908 "stock_id", VALUE_COLUMN, NULL );
3910 renderer = gtk_cell_renderer_text_new ();
3911 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3912 NAME_COLUMN, "fieldname", renderer,
3913 "text", NAME_COLUMN, NULL );
3915 gtk_container_add (GTK_CONTAINER (sw), treeview);
3917 /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
3921 accel_group = gtk_accel_group_new ();
3923 /* This function initializes the item factory.
3924 * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
3925 * or GTK_TYPE_OPTION_MENU.
3926 * Param 2: The path of the menu.
3927 * Param 3: A pointer to a gtk_accel_group. The item factory sets up
3928 * the accelerator table while generating menus.
3931 item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
3933 /* This function generates the menu items. Pass the item factory,
3934 the number of items in the array, the array itself, and any
3935 callback data for the the menu items. */
3936 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
3938 /* Attach the new accelerator group to the window. */
3939 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
3942 /* expand all rows after the treeview widget has been realized */
3943 g_signal_connect (treeview, "realize",
3944 G_CALLBACK (gtk_tree_view_expand_all), NULL);
3945 g_signal_connect (treeview, "row-activated",
3946 G_CALLBACK (my_signal_handler), (gpointer)model);
3948 g_signal_connect (treeview, "button_press_event",
3949 G_CALLBACK (button_press_callback), item_factory);
3951 /* g_signal_connect_swapped (treeview, "event",
3952 * G_CALLBACK (button_press_handler),
3955 gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
3958 if (!GTK_WIDGET_VISIBLE (window))
3959 gtk_widget_show_all (window);
3962 gtk_widget_destroy (window);
3966 #endif /* SHOWPDU */
3968 /************************************************************************************************
3969 * routines to find names to go with the decoded data stream *
3970 ************************************************************************************************/
3971 typedef struct _statestack statestack;
3972 static struct _statestack {
3978 static gint PDUstatec = 0;
3980 #define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
3981 #define STORENODE(x) { PDUstate[PDUstatec-1] = (x); }
3982 #define POPSTATE PDUstate[--PDUstatec]
3983 #define GETSTATE PDUstate[PDUstatec-1]
3984 #define GETNAME (((PDUinfo *)pos.node->data)->name)
3985 #define TYPENAME (((PDUinfo *)pos.node->data)->typename)
3986 #define GETTYPE (((PDUinfo *)pos.node->data)->type & TBL_TYPEmask)
3987 #define GETFLAGS (((PDUinfo *)pos.node->data)->flags)
3988 #define GETINFO ((PDUinfo *)pos.node->data)
3989 #define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
3990 #define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
3991 #define MATCH ((class == info->tclass) && (tag == info->tag))
3992 #define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
3993 #define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
3994 #define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
3995 #define ISCHOICE (info && (info->flags & PDU_CHOICE))
3996 #define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
3999 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
4000 pos.node=0;PUSHNODE(pos);return ret;}}
4004 showstack(statestack *pos, char *txt, int n)
4007 const char *name, *type, *stype;
4008 const char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
4014 if ( ! asn1_verbose)
4020 g_message("==underflow");
4023 rep = chs = done = ref = pop = chr = rch = sch = con = empty;
4027 name = ((PDUinfo *)g->data)->name;
4028 type = TBLTYPE(((PDUinfo *)g->data)->type);
4030 name = "node<null>";
4034 stype = TBLTYPE(typef);
4035 if (typef & TBL_REPEAT) rep = "[repeat]";
4036 if (typef & TBL_CHOICE_made) chs = "[choice]";
4037 if (typef & TBL_SEQUENCE_done) done = "[done]";
4038 if (typef & TBL_REFERENCE) ref = "[ref]";
4039 if (typef & TBL_REFERENCE_pop) pop = "[ref-pop]";
4040 if (typef & TBL_CHOICE_repeat) chr = "[chs-rep]";
4041 if (typef & TBL_REPEAT_choice) rch = "[rep-chs]";
4042 if (typef & TBL_SEQUENCE_choice)sch = "[seq-chs]";
4043 if (typef & TBL_CONSTRUCTED) con = "[constr]";
4045 i = sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
4046 pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4047 pos->name, pos->offset);
4049 for(j=1, n--; n>0; j++, n--) {
4050 p = &PDUstate[PDUstatec-j];
4052 stype = TBLTYPE(typef);
4053 rep = (typef & TBL_REPEAT) ? "[repeat]" : empty;
4054 chs = (typef & TBL_CHOICE_made) ? "[choice]" : empty;
4055 done = (typef & TBL_SEQUENCE_done) ? "[done]" : empty;
4056 ref = (typef & TBL_REFERENCE) ? "[ref]" : empty;
4057 pop = (typef & TBL_REFERENCE_pop) ? "[ref-pop]" : empty;
4058 chr = (typef & TBL_CHOICE_repeat) ? "[chs-rep]" : empty;
4059 rch = (typef & TBL_REPEAT_choice) ? "[rep-chs]" : empty;
4060 sch = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
4061 con = (typef & TBL_CONSTRUCTED) ? "[constr]" : empty;
4063 i += sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
4064 p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4065 p->name, p->offset);
4071 showrefNode(GNode *node, int n)
4073 const char *name = empty, *type = empty, *tname = empty;
4074 int cls = 0, tag = 0;
4079 g_message("%*sstop, nesting too deep", 2*n, empty);
4083 info = (PDUinfo *)(node->data);
4084 type = TBLTYPE(info->type);
4086 tname = info->typename;
4087 ref = info->reference;
4091 g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4092 2*n, empty, tname, type, name, node, node->data,
4093 ref, tag_class[cls], tag);
4096 showrefNode(ref, n+1);
4100 showNode(GNode *node, int n, int m)
4102 const char *name = empty, *type = empty;
4109 type = TBLTYPE(((PDUinfo *)(node->data))->type);
4110 name = ((PDUinfo *)(node->data))->name;
4111 ref = ((PDUinfo *)(node->data))->reference;
4113 g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4114 2*n, empty, type, name, node, node->data, node->next, node->prev,
4115 node->parent, node->children);
4118 g_message("%*sstop, nesting too deep", 2*n, empty);
4122 if (ref) showrefNode(ref, n+2);
4124 if (node->children) showNode(node->children, n+1, m);
4125 if (node->next) showNode(node->next, n, m);
4129 PDUreset(int count, int count2)
4133 if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
4135 PDUstatec = 0; /* stackpointer */
4136 PDUerrcount = 0; /* error counter per asn.1 message */
4138 pos.node = 0; /* sentinel */
4139 pos.name = "sentinel";
4140 pos.type = TBL_SEQUENCEOF;
4145 pos.node = PDUtree; /* root of the tree */
4147 pos.type = GETTYPE | TBL_REPEAT;
4153 static GNode * /* find GNode for a choice element, 0 if none */
4154 makechoice(GNode *p, guint class, guint tag)
4159 p = g_node_first_child(p); /* the list of choices */
4160 info = 0; /* avoid gcc warning */
4163 info = ((PDUinfo *)p->data);
4165 if (info->type == TBL_CHOICE) {
4167 g_message(" using sub choice (%s)%s", info->typename, info->name);
4169 q = makechoice(p, class, tag);
4170 if (q) { /* found it */
4172 info = ((PDUinfo *)p->data);
4174 } /* continue with this level */
4178 g_message(" have %c%d, found %c%d, %s", tag_class[class], tag,
4179 tag_class[info->tclass], info->tag, info->name);
4181 if ((class == info->tclass) && (tag == info->tag))
4182 break; /* found it */
4185 p = g_node_next_sibling(p);
4188 if (p) g_message(" OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
4190 else g_message(" ...no matching choice...");
4195 /* offset is for debugging only, a reference to output on screen */
4197 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
4199 statestack pos, pos2, save_pos;
4201 const char *ret, *tmp;
4202 int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4203 static char namestr[64]; /* enough ? */
4204 static char posstr[40];
4205 static char noname[] = "*noname*";
4206 static PDUprops constructed_save; /* for unexpectedly constructed enteties */
4208 if (PDUstatec > 0) /* don't read from below the stack */
4210 /* pos refers to the last asn1 node handled */
4212 /* a very simple, too simple??, way to handle constructed entities */
4213 if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4214 /* unexpectedly constructed, return same info as last time */
4215 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4216 showstack(&pos, posstr, 3);
4217 pos.offset = offset;
4218 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4219 PUSHNODE(pos); /* push extra, to match with a EOI operation */
4220 PUSHNODE(pos); /* restore the stack */
4221 *out = constructed_save;
4223 g_message(" return for constructed %s (%s)%s",
4224 TBLTYPE(out->type), out->typename, out->name);
4228 save_pos = pos; /* may need it again */
4232 out->typename = "*error*";
4239 if (PDUstatec <= 0) {
4240 if (PDUstatec > -10) {
4242 g_message(">>off=%d stack underflow, return", offset);
4244 if (PDUstatec == -10) {
4246 g_message(">>off=%d stack underflow, return, no more messages", offset);
4248 out->name = "*underflow*";
4249 out->flags |= OUT_FLAG_noname;
4253 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4255 showstack(&pos, posstr, 3);
4259 if (class == ASN1_EOI) { /* end of this input sequence */
4261 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4262 if (asn1_verbose) g_message(" EOI: reference pop");
4265 switch(pos.type & TBL_TYPEmask) {
4267 if (asn1_verbose) g_message(" EOI: pop typeref");
4268 pos = POPSTATE; /* remove typeref */
4270 case TBL_CHOICE_done:
4271 if (asn1_verbose) g_message(" EOI: mark choice");
4273 pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4281 pos = POPSTATE; /* this is pushed back on the stack later */
4282 if (pos.node == 0) {
4283 if (asn1_verbose) g_message(" EOI, pos.node == 0");
4284 out->name = "*no-name-EOI*";
4285 out->flags |= OUT_FLAG_noname;
4292 tmp = TBLTYPE(info->type);
4293 if (offset != pos.offset) {
4295 g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4296 tmp, ret, offset, pos.offset);
4297 while ((offset < pos.offset) && (PDUstatec > 0)) {
4300 g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
4301 offset, pos.offset);
4303 if (offset != pos.offset)
4304 PDUerrcount++; /* only count if still unequal */
4306 if (asn1_verbose) g_message(" EOI %s:%s OK, offset=%d", tmp, ret, offset);
4309 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4310 * indicated by the synthetic EOI call. */
4311 if ((class == ASN1_UNI) && (tag == ASN1_EOC)) { /* explicit EOC never has a name */
4312 PUSHNODE(pos); /* restore stack */
4313 ret = "explicit-EOC";
4314 if (asn1_verbose) g_message(" return '%s', ignore", ret);
4316 out->typename = "ASN1";
4320 /* find appropriate node for this tag */
4322 if (pos.node == 0) {
4323 if (asn1_verbose) g_message(" pos.node == 0");
4324 out->name = "*no-name*";
4325 out->flags |= OUT_FLAG_noname;
4330 /* showNode(pos.node, 3, 4); */
4332 switch (pos.type & TBL_TYPEmask) {
4333 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4337 if (pos.type & TBL_CHOICE_made) {
4338 if (asn1_verbose) g_message(" finish choice");
4346 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4347 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4349 if (asn1_verbose) g_message(" repeating choice"); /* ignore repeat */
4352 if (asn1_verbose) g_message(" seqof: repeat start");
4353 /* decide how to continue, CHILD for next instance of sequence
4354 * or NEXT for end of repeated sequence.
4355 * use the tag to make a descision */
4356 if (asn1_verbose) g_message(" seqof: first got %c%d, found %c%d",
4357 tag_class[class], tag,
4358 tag_class[info->tclass], info->tag);
4360 /* This is the start of repeating */
4363 if (asn1_verbose) g_message(" return for repeat '%s'", ret);
4364 out->type = (pos.type & TBL_TYPEmask);
4365 out->typename = info->typename;
4367 out->value_id = info->value_id;
4368 out->type_id = info->type_id;
4370 if (asn1_verbose) g_message(" anonymous: dontshow");
4372 out->flags |= OUT_FLAG_dontshow;
4378 /* find out where to go .... */
4380 CHILD; /* assume sequence is repeated */
4382 info = GETINFO; /* needed for MATCH to look ahead */
4384 g_message(" seqof: child: got %c%d, found %c%d",
4385 tag_class[class], tag,
4386 tag_class[info->tclass], info->tag);
4388 if (pos2.type & TBL_CHOICE_repeat) {
4391 g_message(" repeating a choice, %s",
4393 pos.type = TBL_CHOICE_immediate;
4395 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4396 donext = 1; /* move on */
4398 g_message(" seqof: no repeat, force next");
4400 /* following code will take the child again */
4406 } else if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4407 if (asn1_verbose) g_message(" reference pop, donext");
4410 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4411 if (pos.type & TBL_SEQUENCE_choice) {
4412 pos = POPSTATE; /* expect to find a repeat here */
4415 if (asn1_verbose) g_message(" sequence done, donext");
4419 if (pos.type & TBL_REFERENCE) {
4420 if (asn1_verbose) g_message(" reference change ref -> pop");
4421 pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4424 pos.offset = offset;
4426 ret = pos.name; /* for the debug messages */
4429 if (asn1_verbose) g_message(" donext");
4432 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4433 case TBL_SETOF: /* ?? */
4434 case TBL_SEQUENCEOF:
4435 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4436 pos.type |= TBL_REPEAT;
4440 /* remember this is the start of a repeat cycle */
4441 typeflags |= TBL_REPEAT;
4443 g_message(" seqof: set repeat mark [push,child]");
4446 g_message(" seqof: end of reapeat loop [next]");
4450 case TBL_SET: /* ?? */
4452 pos.type |= TBL_SEQUENCE_done;
4456 if (asn1_verbose) g_message(" seq [push,child]");
4459 /* no more choice */
4460 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4463 pos.type = 0; /* clear all type flags */
4465 g_message(" choice [push], %c%d, %s",
4466 tag_class[info->tclass], info->tag, GETNAME);
4467 pos.node = makechoice(pos.node, class, tag);
4468 if (pos.node == 0) {
4470 out->flags |= OUT_FLAG_noname;
4477 g_message(" '%s' %c%d will be used",
4478 ret, tag_class[info->tclass], info->tag);
4480 case TBL_CHOICE_done:
4486 if (asn1_verbose) g_message(" typeref [pop,next]");
4488 case TBL_ENUMERATED:
4490 /* skip named numbers now, call to PDUenum() will retrieve a name */
4493 case TBL_CHOICE_immediate:
4494 if (asn1_verbose) g_message(" immediate choice [no next]");
4503 if (pos.node == 0) {
4504 ret = "*no-name-2*";
4505 if (asn1_verbose) g_message(" return '%s'", ret);
4507 out->flags |= OUT_FLAG_noname;
4511 ret = pos.name = GETNAME;
4512 pos.type = GETTYPE | (pos.type & ~TBL_TYPEmask);
4515 /* pos now points to the prospective current node, go check it ********************/
4516 if (asn1_verbose) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4517 (ISOPTIONAL)?", optional":empty,
4518 (ISIMPLICIT)?", implicit":empty,
4519 tag_class[info->tclass], info->tag );
4521 if (ISOPTIONAL) { /* must check the tag */
4522 while(! MATCH) { /* check optional here again...? */
4524 g_message(" got %c%d, found %c%d", tag_class[class], tag,
4525 tag_class[info->tclass], info->tag);
4527 if (pos.node == 0) {
4530 pos = save_pos; /* reset for next time */
4531 pos.type |= TBL_SEQUENCE_done;
4533 pos.type &= ~TBL_SEQUENCE_done;
4535 out->flags |= OUT_FLAG_dontshow;
4537 g_message(" end of optional list, constructed, expect value next time");
4540 out->flags |= OUT_FLAG_noname;
4542 g_message(" *end of optional list...");
4543 info = 0; /* this is not valid any more... */
4545 break; /* end of list */
4548 if (asn1_verbose) g_message(" optional, %s", GETNAME);
4550 if (pos.node && ! cons_handled) {
4551 ret = pos.name = GETNAME;
4554 /* pos now refers to node with name we want, optional nodes skipped */
4557 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4558 pos2 = pos; /* save current state */
4562 g_message(" already pushed, skip next push");
4564 typeflags &= ~TBL_CHOICE_made;
4568 g_message(" immediate choice [push], %c%d, %s",
4569 tag_class[info->tclass], info->tag, GETNAME);
4570 pos.node = makechoice(pos.node, class, tag);
4571 if (pos.node == 0) {
4577 out->type = (pos.type & TBL_TYPEmask);
4578 out->flags |= OUT_FLAG_type;
4580 sprintf(namestr, "%s!%s", ret, GETNAME);
4583 g_message(" %s:%s will be used", TBLTYPE(pos.type), ret);
4584 if (typeflags & TBL_REPEAT) {
4585 pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
4587 pos.type |= TBL_SEQUENCE_choice;
4590 g_message(" return from immediate choice [%s] '%s'",
4591 TBLTYPE(pos.type), ret);
4593 out->data = pos.node; /* for access to named numbers... */
4595 out->type = (pos.type & TBL_TYPEmask);
4598 out->typename = info->typename;
4599 out->fullname = info->fullname;
4600 out->value_id = info->value_id;
4601 out->type_id = info->type_id;
4606 typeflags |= TBL_CHOICE_made;
4609 if (asn1_verbose) g_message(" matching choice '%s'", ret);
4611 if ( ! cons ) { /* ISIMPLICIT was not OK for all */
4612 pos = pos2; /* reset for continuation */
4617 g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4618 (ISOPTIONAL)?", optional":empty,
4619 (ISIMPLICIT)?", implicit":empty,
4620 tag_class[info->tclass], info->tag );
4622 g_message(" using: unknown '%s'", ret);
4625 /* must follow references now */
4626 if (pos.type == TBL_TYPEREF) {
4627 out->typename = info->typename;
4628 out->type_id = info->typenum;
4629 out->flags |= OUT_FLAG_typename;
4631 PUSHNODE(pos); /* remember where we were */
4632 if (asn1_verbose) g_message(" typeref [push]");
4633 typeflags |= TBL_REFERENCE;
4634 if (info->reference == 0) { /* resolved ref to universal type.... */
4635 /* showNode(pos.node, 3, 4); */
4636 pos.type = GETTYPE; /* the resulting type */
4638 tmp = "inknown tag";
4639 if ((info->tclass == ASN1_UNI) && (info->tag < 31)) {
4640 tmp = asn1_tag[info->tag];
4641 pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
4644 g_message(" indirect typeref to %s:%s, %s [%c%d]",
4645 TBLTYPE(pos.type), info->typename, tmp,
4646 tag_class[info->tclass], info->tag );
4648 out->fullname = info->fullname;
4649 donext = (ISANONYMOUS); /* refereing entity has no name ? */
4650 pos.node = info->reference;
4654 g_message(" typeref %s %s", TBLTYPE(pos.type), GETNAME);
4655 /* keep name from before going through the reference, unless anonymous */
4656 if (donext) /* refering entity has no name */
4657 ret = GETNAME; /* a better name */
4659 /* handle choice here ? !!mm!! */
4661 out->type = (pos.type & TBL_TYPEmask);
4662 out->flags |= OUT_FLAG_type;
4663 /* showNode(pos.node, 3, 4); */
4666 out->data = pos.node;
4667 out->flags |= OUT_FLAG_data;
4669 g_message(" typeref set named number list node %p", pos.node);
4673 pos.type = TBL_TYPEREF_nopop;
4674 if (asn1_verbose) g_message(" typeref pop");
4675 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
4676 /* do not enter the named-number list */
4678 pos.type = TBL_TYPEREF_nopop;
4679 if (asn1_verbose) g_message(" typeref [pop]");
4681 typeflags |= TBL_REFERENCE;
4686 if (cons && ! cons_handled) { /* This entity is constructed, expected ? */
4688 case TBL_BOOLEAN: /* these are not expected to be constructed */
4690 case TBL_OCTETSTRING:
4694 case TBL_ENUMERATED:
4696 typeflags |= TBL_CONSTRUCTED;
4697 /* this entry has no extra info, next is the same */
4698 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
4699 if (asn1_verbose) g_message(" dontshow and set constructed flag");
4701 default: /* others, such as sequences, are expected to be constructed */
4708 if (asn1_verbose) g_message(" anonymous: dontshow");
4709 if (asn1_debug) /* this entry has no extra info, next is the same */
4710 out->flags |= OUT_FLAG_dontshow;
4712 out->name = empty; /* show it, but no name */
4715 if (out->name != empty)
4718 if ( ! (out->flags & OUT_FLAG_data))
4719 out->data = pos.node; /* for access to named numbers... */
4721 pos.type |= typeflags;
4724 if ( ! (out->flags & OUT_FLAG_type))
4725 out->type = pos.type;
4727 out->type &= TBL_TYPEmask;
4729 if (ret == noname) {
4731 out->flags |= OUT_FLAG_noname;
4734 if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
4735 out->typename = info->typename;
4736 out->type_id = info->typenum;
4739 if (info && (out->value_id == -1)) {
4740 out->value_id = info->value_id;
4741 out->type_id = info->type_id;
4744 if ((out->fullname == 0) && info)
4745 out->fullname = info->fullname;
4747 if (typeflags & TBL_CONSTRUCTED)
4748 constructed_save = *out;
4751 g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
4752 out->value_id, out->type_id);
4758 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
4762 const char *ret, *name;
4763 static char unnamed[] = "*unnamed*";
4765 (void) cls; (void) tag; /* make a reference */
4767 if (props->flags & OUT_FLAG_noname)
4771 list = (GNode *)props->data;
4774 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
4776 return "*list-still-0*";
4779 if ((PDUinfo *)list->data)
4780 name = ((PDUinfo *)list->data)->name;
4784 for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
4785 info = (PDUinfo *)list->data;
4786 if (value == info->tag) {
4795 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
4799 #endif /* READSYNTAX */
4802 proto_register_asn1(void) {
4804 static const enum_val_t type_recursion_opts[] = {
4818 static gint *ett[1+MAX_NEST+MAXPDU];
4822 module_t *asn1_module;
4825 asn1_logfile = get_tempfile_path(ASN1LOGFILE);
4827 current_asn1 = g_strdup("");
4828 asn1_filename = g_strdup(current_asn1);
4830 current_pduname = g_strdup("ASN1");
4831 asn1_pduname = g_strdup(current_pduname);
4833 proto_asn1 = proto_register_protocol("ASN.1 decoding",
4837 for (i=0, j=1; i<MAX_NEST; i++, j++) {
4838 ett[j] = &ett_seq[i];
4841 for(i=0; i<MAXPDU; i++, j++) {
4842 ett[j] = &ett_pdu[i];
4846 proto_register_subtree_array(ett, array_length(ett));
4848 asn1_module = prefs_register_protocol(proto_asn1,
4849 proto_reg_handoff_asn1);
4850 #ifdef JUST_ONE_PORT
4851 prefs_register_uint_preference(asn1_module, "tcp_port",
4853 "The TCP port on which "
4854 "ASN.1 messages will be read",
4855 10, &global_tcp_port_asn1);
4856 prefs_register_uint_preference(asn1_module, "udp_port",
4858 "The UDP port on which "
4859 "ASN.1 messages will be read",
4860 10, &global_udp_port_asn1);
4861 prefs_register_uint_preference(asn1_module, "sctp_port",
4863 "The SCTP port on which "
4864 "ASN.1 messages will be read",
4865 10, &global_sctp_port_asn1);
4867 g_snprintf(tmpstr, sizeof(tmpstr), "%u", TCP_PORT_ASN1);
4868 range_convert_str(&global_tcp_ports_asn1, tmpstr, 65535);
4870 g_snprintf(tmpstr, sizeof(tmpstr), "%u", UDP_PORT_ASN1);
4871 range_convert_str(&global_udp_ports_asn1, tmpstr, 65535);
4873 g_snprintf(tmpstr, sizeof(tmpstr), "%u", SCTP_PORT_ASN1);
4874 range_convert_str(&global_sctp_ports_asn1, tmpstr, 65535);
4876 prefs_register_range_preference(asn1_module, "tcp_ports",
4878 "The TCP ports on which "
4879 "ASN.1 messages will be read",
4880 &global_tcp_ports_asn1, 65535);
4881 prefs_register_range_preference(asn1_module, "udp_ports",
4883 "The UDP ports on which "
4884 "ASN.1 messages will be read",
4885 &global_udp_ports_asn1, 65535);
4886 prefs_register_range_preference(asn1_module, "sctp_ports",
4888 "The SCTP ports on which "
4889 "ASN.1 messages will be read",
4890 &global_sctp_ports_asn1, 65535);
4891 #endif /* JUST_ONE_PORT */
4893 prefs_register_bool_preference(asn1_module, "desegment_messages",
4895 "Desegment ASN.1 messages that span TCP segments",
4898 old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
4900 bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
4903 prefs_register_string_preference(asn1_module, "file",
4904 "ASN.1 type table file",
4905 "Compiled ASN.1 description of ASN.1 types",
4907 prefs_register_string_preference(asn1_module, "pdu_name",
4909 "Name of top level PDU",
4911 prefs_register_uint_preference(asn1_module, "first_pdu_offset",
4912 "Offset to first PDU in first tcp packet",
4913 "Offset for non-reassembled packets, "
4914 "wrong if this happens on other than the first packet!",
4915 10, &first_pdu_offset);
4916 prefs_register_bool_preference(asn1_module, "flat",
4918 "Show full names for all values",
4920 prefs_register_enum_preference(asn1_module, "type_recursion",
4921 "Eliminate references to level",
4922 "Allow this recursion level for eliminated type references",
4923 &type_recursion_level,
4924 type_recursion_opts, FALSE);
4925 prefs_register_bool_preference(asn1_module, "debug",
4927 "Extra output useful for debuging",
4930 prefs_register_bool_preference(asn1_module, "message_win",
4932 "show full message description",
4935 prefs_register_obsolete_preference(asn1_module, "message_win");
4937 prefs_register_bool_preference(asn1_module, "verbose_log",
4938 "Write very verbose log",
4939 "log to file $TMP/" ASN1LOGFILE,
4943 /* The registration hand-off routing */
4945 static dissector_handle_t asn1_handle;
4948 register_tcp_port(guint32 port)
4950 dissector_add("tcp.port", port, asn1_handle);
4954 unregister_tcp_port(guint32 port)
4956 dissector_delete("tcp.port", port, asn1_handle);
4960 register_udp_port(guint32 port)
4962 dissector_add("udp.port", port, asn1_handle);
4966 unregister_udp_port(guint32 port)
4968 dissector_delete("udp.port", port, asn1_handle);
4972 register_sctp_port(guint32 port)
4974 dissector_add("sctp.port", port, asn1_handle);
4978 unregister_sctp_port(guint32 port)
4980 dissector_delete("sctp.port", port, asn1_handle);
4984 proto_reg_handoff_asn1(void) {
4985 static int asn1_initialized = FALSE;
4986 #ifndef JUST_ONE_PORT
4987 char *tcp_ports_asn1_string, *udp_ports_asn1_string, *sctp_ports_asn1_string;
4992 #ifdef JUST_ONE_PORT
4993 if (asn1_verbose) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegnment=%d, "
4994 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
4995 global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
4996 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
4999 tcp_ports_asn1_string = range_convert_range(global_tcp_ports_asn1);
5000 udp_ports_asn1_string = range_convert_range(global_udp_ports_asn1);
5001 sctp_ports_asn1_string = range_convert_range(global_sctp_ports_asn1);
5002 g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegnment=%d, "
5003 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5004 tcp_ports_asn1_string, udp_ports_asn1_string, sctp_ports_asn1_string, asn1_desegment,
5005 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5007 #endif /* JUST_ONE_PORT */
5009 if(!asn1_initialized) {
5010 asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
5011 asn1_initialized = TRUE;
5012 } else { /* clean up ports and their lists */
5013 #ifdef JUST_ONE_PORT
5014 unregister_tcp_port(tcp_port_asn1);
5015 unregister_udp_port(udp_port_asn1);
5016 unregister_sctp_port(sctp_port_asn1);
5018 if (tcp_ports_asn1 != NULL) {
5019 range_foreach(tcp_ports_asn1, unregister_tcp_port);
5020 g_free(tcp_ports_asn1);
5023 if (udp_ports_asn1 != NULL) {
5024 range_foreach(udp_ports_asn1, unregister_udp_port);
5025 g_free(udp_ports_asn1);
5028 if (sctp_ports_asn1 != NULL) {
5029 range_foreach(sctp_ports_asn1, unregister_sctp_port);
5030 g_free(sctp_ports_asn1);
5032 #endif /* JUST_ONE_PORT */
5035 if (strcmp(asn1_filename, current_asn1) != 0) {
5036 /* new definitions, parse the file if we have one */
5037 /* !!! should be postponed until we really need it !!! */
5039 read_asn1_type_table(asn1_filename);
5040 #endif /* READSYNTAX */
5041 g_free(current_asn1);
5042 current_asn1 = g_strdup(asn1_filename);
5044 if (!PDUtree || /* no tree built yet for PDU type */
5045 strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
5046 if (build_pdu_tree(asn1_pduname)) {
5047 g_free(current_pduname);
5048 current_pduname = g_strdup(asn1_pduname);
5052 if (asn1_message_win) { /* show what we are prepared to recognize */
5054 gtk_widget_destroy (window);
5057 create_message_window();
5059 #endif /* SHOWPDU */
5061 /* If we now have a PDU tree, register for the port or ports we have */
5063 #ifdef JUST_ONE_PORT
5064 tcp_port_asn1 = global_tcp_port_asn1;
5065 udp_port_asn1 = global_udp_port_asn1;
5066 sctp_port_asn1 = global_sctp_port_asn1;
5068 register_tcp_port(tcp_port_asn1);
5069 register_udp_port(udp_port_asn1);
5070 register_sctp_port(sctp_port_asn1);
5072 tcp_ports_asn1 = range_copy(global_tcp_ports_asn1);
5073 udp_ports_asn1 = range_copy(global_udp_ports_asn1);
5074 sctp_ports_asn1 = range_copy(global_sctp_ports_asn1);
5076 range_foreach(tcp_ports_asn1, register_tcp_port);
5077 range_foreach(udp_ports_asn1, register_udp_port);
5078 range_foreach(sctp_ports_asn1, register_sctp_port);
5080 #endif /* JUST_ONE_PORT */
5083 /* Start the functions we need for the plugin stuff */
5085 #ifndef ENABLE_STATIC
5087 G_MODULE_EXPORT void
5088 plugin_register(void)
5090 /* register the new protocol, protocol fields, and subtrees */
5091 if (proto_asn1 == -1) { /* execute protocol initialization only once */
5092 proto_register_asn1();
5096 G_MODULE_EXPORT void
5097 plugin_reg_handoff(void){
5098 proto_reg_handoff_asn1();
5103 /* End the functions we need for plugin stuff */