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 "plugins/plugin_api.h"
72 #include "moduleinfo.h"
80 #include <epan/packet.h>
81 #include <epan/addr_resolv.h>
83 #include <epan/strutil.h>
84 #include <epan/filesystem.h>
85 #include <epan/report_err.h>
87 #include "simple_dialog.h"
89 #include "plugins/plugin_api_defs.h"
91 #ifdef DISSECTOR_WITH_GUI
97 /* Define version if we are not building ethereal statically */
100 G_MODULE_EXPORT const gchar version[] = VERSION;
108 /* Define default ports */
110 #define TCP_PORT_ASN1 801
111 #define UDP_PORT_ASN1 801
112 #define SCTP_PORT_ASN1 801
114 void proto_reg_handoff_asn1(void);
116 /* Define the asn1 proto */
118 static int proto_asn1 = -1;
120 /* Define the tree for asn1*/
122 static int ett_asn1 = -1;
124 #define MAXPDU 64 /* max # PDU's in one packet */
125 static int ett_pdu[MAXPDU];
127 #define MAX_NEST 32 /* max nesting level for ASN.1 elements */
128 static int ett_seq[MAX_NEST];
131 * Global variables associated with the preferences for asn1
135 static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
136 static guint global_udp_port_asn1 = UDP_PORT_ASN1;
137 static guint global_sctp_port_asn1 = SCTP_PORT_ASN1;
138 static guint tcp_port_asn1 = TCP_PORT_ASN1;
139 static guint udp_port_asn1 = UDP_PORT_ASN1;
140 static guint sctp_port_asn1 = SCTP_PORT_ASN1;
142 static char *global_tcp_ports_asn1 = NULL;
143 static char *global_udp_ports_asn1 = NULL;
144 static char *global_sctp_ports_asn1 = NULL;
146 static GSList *tcp_ports_asn1 = 0;
147 static GSList *udp_ports_asn1 = 0;
148 static GSList *sctp_ports_asn1 = 0;
149 #endif /* JUST_ONE_PORT */
151 static gboolean asn1_desegment = TRUE;
152 static char *asn1_filename = NULL;
153 static char *old_default_asn1_filename = NULL;
154 #define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
156 #define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
157 static char *bad_separator_old_default_asn1_filename = NULL;
159 static char *current_asn1 = NULL;
160 static char *asn1_pduname = NULL;
161 static char *current_pduname = NULL;
162 static gboolean asn1_debug = FALSE;
163 static guint first_pdu_offset = 0;
164 static gboolean asn1_message_win = FALSE;
165 static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
166 static gboolean asn1_full = FALSE; /* show full names */
167 static guint type_recursion_level = 1; /* eliminate 1 level of references */
168 static char *asn1_logfile = NULL;
170 #define ASN1LOGFILE "ethereal.log"
172 /* PDU counter, for correlation between GUI display and log file in debug mode */
173 static int pcount = 0;
175 static tvbuff_t *asn1_desc; /* the PDU description */
176 static GNode *asn1_nodes = 0; /* GNode tree pointing to every asn1 data element */
177 static GNode *data_nodes = 0; /* GNode tree describing the syntax data */
178 static GNode *PDUtree = 0; /* GNode tree describing the expected PDU format */
180 static guint PDUerrcount = 0; /* count of parse errors in one ASN.1 message */
182 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
185 char pabbrev[] = "asn1"; /* field prefix */
187 char fieldname[512]; /* for constructing full names */
188 guint pabbrev_pdu_len; /* length initial part of fieldname with 'abbrev.asn1pdu.' */
191 * Text strings describing the standard, universal, ASN.1 names.
194 #define ASN1_EOI 4 /* this is in the class number space... */
195 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
197 char tag_class[] = "UACPX";
199 char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
201 char *asn1_con[] = { "Primitive", "Constructed" };
204 /* 0 */ "EOC", "Boolean", "Integer", "BitString",
205 /* 4 */ "OctetString", "Null", "ObjectIdentifier", "ObjectDescriptor",
206 /* 8 */ "External", "Real", "Enumerated", "tag11",
207 /* 12 */ "UTF8String", "tag13", "tag14", "tag15",
208 /* 16 */ "Sequence", "Set", "NumericString", "PrintableString",
209 /* 20 */ "TeletexString", "VideotexString", "IA5String", "UTCTime",
210 /* 24 */ "GeneralTime", "GraphicString", "ISO646String", "GeneralString",
211 /* 28 */ "UniversalString", "tag29", "BMPString", "Long tag prefix"
212 /* TT61 == TELETEX */
213 /* ISO646 == VISIBLE*/
216 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
217 gboolean tbl_types_verified = FALSE;
219 typedef enum { /* copied from .../snacc/c-lib/boot/tbl.h */
228 TBL__SIMPLE = 8, /* values smaller than this can have a value */
236 TBL_SEQUENCEOF_start, /* to mark potential sequence-of repeat */
237 TBL_TYPEREF_nopop, /* typeref has been handled immediately */
238 TBL_CHOICE_done, /* choice is finished */
239 TBL_reserved, /* this sequence has been visited */
240 TBL_CHOICE_immediate, /* immediate choice, no next */
242 TBL_INVALID /* incorrect value for this enum */
245 /* Universal tags mapped to snacc ASN.1 table types */
246 int asn1_uni_type[] = {
247 /* 0 */ TBL_INVALID, TBL_BOOLEAN, TBL_INTEGER, TBL_BITSTRING,
248 /* 4 */ TBL_OCTETSTRING, TBL_NULL, TBL_OID, TBL_INVALID,
249 /* 8 */ TBL_INVALID, TBL_REAL, TBL_ENUMERATED, TBL_INVALID,
250 /* 12 */ TBL_OCTETSTRING, TBL_INVALID, TBL_INVALID, TBL_INVALID,
251 /* 16 */ TBL_SEQUENCE, TBL_SET, TBL_OCTETSTRING, TBL_OCTETSTRING,
252 /* 20 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
253 /* 24 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
254 /* 28 */ TBL_OCTETSTRING, TBL_INVALID, TBL_OCTETSTRING, TBL_INVALID,
258 #define TBL_REPEAT 0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
259 #define TBL_REPEAT_choice 0x00020000 /* repeating a choice */
260 #define TBL_CHOICE_made 0x00040000 /* This was a choice entry */
261 #define TBL_SEQUENCE_done 0x00080000 /* children have been processed */
262 #define TBL_CHOICE_repeat 0x00100000 /* a repeating choice */
263 #define TBL_REFERENCE 0x00200000 /* This entry is result of a typeref */
264 #define TBL_REFERENCE_pop 0x00400000 /* reference handled, do pop i.s.o. next */
265 #define TBL_SEQUENCE_choice 0x00800000 /* this sequence is a first of a repeating choice */
266 #define TBL_CONSTRUCTED 0x01000000 /* unexpectedly constructed entry */
267 #define TBL_TYPEmask 0x0000FFFF /* Mask just the type */
270 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
272 /* text tables for debugging and GUI */
273 char *tbl_types[] = { /* 0 */ "tbl-boolean",
274 /* 1 */ "tbl-integer",
275 /* 2 */ "tbl-bitstring",
276 /* 2 */ "tbl-octetstring",
280 /* 7 */ "tbl-enumerated",
281 /* 8 */ "tbl-sequence",
283 /* 10 */ "tbl-sequenceof",
284 /* 11 */ "tbl-setof",
285 /* 12 */ "tbl-choice",
286 /* 13 */ "tbl-typeref",
288 /* 14 */ "tbl-sequenceof-start",
289 /* 15 */ "tbl-typeref-nopop",
290 /* 16 */ "tbl-choice-done",
291 /* 17 */ "tbl-reserved",
292 /* 18 */ "tbl-choice-immediate",
294 /* 19 */ "tbl-invalid",
296 char *tbl_types_asn1[] = {
300 /* 2 */ "OCTET STRING",
302 /* 5 */ "OBJECT IDENTIFIER",
304 /* 7 */ "ENUMERATED",
307 /* 10 */ "SEQUENCE OF",
312 /* 14 */ "start-SEQUENCE OF",
313 /* 15 */ "TYPEREF nopop",
314 /* 16 */ "CHOICE done",
316 /* 18 */ "CHOICE immediate",
318 /* 19 */ "INVALID entry",
320 /* conversion from snacc type to appropriate ethereal type */
321 guint tbl_types_ethereal[] = {
322 /* 0 */ FT_BOOLEAN, /* TBL_BOOLEAN */
323 /* 1 */ FT_UINT32, /* TBL_INTEGER */
324 /* 2 */ FT_UINT32, /* TBL_BITSTRING */
325 /* 2 */ FT_STRINGZ, /* TBL_OCTETSTRING */
326 /* 4 */ FT_NONE, /* TBL_NULL */
327 /* 5 */ FT_BYTES, /* TBL_OID */
328 /* 6 */ FT_DOUBLE, /* TBL_REAL */
329 /* 7 */ FT_UINT32, /* TBL_ENUMERATED */
330 /* 8 */ FT_NONE, /* TBL_SEQUENCE */
331 /* 9 */ FT_NONE, /* TBL_SET */
332 /* 10 */ FT_NONE, /* TBL_SEQUENCEOF */
333 /* 11 */ FT_NONE, /* TBL_SETOF */
334 /* 12 */ FT_NONE, /* TBL_CHOICE */
335 /* 13 */ FT_NONE, /* TBL_TYPEREF */
337 /* 14 */ FT_NONE, /* TBL_SEQUENCEOF_start */
338 /* 15 */ FT_NONE, /* TBL_TYPEREF_nopop */
339 /* 16 */ FT_NONE, /* TBL_CHOICE_done */
340 /* 17 */ FT_NONE, /* TBL_reserved */
341 /* 18 */ FT_NONE, /* TBL_CHOICE_immediate */
343 /* 19 */ FT_NONE, /* TBL_INVALID */
346 char *tbl_types_ethereal_txt[] = {
347 /* 0 */ "FT_BOOLEAN", /* TBL_BOOLEAN */
348 /* 1 */ "FT_UINT32", /* TBL_INTEGER */
349 /* 2 */ "FT_UINT32", /* TBL_BITSTRING */
350 /* 2 */ "FT_STRINGZ", /* TBL_OCTETSTRING */
351 /* 4 */ "FT_NONE", /* TBL_NULL */
352 /* 5 */ "FT_BYTES", /* TBL_OID */
353 /* 6 */ "FT_DOUBLE", /* TBL_REAL */
354 /* 7 */ "FT_UINT32", /* TBL_ENUMERATED */
355 /* 8 */ "FT_NONE", /* TBL_SEQUENCE */
356 /* 9 */ "FT_NONE", /* TBL_SET */
357 /* 10 */ "FT_NONE", /* TBL_SEQUENCEOF */
358 /* 11 */ "FT_NONE", /* TBL_SETOF */
359 /* 12 */ "FT_NONE", /* TBL_CHOICE */
360 /* 13 */ "FT_NONE", /* TBL_TYPEREF */
362 /* 14 */ "FT_NONE", /* TBL_SEQUENCEOF_start */
363 /* 15 */ "FT_NONE", /* TBL_TYPEREF_nopop */
364 /* 16 */ "FT_NONE", /* TBL_CHOICE_done */
365 /* 17 */ "FT_NONE", /* TBL_reserved */
366 /* 18 */ "FT_NONE", /* TBL_CHOICE_immediate */
368 /* 19 */ "FT_NONE", /* TBL_INVALID */
371 typedef struct _PDUinfo PDUinfo;
382 gint basetype; /* parent type */
383 gint mytype; /* original type number, typenum may have gone through a reference */
384 gint value_id; /* ethereal field id for the value in this PDU */
385 gint type_id; /* ethereal field id for the type of this PDU */
386 hf_register_info value_hf; /* ethereal field info for this value */
390 /* bits in the flags collection */
391 #define PDU_OPTIONAL 1
392 #define PDU_IMPLICIT 2
393 #define PDU_NAMEDNUM 4
394 #define PDU_REFERENCE 8
395 #define PDU_TYPEDEF 0x10
396 #define PDU_ANONYMOUS 0x20
397 #define PDU_TYPETREE 0x40
399 #define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
401 guint PDUinfo_initflags = 0; /* default flags for newly allocated PDUinfo structs */
403 /* description of PDU properties as passed from the matching routine
404 * to the decoder and GUI.
406 typedef struct _PDUprops PDUprops;
408 guint type; /* value from enum TBLTypeId */
417 /* flags defined in PDUprops.flags */
418 #define OUT_FLAG_type 1
419 #define OUT_FLAG_data 2
420 #define OUT_FLAG_typename 4
421 #define OUT_FLAG_dontshow 8
422 #define OUT_FLAG_noname 0x10
423 #define OUT_FLAG_constructed 0x20
425 PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
426 char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
428 char empty[] = ""; /* address of the empt string, avoids many tests for NULL */
429 #define MAX_OTSLEN 256 /* max printed size for an octet string */
432 #undef NEST /* show nesting of asn.1 enties */
434 #ifdef NEST /* only for debugging */
435 /* show nesting, only for debugging... */
436 #define MAXTAGS MAX_NEST
442 char *showtaglist(guint level)
444 static char tagtxt[BUFLM];
449 for(i=0; i<= level; i++) {
450 switch(taglist[i].cls) {
451 case ASN1_UNI: *p++ = 'U'; break;
452 case ASN1_APL: *p++ = 'A'; break;
453 case ASN1_CTX: *p++ = 'C'; break;
454 case ASN1_PRV: *p++ = 'P'; break;
455 default: *p++ = 'x'; break;
457 p += sprintf(p, "%d.", taglist[i].tag);
459 #else /* only context tags */
461 for(i=0; i<= level; i++) {
462 if (taglist[i].cls == ASN1_CTX) {
463 p += sprintf(p, "%d.", taglist[i].tag);
467 *--p = 0; /* remove trailing '.' */
472 get_context(guint level)
477 for(i=0; i<=level; i++) {
478 if (taglist[i].cls == ASN1_CTX)
479 ctx = (ctx << 8) | taglist[i].tag;
483 #endif /* NEST, only for debugging */
486 /* Convert a bit string to an ascii representation for printing
487 * -- not thread safe ...
489 char *showbits(guchar *val, guint count)
491 static char str[BUFLM];
496 return "*too many bits*";
499 for(i=0; i<count; i++) {
500 if (i && ((i & 7) == 0)) *p++ = ' ';
501 *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
508 /* get bitnames string for bits set */
509 char * showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
511 static char str[BUFLL];
515 if (props->flags & OUT_FLAG_noname)
519 return "*too many bits, no names...*";
522 for(i=0; i<count; i++) {
523 if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
524 p += sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
528 --p; /* remove terminating , */
536 /* Convert an oid to its conventional text representation
537 * -- not thread safe...
539 char *showoid(subid_t *oid, guint len)
541 static char str[BUFLM];
546 for(i=0; i<len; i++) {
548 p += sprintf(p, "%lu", (unsigned long)oid[i]);
555 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
556 char *showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
561 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 */
622 int checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
627 snprintf(lenstr, strmax, "indefinite");
631 if (len < 0) /* negative ..... */
634 if (cls != ASN1_UNI) { /* don't know about the tags */
639 case ASN1_EOC: /* End Of Contents */
640 case ASN1_NUL: /* Null */
643 case ASN1_BOL: /* Boolean */
646 case ASN1_INT: /* Integer */
647 case ASN1_ENUM: /* Enumerated */
651 case ASN1_BTS: /* Bit String */
655 case ASN1_OTS: /* Octet String */
656 case ASN1_NUMSTR: /* Numerical String */
657 case ASN1_PRNSTR: /* Printable String */
658 case ASN1_TEXSTR: /* Teletext String */
659 case ASN1_VIDSTR: /* Video String */
660 case ASN1_IA5STR: /* IA5 String */
661 case ASN1_GRASTR: /* Graphical String */
662 case ASN1_VISSTR: /* Visible String */
663 case ASN1_GENSTR: /* General String */
667 case ASN1_OJI: /* Object Identifier */
668 case ASN1_OJD: /* Description */
669 case ASN1_EXT: /* External */
673 case ASN1_REAL: /* Real */
677 case ASN1_SEQ: /* Sequence */
678 case ASN1_SET: /* Set */
682 case ASN1_UNITIM: /* Universal Time */
683 case ASN1_GENTIM: /* General Time */
696 /* a change was needed.... */
697 snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
699 snprintf(lenstr, strmax, "%d", len);
704 guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
705 void PDUreset(int count, int counr2);
708 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
711 guint cls, con, tag, def, len, offset, reassembled;
717 volatile guint boffset;
718 volatile int i = 0; /* PDU counter */
719 proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
721 static guint lastseq;
726 reassembled = 1; /* UDP is not a stream, and thus always reassembled .... */
727 if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
728 struct tcpinfo *info = (struct tcpinfo *)pinfo->private_data;
729 gint delta = info->seq - lastseq;
730 reassembled = info->is_reassembled;
734 g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
735 info->seq, delta, reassembled);
738 g_message("dissect_asn1: udp");
741 /* Set the protocol column */
742 if(check_col(pinfo->cinfo, COL_PROTOCOL)){
743 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
746 if(check_col(pinfo->cinfo, COL_INFO))
747 col_clear(pinfo->cinfo, COL_INFO);
751 if ((first_pdu_offset > 0) && !reassembled) {
752 boffset = first_pdu_offset;
753 snprintf(offstr, sizeof(offstr), " at %d", boffset);
756 /* open BER decoding */
757 asn1_open(&asn1, tvb, boffset);
759 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
761 asn1_close(&asn1, &offset);
763 PDUreset(pcount, 0); /* arguments are just for debugging */
764 getPDUprops(&props, boffset, cls, tag, con);
766 tname = props.typename;
768 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
772 snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
774 snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
781 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
787 if (props.flags & OUT_FLAG_noname) {
788 snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
789 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
791 snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
794 /* Set the info column */
795 if(check_col(pinfo->cinfo, COL_INFO)){
796 col_add_str(pinfo->cinfo, COL_INFO, headstr );
800 * If we have a non-null tree (ie we are building the proto_tree
801 * instead of just filling out the columns ), then add a BER
805 /* ignore the tree here, must decode BER to know how to reassemble!! */
808 TRY { /* catch incomplete PDU's */
810 ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
811 def? (int) (offset - boffset + len) : -1,
812 "ASN.1 %s", current_pduname);
814 tree2 = proto_item_add_subtree(ti, ett_asn1);
816 proto_tree_add_item_hidden(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
817 def? (int) (offset - boffset + len) : -1, TRUE);
819 offset = boffset; /* the first packet */
820 while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
823 /* open BER decoding */
824 asn1_open(&asn1, tvb, offset);
825 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
826 asn1_close(&asn1, &offset);
828 PDUreset(pcount, i+1);
829 getPDUprops(&props, boffset, cls, tag, con);
831 tname = props.typename;
834 len = tvb_length_remaining(tvb, offset);
836 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
840 snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
842 snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
845 ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
848 tvb_length_remaining(tvb, offset) );
850 if (props.value_id == -1)
851 ti2 = proto_tree_add_text(tree2, tvb, boffset,
852 def? (int) (offset - boffset + len) : -1,
853 "%s: (%s)%s %d-%d %s", current_pduname,
854 tname, name, pcount, i+1, headstr);
856 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
857 def? (int) (offset - boffset + len) : -1,
858 "%s: (%s)%s %d-%d %s ~", current_pduname,
859 tname, name, pcount, i+1, headstr);
861 if (props.type_id != -1)
862 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
863 def? (int) (offset - boffset + len) : -1, TRUE);
867 if (props.flags & OUT_FLAG_noname) {
868 snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
869 name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
871 if (props.value_id == -1)
872 ti2 = proto_tree_add_text(tree2, tvb, boffset,
873 def? (int) (offset - boffset + len) : -1,
874 "%s: (%s)%s", current_pduname, tname, name);
876 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
877 def? (int) (offset - boffset + len) : -1,
878 "%s: (%s)%s ~", current_pduname, tname, name);
879 if (props.type_id != -1)
880 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
881 def? (int) (offset - boffset + len) : -1, TRUE);
884 asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
887 taglist[0].cls = cls;
888 taglist[0].tag = tag;
891 if (!def) len++; /* make sure we get an exception if we run off the end! */
893 offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
895 proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
897 i++; /* one more full message handled */
899 if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
900 proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
902 if(check_col(pinfo->cinfo, COL_INFO))
903 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
905 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
910 CATCH(ReportedBoundsError) {
911 if(check_col(pinfo->cinfo, COL_INFO))
912 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
914 proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
916 proto_item_append_text(ti2, " (incomplete)");
917 if (asn1_desegment) {
918 pinfo->desegment_offset = boffset;
919 pinfo->desegment_len = 1;
921 g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
922 boffset, 1, pinfo->can_desegment);
930 g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
931 pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
934 /* decode an ASN.1 sequence, until we have consumed the specified length */
936 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
939 guint ret, cls, con, tag, def, len, boffset, soffset, eos;
941 char *clsstr, *constr, *tagstr;
945 proto_tree *ti, *pt2;
946 guchar *octets, *bits, unused;
948 /* the debugging formats */
949 static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s"; /* decimal */
950 static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s"; /* enum */
951 static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s"; /* octet string */
952 static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s"; /* bit field */
953 static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s"; /* constructed */
954 static char matchind[] = " ~"; /* indication of possible match */
955 char *name, *ename, *tname, *oname;
958 ti = 0; /* suppress gcc warning */
960 soffset = offset; /* where this sequence starts */
962 while (offset < eos) { /* while this entity has not ended... */
964 asn1_open(&asn1, tvb, offset);
965 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
966 asn1_close(&asn1, &offset); /* mark current position */
967 if (ret != ASN1_ERR_NOERROR) {
968 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
972 getPDUprops(&props, boffset, cls, tag, con);
974 tname = props.typename;
976 name = &props.fullname[pabbrev_pdu_len]; /* no abbrev.pduname */
977 if (asn1_debug) { /* show both names */
978 sprintf(fieldname, "%s[%s]", props.name, props.fullname);
982 clsstr = asn1_cls[cls];
983 constr = asn1_con[con];
984 if ((cls == ASN1_UNI) && ( tag < 32 )) {
985 tagstr = asn1_tag[tag];
987 snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
991 len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
994 snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
996 strncpy(nnbuf, "NN-", sizeof(nnbuf));
997 /* make sure we get an exception if we run off the end! */
998 len = tvb_length_remaining(tvb, offset) + 1;
1000 if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
1001 /* just give type name if we don't know any better */
1003 name = nnbuf; /* this is better than just empty.... */
1007 taglist[level].cls = cls;
1008 taglist[level].tag = tag;
1012 if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
1015 oname = g_malloc(strlen(name) + 32);
1016 sprintf(oname, "%s ** nesting cut off **", name);
1020 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
1023 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1024 asn1_close(&asn1, &offset); /* mark where we are now */
1026 if ( (props.value_id == -1) ||
1027 (tbl_types_ethereal[props.type] != FT_UINT32) )
1028 /* unknown or unexpected: just text */
1029 proto_tree_add_text(pt, tvb, boffset,
1030 offset - boffset, textfmt_d, boffset,
1031 clsstr, constr, tagstr, tname, name, value,
1034 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1035 offset - boffset, value, textfmt_d, boffset,
1036 clsstr, constr, tagstr, tname, name, value,
1038 if (props.type_id != -1)
1039 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1040 boffset, offset - boffset, value);
1043 if ( (props.value_id == -1) ||
1044 (tbl_types_ethereal[props.type] != FT_UINT32) )
1045 /* unknown or unexpected, just text */
1046 proto_tree_add_text(pt, tvb, boffset,
1048 "(%s)%s: %d", tname, name, value);
1050 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1051 offset - boffset, value,
1052 "(%s)%s: %d ~", tname, name, value);
1053 if (props.type_id != -1)
1054 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1055 boffset, offset - boffset, value);
1061 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1062 asn1_close(&asn1, &offset); /* mark where we are now */
1063 ename = getPDUenum(&props, boffset, cls, tag, value);
1065 if ( (props.value_id == -1) ||
1066 (tbl_types_ethereal[props.type] != FT_UINT32) )
1067 /* unknown or unexpected, just text */
1068 proto_tree_add_text(pt, tvb, boffset,
1070 textfmt_e, boffset, clsstr, constr, tagstr,
1071 tname, name, value, ename, empty);
1073 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1074 offset - boffset, value,
1075 textfmt_e, boffset, clsstr, constr, tagstr,
1076 tname, name, value, ename, matchind);
1077 if (props.type_id != -1)
1078 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1079 boffset, offset - boffset, value);
1082 if ( (props.value_id == -1) ||
1083 (tbl_types_ethereal[props.type] != FT_UINT32) )
1084 /* unknown or unexpected, just text */
1085 proto_tree_add_text(pt, tvb, boffset,
1087 "(%s)%s: %d:%s", tname, name, value, ename);
1089 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1090 offset - boffset, value,
1091 "(%s)%s: %d:%s ~", tname, name, value, ename);
1092 if (props.type_id != -1)
1093 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1094 boffset, offset - boffset, value);
1100 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1101 asn1_close(&asn1, &offset); /* mark where we are now */
1103 if ( (props.value_id == -1) ||
1104 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1105 /* unknown or unexpected, just text */
1106 proto_tree_add_text(pt, tvb, boffset,
1108 textfmt_s, boffset, clsstr, constr, tagstr,
1109 tname, name, value? "true" : "false", empty);
1111 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1112 offset - boffset, value != 0,
1113 textfmt_s, boffset, clsstr, constr, tagstr,
1114 tname, name, value? "true" : "false", matchind);
1115 if (props.type_id != -1)
1116 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1117 boffset, offset - boffset, value != 0);
1120 if ( (props.value_id == -1) ||
1121 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1122 /* unknown or unexpected, just text */
1123 proto_tree_add_text(pt, tvb, boffset,
1125 "(%s)%s: %s", tname, name,
1126 value? "true" : "false");
1128 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1129 offset - boffset, value != 0,
1130 "(%s)%s: %s ~", tname, name,
1131 value? "true" : "false");
1132 if (props.type_id != -1)
1133 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1134 boffset, offset - boffset, value != 0);
1147 /* read value, \0 terminated */
1148 ret = asn1_string_value_decode(&asn1, len, &octets);
1149 asn1_close(&asn1, &offset); /* mark where we are now */
1150 ename = showoctets(octets, len, (tag == ASN1_OTS) ? 4 : 0 );
1152 if ( (props.value_id == -1) ||
1153 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1154 /* unknown or unexpected, just text */
1155 proto_tree_add_text(pt, tvb, boffset,
1157 textfmt_s, boffset, clsstr, constr, tagstr,
1158 tname, name, ename, empty);
1160 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1161 offset - boffset, octets, /* \0 termnated */
1162 textfmt_s, boffset, clsstr, constr, tagstr,
1163 tname, name, ename, matchind);
1164 if (props.type_id != -1)
1165 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1166 boffset, offset - boffset, octets);
1169 if ( (props.value_id == -1) ||
1170 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1171 /* unknown or unexpected, just text */
1172 proto_tree_add_text(pt, tvb, boffset,
1174 "(%s)%s: %s", tname, name, ename);
1176 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1177 offset - boffset, octets, /* \0 terminated */
1178 "(%s)%s: %s ~", tname, name, ename);
1179 if (props.type_id != -1)
1180 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1181 boffset, offset - boffset, octets);
1189 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1190 asn1_close(&asn1, &offset); /* mark where we are now */
1191 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1193 if ( (props.value_id == -1) ||
1194 (tbl_types_ethereal[props.type] != FT_UINT32) )
1195 /* unknown or unexpected, just text */
1196 proto_tree_add_text(pt, tvb, boffset,
1198 textfmt_b, boffset, clsstr, constr, tagstr,
1200 showbits(bits, (con*8)-unused), ename, empty);
1202 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1203 offset - boffset, *bits, /* XXX length ? XXX */
1204 textfmt_b, boffset, clsstr, constr, tagstr,
1206 showbits(bits, (con*8)-unused),ename, matchind);
1207 if (props.type_id != -1)
1208 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1209 boffset, offset - boffset, *bits);
1213 if ( (props.value_id == -1) ||
1214 (tbl_types_ethereal[props.type] != FT_UINT32) )
1215 /* unknown or unexpected, just text */
1216 proto_tree_add_text(pt, tvb, boffset,
1218 "(%s)%s: %s:%s", tname, name,
1219 showbits(bits, (con*8)-unused), ename);
1221 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1222 offset - boffset, *bits, /* XXX length ? XXX */
1223 "(%s)%s: %s:%s ~", tname, name,
1224 showbits(bits, (con*8)-unused), ename);
1225 if (props.type_id != -1)
1226 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1227 boffset, offset - boffset, *bits);
1235 /* show full sequence length */
1238 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1240 if ( (props.flags & OUT_FLAG_constructed))
1241 ename = ", unexpected constructed";
1243 if (props.value_id == -1)
1244 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1245 textfmt_c, boffset, clsstr, constr, tagstr,
1246 tname, name, ename, empty);
1248 ti = proto_tree_add_item(pt, props.value_id, tvb,
1250 /* change te text to to what I really want */
1251 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1252 tagstr, tname, name, ename, matchind);
1253 if (props.type_id != -1)
1254 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1258 if (props.value_id == -1) {
1259 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1260 ti = proto_tree_add_text(pt, tvb, boffset,
1261 offset - boffset + len,
1262 "(%s)%s", tname, name);
1264 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1265 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1266 boffset, offset - boffset + len,
1267 "(%s)%s ~", tname, name);
1269 /* don't care about the text */
1270 ti = proto_tree_add_item_hidden(pt, props.value_id, tvb,
1273 if (props.type_id != -1)
1274 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1278 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1280 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1281 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1285 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1287 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1288 proto_item_set_len(ti, offset - boffset);
1293 if (asn1_debug) { /* don't show if not debugging */
1294 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1295 boffset, clsstr, constr, tagstr, tname, name,
1296 offset - soffset, empty);
1298 getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1302 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1303 asn1_close(&asn1, &offset); /* mark where we are now */
1304 ename = showoid(oid, con);
1306 if ( (props.value_id == -1) ||
1307 (tbl_types_ethereal[props.type] != FT_BYTES) )
1308 /* unknown or unexpected, just text */
1309 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1310 boffset, clsstr, constr, tagstr, tname, name,
1313 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1314 offset - boffset, ename,/* XXX length?*/
1315 "(%s)%s: %s ~", tname, name, ename);
1316 if (props.type_id != -1)
1317 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1318 boffset, offset - boffset, ename);
1321 if ( (props.value_id == -1) ||
1322 (tbl_types_ethereal[props.type] != FT_BYTES) )
1323 /* unknown or unexpected, just text */
1324 proto_tree_add_text(pt, tvb, boffset,
1326 "(%s)%s: %s", tname, name, ename);
1328 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1329 offset - boffset, ename, /* XXX length ? */
1330 "(%s)%s: %s ~", tname, name, ename);
1331 if (props.type_id != -1)
1332 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1333 boffset, offset - boffset, ename);
1341 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1342 boffset, clsstr, constr, tagstr, tname, name,
1345 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1346 "(%s)%s: [NULL]", tname, name);
1348 offset += len; /* skip value ... */
1360 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1361 textfmt_s, boffset, clsstr, constr, tagstr,
1362 tname, name, lenbuf, empty);
1364 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1365 "(%s)%s: %s bytes", tname, name, lenbuf);
1367 proto_item_append_text(ti, " *"); /* indicate default is used */
1368 offset += len; /* skip value ... */
1373 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1374 case ASN1_APL: /* fprintf(stderr, "Application\n"); */
1375 case ASN1_PRV: /* fprintf(stderr, "Private\n"); */
1378 if (props.value_id == -1) /* type unknown, handle as string */
1380 switch(props.type) {
1381 /* this is via the asn1 description, don't trust the length */
1385 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1386 asn1_close(&asn1, &offset); /* mark where we are now */
1388 if ( (props.value_id == -1) ||
1389 (tbl_types_ethereal[props.type] != FT_UINT32) )
1390 /* unknown or unexpected, just text */
1391 proto_tree_add_text(pt, tvb,
1392 boffset, offset - boffset,
1393 textfmt_d, boffset, clsstr, constr,
1394 tagstr, tname, name, value, empty);
1396 proto_tree_add_uint_format(pt, props.value_id, tvb,
1397 boffset, offset - boffset, value,
1398 textfmt_d, boffset, clsstr, constr,
1399 tagstr, tname, name, value, matchind);
1400 if (props.type_id != -1)
1401 proto_tree_add_uint_hidden(pt, props.type_id,
1402 tvb, boffset, offset - boffset, value);
1405 if ( (props.value_id == -1) ||
1406 (tbl_types_ethereal[props.type] != FT_UINT32) )
1407 /* unknown or unexpected, just text */
1408 proto_tree_add_text(pt, tvb,
1409 boffset, offset - boffset,
1410 "(%s)%s: %d", tname, name, value);
1412 proto_tree_add_uint_format(pt, props.value_id, tvb,
1413 boffset, offset - boffset, value,
1414 "(%s)%s: %d ~", tname, name, value);
1415 if (props.type_id != -1)
1416 proto_tree_add_uint_hidden(pt, props.type_id,
1417 tvb, boffset, offset - boffset, value);
1422 case TBL_ENUMERATED:
1425 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1426 asn1_close(&asn1, &offset); /* mark where we are now */
1427 ename = getPDUenum(&props, boffset, cls, tag, value);
1429 if ( (props.value_id == -1) ||
1430 (tbl_types_ethereal[props.type] != FT_UINT32) )
1431 /* unknown or unexpected, just text */
1432 proto_tree_add_text(pt, tvb,
1433 boffset, offset - boffset,
1434 textfmt_e, boffset, clsstr, constr,
1435 tagstr, tname, name, value, ename, empty);
1437 proto_tree_add_uint_format(pt, props.value_id, tvb,
1438 boffset, offset - boffset, value,
1439 textfmt_e, boffset, clsstr, constr,
1440 tagstr, tname, name, value, ename, matchind);
1441 if (props.type_id != -1)
1442 proto_tree_add_uint_hidden(pt, props.type_id,
1443 tvb, boffset, offset - boffset, value);
1446 if ( (props.value_id == -1) ||
1447 (tbl_types_ethereal[props.type] != FT_UINT32) )
1448 /* unknown or unexpected, just text */
1449 proto_tree_add_text(pt, tvb,
1450 boffset, offset - boffset,
1451 "(%s)%s: %d:%s", tname, name, value, ename);
1453 proto_tree_add_uint_format(pt, props.value_id, tvb,
1454 boffset, offset - boffset, value,
1455 "(%s)%s: %d:%s ~", tname, name, value, ename);
1456 if (props.type_id != -1)
1457 proto_tree_add_uint_hidden(pt, props.type_id,
1458 tvb, boffset, offset - boffset, value);
1463 if (len > (1+4)) /* max 32 bits ...?.. */
1466 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1467 asn1_close(&asn1, &offset); /* mark where we are now */
1468 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1470 if ( (props.value_id == -1) ||
1471 (tbl_types_ethereal[props.type] != FT_UINT32) )
1472 /* unknown or unexpected, just text */
1473 proto_tree_add_text(pt, tvb,
1474 boffset, offset - boffset,
1475 textfmt_b, boffset, clsstr, constr,
1476 tagstr, tname, name,
1477 showbits(bits, (con*8)-unused), ename,
1480 proto_tree_add_uint_format(pt, props.value_id, tvb,
1481 boffset, offset - boffset, *bits,
1482 textfmt_b, boffset, clsstr, constr,
1483 tagstr, tname, name,
1484 showbits(bits, (con*8)-unused), ename,
1486 if (props.type_id != -1)
1487 proto_tree_add_uint_hidden(pt, props.type_id,
1488 tvb, boffset, offset - boffset, *bits);
1491 if ( (props.value_id == -1) ||
1492 (tbl_types_ethereal[props.type] != FT_UINT32) )
1493 /* unknown or unexpected, just text */
1494 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1495 "(%s)%s: %s:%s", tname, name,
1496 showbits(bits, (con*8)-unused), ename);
1498 proto_tree_add_uint_format(pt, props.value_id, tvb,
1499 boffset, offset - boffset, *bits,
1500 "(%s)%s: %s:%s ~", tname, name,
1501 showbits(bits, (con*8)-unused), ename);
1502 if (props.type_id != -1)
1503 proto_tree_add_uint_hidden(pt, props.type_id,
1504 tvb, boffset, offset - boffset, *bits);
1512 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1513 asn1_close(&asn1, &offset); /* mark where we are now */
1515 if ( (props.value_id == -1) ||
1516 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1517 /* unknown or unexpected, just text */
1518 proto_tree_add_text(pt, tvb,
1519 boffset, offset - boffset,
1520 textfmt_s, boffset, clsstr, constr,
1521 tagstr, tname, name,
1522 value? "true" : "false", empty);
1524 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1525 boffset, offset - boffset, value != 0,
1526 textfmt_s, boffset, clsstr, constr,
1527 tagstr, tname, name,
1528 value? "true" : "false", matchind);
1529 if (props.type_id != -1)
1530 proto_tree_add_boolean_hidden(pt, props.type_id,
1531 tvb, boffset, offset - boffset, value != 0);
1534 if ( (props.value_id == -1) ||
1535 (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
1536 /* unknown or unexpected, just text */
1537 proto_tree_add_text(pt, tvb,
1538 boffset, offset - boffset,
1539 "(%s)%s: %s", tname, name,
1540 value? "true" : "false");
1542 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1543 boffset, offset - boffset, value != 0,
1544 "(%s)%s: %s ~", tname, name,
1545 value? "true" : "false");
1546 if (props.type_id != -1)
1547 proto_tree_add_boolean_hidden(pt, props.type_id,
1548 tvb, boffset, offset - boffset, value != 0);
1556 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1557 textfmt_s, boffset, clsstr, constr,
1558 tagstr, tname, name, "[NULL]", empty);
1560 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1561 "(%s)%s: [NULL]", tname, name);
1563 offset += len; /* skip value ... */
1567 props.value_id = -1; /* unlikely this is correct, dont use it */
1569 case TBL_OCTETSTRING:
1570 /* defined length, not constructed, must be a string.... */
1571 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1572 asn1_close(&asn1, &offset); /* mark where we are now */
1573 ename = showoctets(octets, len, 2); /* convert octets to printable */
1575 if ( (props.value_id == -1) ||
1576 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1577 /* unknown or unexpected, just text */
1578 proto_tree_add_text(pt, tvb,
1579 boffset, offset - boffset,
1580 textfmt_s, boffset, clsstr, constr,
1581 tagstr, tname, name, ename, empty);
1583 proto_tree_add_string_format(pt, props.value_id, tvb,
1584 boffset, offset - boffset, octets, /* XXX */
1585 textfmt_s, boffset, clsstr, constr,
1586 tagstr, tname, name, ename, matchind);
1587 if (props.type_id != -1)
1588 proto_tree_add_string_hidden(pt, props.type_id,
1589 tvb, boffset, offset - boffset, octets);
1592 if ( (props.value_id == -1) ||
1593 (tbl_types_ethereal[props.type] != FT_STRINGZ) )
1594 /* unknown or unexpected, just text */
1595 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1596 "(%s)%s: %s", tname, name, ename);
1598 proto_tree_add_string_format(pt, props.value_id, tvb,
1599 boffset, offset - boffset, octets, /* XXX */
1600 "(%s)%s: %s ~", tname, name, ename);
1601 if (props.type_id != -1)
1602 proto_tree_add_string_hidden(pt, props.type_id,
1603 tvb, boffset, offset - boffset, octets);
1611 /* indefinite length or constructed.... must be a sequence .... */
1612 /* show full sequence length */
1615 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1617 if ( (props.flags & OUT_FLAG_constructed))
1618 ename = ", unexpected constructed";
1620 if (props.value_id == -1)
1621 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1622 textfmt_c, boffset, clsstr, constr,
1623 tagstr, tname, name, ename, empty);
1625 ti = proto_tree_add_item(pt, props.value_id, tvb,
1627 /* change te text to to what I really want */
1629 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1630 tagstr, tname, name, ename, matchind);
1631 if (props.type_id != -1)
1632 proto_tree_add_item_hidden(pt, props.type_id, tvb,
1635 ti = proto_tree_add_text(pt, tvb, boffset,
1636 offset - boffset + len,
1637 textfmt_c, boffset, clsstr, constr,
1638 tagstr, tname, name, ename, empty);
1642 if (props.value_id == -1) {
1643 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1644 ti = proto_tree_add_text(pt, tvb, boffset,
1645 offset - boffset + len, "(%s)%s", tname, name);
1647 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1648 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1650 "(%s)%s ~", tname, name);
1652 /* don't care about the text */
1653 ti = proto_tree_add_item_hidden(pt, props.value_id,
1654 tvb, boffset, 1, TRUE);
1656 if (props.type_id != -1)
1657 proto_tree_add_item_hidden(pt, props.type_id,
1658 tvb, boffset, 1, TRUE);
1662 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1664 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1665 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1669 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1671 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1672 proto_item_set_len(ti, offset - boffset);
1676 default: /* fprintf(stderr, "Other\n"); */
1678 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1679 textfmt_s, boffset, clsstr, constr, tagstr,
1680 tname, name, lenbuf, empty);
1682 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1683 "(%s)%s: %s bytes %s data", tname, name,
1686 proto_item_append_text(ti, " *"); /* indicate default is used */
1687 offset += len; /* skip value ... */
1690 g_free(oname); /* XXX, memory management ? */
1692 /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1694 getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1701 /************************************************************************************************/
1702 /* search throug the ASN.1 description for appropriate names */
1703 /************************************************************************************************/
1705 guint lev_limit = G_MAXINT;
1707 int icount = 0; /* item counter */
1710 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1713 guint eos, ret, cls, con, tag, def, len, value;
1714 guchar *octets, *bits, unused;
1716 char *clsstr, *constr, *tagstr;
1719 GNode *cur_node = 0;
1721 eos = offset + size;
1723 if (level > lev_limit)
1726 while(offset < eos) {
1727 if (ptr) /* build pointer tree to all asn1 enteties */
1728 cur_node = g_node_append_data(ptr, (void *)offset);
1730 asn1_open(&asn1, tvb, offset);
1731 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1732 asn1_close(&asn1, &offset); /* mark where we are */
1734 clsstr = asn1_cls[cls];
1735 constr = asn1_con[con];
1736 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1737 tagstr = asn1_tag[tag];
1739 snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1743 snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1745 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1746 len = tvb_length_remaining(tvb, offset);
1750 case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
1754 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1755 asn1_close(&asn1, &offset); /* mark where we are */
1759 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1760 asn1_close(&asn1, &offset); /* mark where we are */
1771 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1772 asn1_close(&asn1, &offset); /* mark where we are */
1777 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1778 asn1_close(&asn1, &offset); /* mark where we are */
1784 if (len == 0) /* don't recurse if offset isn't going to change */
1787 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1794 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1795 asn1_close(&asn1, &offset); /* mark where we are */
1811 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1812 offset += len; /* skip value ... */
1817 case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
1819 snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
1821 /* defined length, not constructed, must be a string.... */
1822 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1823 asn1_close(&asn1, &offset); /* mark where we are */
1826 /* indefinite length or constructed.... must be a sequence .... */
1827 if (len == 0) /* don't recurse if offset isn't going to change */
1830 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1834 default: /* fprintf(stderr, "Other\n"); */
1835 if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1836 offset += len; /* skip value ... */
1843 void showGNodes(GNode *p, int n);
1846 myLeaf(GNode *node, gpointer data)
1849 guint ret, cls, con, tag, def, len;
1850 char *clsstr, *constr, *tagstr;
1854 (void) data; /* make a reference */
1855 asn1_open(&asn1, asn1_desc, (int)node->data);
1857 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1859 clsstr = asn1_cls[cls];
1860 constr = asn1_con[con];
1861 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1862 tagstr = asn1_tag[tag];
1864 snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1868 snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1870 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1874 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1882 if (asn1_verbose) g_message("build GNode tree:");
1883 showGNodes(g_node_first_child(asn1_nodes), 0);
1884 if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1885 g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1886 g_node_max_height (asn1_nodes),
1887 g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1888 g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1890 g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1895 tt_build_tree(void) /* build a GNode tree with all offset's to ASN.1 entities */
1898 g_node_destroy(asn1_nodes);
1899 asn1_nodes = g_node_new(0);
1901 parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1905 /*****************************************************************************************************/
1907 guint anonCount; /* for naming anonymous types */
1909 typedef struct _TBLModule TBLModule;
1910 typedef struct _TBLTypeDef TBLTypeDef;
1911 typedef struct _TBLTag TBLTag;
1912 typedef struct _TBLType TBLType;
1913 typedef struct _TBLTypeRef TBLTypeRef;
1914 typedef struct _TBLNamedNumber TBLNamedNumber;
1915 typedef struct _TBLRange TBLRange;
1923 TBLTYPE_NamedNumber,
1926 typedef enum _tbl_t tbl_t;
1927 /* text for 'tbl_t' type for debugging */
1928 char *data_types[] = { "Module",
1937 enum _TBLTypeContent_t {
1939 TBLTYPETYPE_Primitive,
1940 TBLTYPETYPE_Elements,
1943 typedef enum _TBLTypeContent_t TBLTypeContent_t;
1945 struct _TBLNamedNumber {
1957 struct _TBLTypeRef {
1973 TBLTypeContent_t content;
1976 gboolean constraint;
1979 struct _TBLTypeDef {
1994 guint totalNumModules;
1995 guint totalNumTypeDefs;
1996 guint totalNumTypes;
1998 guint totalNumStrings;
1999 guint totalLenStrings;
2002 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2005 get_asn1_int(guint want_tag, guint offset)
2008 guint ret, cls, con, tag, def, len;
2011 /* g_message("%d get_asn1_int", offset); */
2013 asn1_open(&asn1, asn1_desc, offset);
2015 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2016 if (ret == ASN1_ERR_NOERROR) {
2017 /* do not check class, both Unversal and Context are OK */
2018 if (con == ASN1_PRI && tag == want_tag) {
2020 asn1_uint32_value_decode(&asn1, len, &value);
2023 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2025 ret = ASN1_ERR_WRONG_TYPE;
2027 g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2032 subid_t * /* with prepended length ..... */
2033 get_asn1_oid(guint want_tag, guint offset)
2036 guint ret, cls, con, tag, def, len;
2039 /* g_message("%d get_asn1_oid", offset); */
2041 asn1_open(&asn1, asn1_desc, offset);
2043 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2044 if (ret == ASN1_ERR_NOERROR) {
2045 /* do not check class, both Unversal and Context are OK */
2046 if ((con == ASN1_PRI) && (tag == want_tag)) {
2048 asn1_oid_value_decode(&asn1, len, &oid, &con);
2049 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2050 memmove(&oid[1], oid, con*sizeof(guint));
2054 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2056 ret = ASN1_ERR_WRONG_TYPE;
2058 g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2063 guchar * /* 0 terminated string */
2064 get_asn1_string(guint want_tag, guint offset)
2067 guint ret, cls, con, tag, def, len;
2070 /* g_message("%d get_asn1_string", offset); */
2072 asn1_open(&asn1, asn1_desc, offset);
2074 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2075 if (ret == ASN1_ERR_NOERROR) {
2076 /* do not check class, both Unversal and Context are OK */
2077 if ((con == ASN1_PRI) && (tag == want_tag)) {
2079 asn1_string_value_decode(&asn1, len, &octets);
2080 octets = g_realloc(octets, len+1); /* need space for sentinel */
2084 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2086 ret = ASN1_ERR_WRONG_TYPE;
2088 g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2094 get_asn1_uint(guint offset)
2097 guint ret, len, value;
2099 /* g_message( "%d get_asn1_uint", offset); */
2101 asn1_open(&asn1, asn1_desc, offset);
2103 ret = asn1_uint32_decode(&asn1, &value, &len);
2105 if (ret != ASN1_ERR_NOERROR) {
2106 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2113 check_tag(guint want_tag, guint offset)
2116 guint ret, cls, con, tag, def, len;
2118 asn1_open(&asn1, asn1_desc, offset);
2120 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2121 if (ret == ASN1_ERR_NOERROR) {
2122 ret = (tag == want_tag) ? TRUE : FALSE;
2123 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2126 g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2132 constructed(guint offset)
2135 guint ret, cls, con, tag, def, len;
2137 /* g_message("%d constructed?", offset); */
2139 asn1_open(&asn1, asn1_desc, offset);
2141 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2142 if (ret == ASN1_ERR_NOERROR) {
2148 /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2154 define_constraint(GNode *p, GNode *q)
2156 TBLRange *range = g_malloc(sizeof(TBLRange));
2157 g_node_append_data(q, range);
2159 range->type = TBLTYPE_Range;
2161 /* g_message("define_constraint %p, %p", p, q); */
2163 p = g_node_first_child(p);
2165 range->from = get_asn1_int(0, (guint)p->data);
2166 p = g_node_next_sibling(p);
2168 range->to = get_asn1_int(1, (guint)p->data);
2173 define_namednumber(GNode *p, GNode *q)
2175 TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2176 g_node_append_data(q, num);
2178 num->type = TBLTYPE_NamedNumber;
2180 /* g_message("define_namednumber %p, %p", p, q); */
2182 p = g_node_first_child(p);
2184 num->name = get_asn1_string(0, (guint)p->data);
2185 p = g_node_next_sibling(p);
2187 num->value = get_asn1_int(1, (guint)p->data);
2191 define_typeref(GNode *p, GNode *q)
2193 TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2194 g_node_append_data(q, ref);
2196 ref->type = TBLTYPE_TypeRef;
2198 /* g_message("define_typeref %p, %p", p, q); */
2200 p = g_node_first_child(p);
2202 ref->typeDefId = get_asn1_uint((guint)p->data);
2203 p = g_node_next_sibling(p);
2205 ref->implicit = get_asn1_int(ASN1_BOL, (guint)p->data);
2209 define_tag(GNode *p, GNode *q)
2211 TBLTag *type = g_malloc(sizeof(TBLTag));
2212 g_node_append_data(q, type);
2214 type->type = TBLTYPE_Tag;
2216 /* g_message("define_tag %p, %p", p, q); */
2218 p = g_node_first_child(p);
2220 type->tclass = get_asn1_int(ASN1_ENUM, (guint)p->data);
2221 p = g_node_next_sibling(p);
2223 type->code = get_asn1_int(ASN1_INT, (guint)p->data);
2228 define_type(GNode *p, GNode *q)
2231 TBLType *type = g_malloc(sizeof(TBLType));
2233 GNode *t = g_node_append_data(q, type);
2235 type->type = TBLTYPE_Type;
2237 /* g_message("define_type %p, %p", p, q); */
2239 type->typeId = get_asn1_int(0, (guint)p->data);
2240 p = g_node_next_sibling(p);
2242 type->optional = get_asn1_int(1, (guint)p->data);
2243 p = g_node_next_sibling(p);
2245 if (check_tag(2, (guint)p->data)) { /* optional, need empty node if not there ?*/
2246 r = g_node_first_child(p);
2249 r = g_node_next_sibling(r);
2251 p = g_node_next_sibling(p);
2254 if (!check_tag(3, (guint)p->data)) {
2255 g_warning("expect tag 3, ERROR");
2257 r = g_node_first_child(p);
2259 type->content = TBLTYPETYPE_None;
2260 if (check_tag(0, (guint)r->data)) type->content = TBLTYPETYPE_Primitive;
2261 if (check_tag(1, (guint)r->data)) type->content = TBLTYPETYPE_Elements;
2262 if (check_tag(2, (guint)r->data)) type->content = TBLTYPETYPE_TypeRef;
2263 switch(type->content) {
2264 case TBLTYPETYPE_Primitive:
2266 case TBLTYPETYPE_Elements:
2267 r = g_node_first_child(r);
2269 define_type(g_node_first_child(r), t);
2270 r = g_node_next_sibling(r);
2273 case TBLTYPETYPE_TypeRef:
2274 define_typeref(r, t);
2276 case TBLTYPETYPE_None:
2277 g_warning("expected a contents choice, error");
2280 p = g_node_next_sibling(p);
2282 type->fieldName = 0;
2283 type->anonymous = FALSE;
2284 if (p && check_tag(4, (guint)p->data)) {
2285 type->fieldName = get_asn1_string(4, (guint)p->data);
2286 p = g_node_next_sibling(p);
2288 type->anonymous = TRUE;
2291 type->constraint = FALSE;
2292 if (p && check_tag(5, (guint)p->data)) {
2293 type->constraint = TRUE;
2294 define_constraint(p, t);
2295 p = g_node_next_sibling(p);
2298 if (p && check_tag(6, (guint)p->data)) {
2299 r = g_node_first_child(p);
2301 define_namednumber(r, t);
2302 r = g_node_next_sibling(r);
2308 define_typedef(GNode *p, GNode *q)
2310 TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2312 GNode *t = g_node_append_data(q, type_def);
2314 /* g_message("define_typedef %p, %p", p, q); */
2316 type_def->type = TBLTYPE_TypeDef;
2318 p = g_node_first_child(p);
2320 type_def->typeDefId = get_asn1_uint((guint)p->data);
2321 p = g_node_next_sibling(p);
2323 type_def->typeName = get_asn1_string(ASN1_PRNSTR, (guint)p->data);
2324 p = g_node_next_sibling(p);
2326 define_type(g_node_first_child(p), t);
2327 p = g_node_next_sibling(p);
2329 type_def->isPdu = (p != 0); /* true if it exists, value ignored */
2333 define_module(GNode *p, GNode *q)
2335 TBLModule *module = g_malloc(sizeof(TBLModule));
2337 GNode *m = g_node_append_data(q, module);
2339 /* g_message("define_module %p %p", p, q); */
2341 module->type = TBLTYPE_Module;
2343 p = g_node_first_child(p);
2345 module->name = get_asn1_string(0, (guint)p->data);
2346 p = g_node_next_sibling(p);
2349 if (check_tag(1, (guint)p->data)) { /* optional */
2350 module->id = get_asn1_oid(1, (guint)p->data);
2351 p = g_node_next_sibling(p);
2354 module->isUseful = get_asn1_int(2, (guint)p->data);
2355 p = g_node_next_sibling(p);
2357 p = g_node_first_child(p);
2359 define_typedef(p, m);
2360 p = g_node_next_sibling(p);
2364 typedef struct _SearchDef SearchDef;
2371 is_typedef(GNode *node, gpointer data)
2373 TBLTypeDef *d = (TBLTypeDef *)node->data;
2374 SearchDef *s = (SearchDef *)data;
2376 if (d == 0) return FALSE;
2377 if (d->type != TBLTYPE_TypeDef) return FALSE;
2378 if (strcmp(s->key, d->typeName) == 0) {
2385 typedef struct _TypeRef TypeRef;
2391 GNode *pdu; /* location in PDU descriptor tree */
2392 guint level; /* recursion counter */
2394 GPtrArray *refs; /* pointers to PDUinfo structures teferencing this entry */
2397 typedef struct _NameDefs NameDefs;
2403 #define ALLOC_INCR 4
2404 #define CLASSREF (ASN1_PRV+1)
2407 is_named(GNode *node, gpointer data)
2409 TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2410 NameDefs *n = (NameDefs *)data;
2413 if (num == 0) return FALSE;
2414 if (num->type != TBLTYPE_NamedNumber) return FALSE;
2416 if (num->value >= n->max) { /* need larger array */
2418 n->max = num->value + ALLOC_INCR;
2419 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2420 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2422 if (num->value > n->used) /* track max used value, there may be holes... */
2423 n->used = num->value;
2425 n->info[num->value].name = num->name;
2431 index_typedef(GNode *node, gpointer data)
2433 TBLTypeDef *d = (TBLTypeDef *)node->data;
2434 NameDefs *n = (NameDefs *)data;
2439 if (d == 0) return FALSE;
2440 if (d->type != TBLTYPE_TypeDef) return FALSE;
2442 if (d->typeDefId >= n->max) { /* need larger array */
2444 n->max = d->typeDefId + ALLOC_INCR;
2445 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2446 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2448 if (d->typeDefId > n->used) /* track max used value, there may be holes... */
2449 n->used = d->typeDefId;
2451 t = &(n->info[d->typeDefId]);
2452 t->name = d->typeName;
2454 t->refs = g_ptr_array_new(); /* collect references here */
2455 node = g_node_first_child(node); /* the real type */
2456 tag = (TBLTag *)node->data;
2457 if ((tag->type == TBLTYPE_Type) && (((TBLType *)tag)->typeId == TBL_CHOICE)) {
2458 /* no reasonable default... ! */
2459 t->defclass = 3; /* Private .... */
2460 t->deftag= 9999; /* a random value */
2462 node = g_node_first_child(node); /* the default tag */
2463 tag = (TBLTag *)node->data;
2466 t->defclass = tag->tclass;
2467 t->deftag = tag->code;
2469 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2470 t->defclass = CLASSREF; /* invalid class.. */
2471 t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2474 g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2475 data_types[tag->type]);
2476 t->defclass = 3; /* Private .... */
2477 t->deftag= 9998; /* another random value */
2485 TypeRef *typeDef_names = 0;
2486 guint numTypedefs = 0;
2489 get_values(void) /* collect values from ASN.1 tree */
2490 /* coded according to the tbl.asn1 description of snacc output */
2491 { /* This routine does not leave references to the tvbuff or */
2492 /* to the asn1_nodes, both can be freed by the caller of this.*/
2498 static char missing[] = " **missing** ";
2500 if (asn1_verbose) g_message("interpreting tree");
2501 typeDef_names = 0; /* just forget allocated any data .... */
2504 g_node_destroy(data_nodes);
2506 data_nodes = g_node_new(0);
2508 p = g_node_first_child(asn1_nodes); /* top of the data tree */
2510 p = g_node_first_child(p);
2511 TT.totalNumModules = get_asn1_uint((guint)p->data);
2512 p = g_node_next_sibling(p);
2513 TT.totalNumTypeDefs = get_asn1_uint((guint)p->data);
2514 p = g_node_next_sibling(p);
2515 TT.totalNumTypes = get_asn1_uint((guint)p->data);
2516 p = g_node_next_sibling(p);
2517 TT.totalNumTags = get_asn1_uint((guint)p->data);
2518 p = g_node_next_sibling(p);
2519 TT.totalNumStrings = get_asn1_uint((guint)p->data);
2520 p = g_node_next_sibling(p);
2521 TT.totalLenStrings = get_asn1_uint((guint)p->data);
2522 p = g_node_next_sibling(p);
2524 p = g_node_first_child(p);
2526 define_module(p, data_nodes);
2527 p = g_node_next_sibling(p);
2530 /* g_message("finished with tree"); */
2532 if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2533 sd.key = "TBLTypeId";
2535 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2536 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", sd.here);
2540 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2541 g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2543 if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, nd.info);
2545 for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2548 s = nd.info[i].name;
2549 if (s == 0) s = missing;
2550 if (g_strcmp(t, s) == 0) { /* OK ! */
2554 E = ", X with errors X";
2556 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2558 if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2560 tbl_types_verified = TRUE;
2562 /* build table with typedef names */
2565 nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2566 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2567 if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, nd.info);
2569 for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2570 TypeRef *ref = &(nd.info[i]);
2573 t = ref->name = missing;
2574 if (asn1_verbose) g_message(" %3d %s", i, t);
2576 if (asn1_verbose) g_message(" %3d %s, %c%d", i, t,
2577 tag_class[ref->defclass], ref->deftag);
2579 if (ref->pdu) { /* should be 0 */
2580 if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, ref->pdu);
2583 typeDef_names = nd.info;
2585 if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
2590 showGNode(GNode *p, int n)
2593 n *=2; /* 2 spaces per level */
2594 if (p->data) { /* show value ... */
2595 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
2596 switch (((TBLTag *)p->data)->type) {
2597 case TBLTYPE_Module: {
2598 TBLModule *m = (TBLModule *)p->data;
2600 g_message("%*smodule %s%s", n, empty, m->name,
2601 m->isUseful ? ", useful" : empty);
2604 case TBLTYPE_TypeDef: {
2605 TBLTypeDef *t = (TBLTypeDef *)p->data;
2607 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
2608 t->isPdu ? ", isPDU" : empty);
2611 case TBLTYPE_Type: {
2612 TBLType *t = (TBLType *)p->data;
2613 char *fn, *s = empty;
2616 /* typeId is a value from enum TBLTypeId */
2617 fn = TBLTYPE(t->typeId);
2618 if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
2619 t->optional ? " opt" : empty, s );
2623 TBLTag *t = (TBLTag *)p->data;
2625 if ((t->tclass == ASN1_UNI) && (t->code < 32))
2626 s = asn1_tag[t->code];
2627 if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
2628 tag_class[t->tclass], t->code, s);
2631 case TBLTYPE_NamedNumber: {
2632 TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
2633 if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
2634 nn->value, nn->name);
2637 case TBLTYPE_Range: {
2638 TBLRange *r = (TBLRange *)p->data;
2639 if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
2643 case TBLTYPE_TypeRef: {
2644 TBLTypeRef *r = (TBLTypeRef *)p->data;
2647 s = typeDef_names[r->typeDefId].name;
2648 if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
2649 r->typeDefId, s, r->implicit ? ", implicit" : empty );
2653 TBLTag *x = (TBLTag *)p->data;
2654 if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
2658 } else { /* just show tree */
2660 g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
2661 n, empty, p, p->data, p->next, p->prev, p->parent, p->children);
2666 showGNodes(GNode *p, int n)
2670 showGNodes(p->children, n+1);
2671 showGNodes(p->next, n);
2674 void showGenv(GNode *p, int n, int m)
2680 if (asn1_verbose) g_message("%*s.....", n*2, empty);
2684 for(i=0; p && (i < 3); p = p->next, i++) {
2686 showGenv(p->children, n+1, m);
2688 if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
2693 debug_dump_TT(void) /* dump contents of TT struct, for debugging */
2696 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
2698 TT.totalNumTypeDefs,
2702 TT.totalLenStrings);
2706 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
2707 const gchar *message, gpointer user_data)
2709 static FILE* logf = 0;
2710 static char eol[] = "\r\n";
2712 (void) log_domain; (void) log_level; (void) user_data; /* make references */
2714 if (logf == NULL && asn1_logfile) {
2715 logf = fopen(asn1_logfile, "w");
2718 fputs(message, logf);
2720 fflush(logf); /* debugging ... */
2725 read_asn1_type_table(char *filename)
2732 if ((filename == 0) || (strlen(filename) == 0))
2733 return; /* no filename provided */
2735 f = fopen(filename, "rb");
2738 * Ignore "file not found" errors if it's the old default
2739 * ASN.1 file name, as we never shipped such a file.
2740 * Also, on Win32, ignore the earlier default, which
2741 * had a "/" rather than a "\" as the last pathname
2744 if ((strcmp(filename, old_default_asn1_filename) != 0
2746 && strcmp(filename, bad_separator_old_default_asn1_filename) != 0
2748 ) || errno != ENOENT)
2749 report_open_failure(filename, errno, FALSE);
2752 fstat(fileno(f), &stat);
2753 size = (int)stat.st_size;
2755 if (asn1_verbose) g_message("file %s is empty, ignored", filename);
2759 if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
2761 data = g_malloc(size);
2762 if (fread(data, size, 1, f) < 1) {
2763 g_warning("error reading %s, %s", filename, strerror(errno));
2768 /* ***** from the time when logging was just in a console... *****
2769 * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
2770 * " Sleep 5 sec...");
2774 static guint mylogh = 0;
2776 g_message("logging to file %s", asn1_logfile);
2779 mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2780 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
2784 asn1_desc = tvb_new_real_data(data, size, size);
2787 if (asn1_verbose) g_message("read %d items from %s", icount, filename);
2789 /* list_modules(); */
2793 g_node_destroy(asn1_nodes); asn1_nodes = 0;
2794 #ifndef WIN32 /* tvb_free not yet exported to plugins... */
2795 tvb_free(asn1_desc);
2798 g_free(data); data = 0;
2800 showGNodes(data_nodes, 0);
2806 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
2807 g_warning("**** unexpected type %s, want %s, at line %d", \
2808 data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
2812 save_reference(PDUinfo *p)
2819 g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
2823 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex);
2827 /* evaluate typeref, pointer to current pdu node and typedef */
2829 tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
2832 PDUinfo *p = (PDUinfo *)pdu->data, *p1;
2836 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
2837 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
2841 CHECKTYPE(tree, TBLTYPE_TypeDef);
2843 if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
2844 p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2846 p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
2847 p->flags |= PDU_TYPEDEF;
2849 tree = g_node_first_child(tree); /* move to its underlying type */
2850 CHECKTYPE(tree, TBLTYPE_Type);
2851 p->type = ((TBLType *)tree->data)->typeId;
2853 q = g_node_first_child(tree); /* the tag of this type entry ... is optional... */
2854 if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
2855 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
2859 /* XXX -- hack -- hack -- hack -- hack -- hack --
2860 * only change tag when class+tag == EOC,
2861 * or class is a reference,
2862 * or new class is not universal.
2864 if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
2865 (((TBLTag *)q->data)->tclass != ASN1_UNI) ) {
2866 p->tclass = ((TBLTag *)q->data)->tclass;
2867 p->tag = ((TBLTag *)q->data)->code;
2869 g_message("%*s*change typeref tag from %c%d to %c%d",
2873 tag_class[p->tclass],
2877 g_message("%*sNOT changing tag from %c%d to %c%d",
2881 tag_class[((TBLTag *)q->data)->tclass],
2882 ((TBLTag *)q->data)->code);
2890 if (p->tclass==CLASSREF)
2891 snprintf(ss, 128, ", CLASSREF %d", p->tag);
2892 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
2894 if (p->tclass==CLASSREF) {
2896 int i = p->basetype;
2897 /* CLASSREF....., get it defined using type of the reference */
2899 /* p->basetype may be -1 .... ? XXX */
2902 tr = &typeDef_names[i];
2904 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
2905 p->tag, tr->name, tr->pdu);
2907 tbl_typeref(n+1, pdu, tr->type, fullindex);
2914 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
2915 p->name, p->typename, p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2919 case TBL_ENUMERATED:
2920 /* names do not have a fullname */
2921 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
2922 /* read the enumeration [save min-max somewhere ?] */
2923 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type]; /* XXX change field type... */
2925 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2930 g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2931 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2932 p->name, p->fullname,
2933 tbl_types_ethereal_txt[p->type], p->value_id);
2936 while((q = g_node_next_sibling(q))) {
2937 CHECKTYPE(q, TBLTYPE_NamedNumber);
2938 p = g_malloc0(sizeof(PDUinfo));
2940 p->type = TBL_ENUMERATED;
2941 p->name = (((TBLNamedNumber *)q->data)->name);
2942 p->tag = (((TBLNamedNumber *)q->data)->value);
2943 p->flags = PDU_NAMEDNUM;
2944 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
2945 g_node_append_data(pdu, p);
2948 /* list all enum values in the field structure for matching */
2949 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
2950 q = g_node_first_child(pdu);
2953 p = (PDUinfo *)q->data;
2954 v[nvals].value = p->tag;
2955 v[nvals].strptr = p->name;
2956 /* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
2958 q = g_node_next_sibling(q);
2960 /* last entry is already initialized to { 0, NULL } */
2965 if (p->value_id == -1) { /* not yet registered ..... */
2966 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
2967 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2972 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2973 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2974 p->name, p->fullname,
2975 tbl_types_ethereal_txt[p->type], p->value_id);
2977 tbl_type(n, pdu, q, fullindex);
2981 if (p->value_id == -1) { /* not yet registered ..... */
2982 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
2983 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2988 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2989 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2990 p->name, p->fullname,
2991 tbl_types_ethereal_txt[p->type], p->value_id);
2993 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
2998 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
3006 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
3007 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3011 /* showGenv(list, n, n+1); */
3014 pdu1 = pdu; /* save start location for append */
3015 while (list) { /* handle all entries */
3017 g_message("%*s+handle a %s, list=%p", n*2, empty,
3018 data_types[((TBLTag *)list->data)->type], list);
3020 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
3021 list = g_node_next_sibling(list);
3022 if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
3027 /******* change to positive comparation, but leave comment for reference
3028 * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3029 * CHECKTYPE(list, TBLTYPE_Type);
3032 if (((TBLTag *)list->data)->type == TBLTYPE_Type) {
3033 CHECKTYPE(list, TBLTYPE_Type);
3035 p = g_malloc0(sizeof(PDUinfo));
3036 pdu = g_node_append_data(pdu1, p);
3038 p->type = ((TBLType *)list->data)->typeId;
3039 p->typename = tbl_types_asn1[p->type]; /* the default type */
3042 p->basetype = ((PDUinfo *)pdu1->data)->typenum;
3043 p->flags = PDUinfo_initflags;
3044 p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
3045 p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
3047 if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
3048 /* assign an anonymous name [XXX refer to parent typename...] */
3049 ((TBLType *)list->data)->fieldName =
3050 g_strdup_printf("anon%d", anonCount++);
3052 p->name = ((TBLType *)list->data)->fieldName;
3055 ni += snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
3056 p->fullname = g_strdup(fieldname);
3058 /* initialize field info */
3061 p->value_hf.p_id = &(p->value_id);
3062 p->value_hf.hfinfo.name = p->fullname;
3063 p->value_hf.hfinfo.abbrev = p->fullname;
3064 p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
3065 p->value_hf.hfinfo.display = BASE_DEC;
3066 p->value_hf.hfinfo.blurb = p->fullname;
3067 /* all the other fields are already 0 ! */
3069 if (p->type < TBL__SIMPLE) {
3070 /* only register fields with a value here, postpone others */
3071 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3076 g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3077 p->mytype, p->typenum, p->basetype, p->flags,
3078 p->typename, p->name, p->fullname,
3079 tbl_types_ethereal_txt[p->type], p->value_id);
3082 q = g_node_first_child(list);
3084 p = (PDUinfo *)pdu->data;
3089 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
3094 case TBL_OCTETSTRING:
3098 CHECKTYPE(q, TBLTYPE_Tag);
3099 p->tclass = ((TBLTag *)q->data)->tclass;
3100 p->tag = ((TBLTag *)q->data)->code;
3104 case TBL_ENUMERATED:
3105 CHECKTYPE(q, TBLTYPE_Tag);
3106 p->tclass = ((TBLTag *)q->data)->tclass;
3107 p->tag = ((TBLTag *)q->data)->code;
3108 if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
3109 /* read the enumeration [save min-max somewhere ?] */
3112 while((q = g_node_next_sibling(q))) {
3113 CHECKTYPE(q, TBLTYPE_NamedNumber);
3114 p = g_malloc0(sizeof(PDUinfo));
3116 p->type = TBL_ENUMERATED;
3117 p->name = (((TBLNamedNumber *)q->data)->name);
3118 p->tag = (((TBLNamedNumber *)q->data)->value);
3119 p->flags = PDU_NAMEDNUM;
3120 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3121 g_node_append_data(pdu, p);
3124 /* list all enum values in the field structure for matching */
3125 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3126 q = g_node_first_child(pdu);
3129 p = (PDUinfo *)q->data;
3130 v[nvals].value = p->tag;
3131 v[nvals].strptr = p->name;
3132 /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3134 q = g_node_next_sibling(q);
3136 /* last entry is already initialized to { 0, NULL } */
3142 case TBL_SEQUENCEOF:
3145 CHECKTYPE(q, TBLTYPE_Tag);
3146 q = g_node_first_child(list);
3147 tbl_type(n+1, pdu, q, ni);
3150 case TBL_TYPEREF: { /* may have a tag ... */
3153 if ( q && (((TBLTag *)q->data)->type == TBLTYPE_Tag)) {
3154 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3155 p->tclass = ((TBLTag *)q->data)->tclass;
3156 p->tag = ((TBLTag *)q->data)->code;
3158 g_message("%*s*insert type tag %c%d", n*2, empty,
3159 tag_class[p->tclass], p->tag);
3161 q = g_node_next_sibling(q);
3162 } else { /* use default tag for this type */
3163 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3164 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != ASN1_UNI)) ||
3165 ((p->tclass | p->tag) == 0 )) {
3166 /* not implicit, use this tag */
3167 p->tclass = tr->defclass;
3168 p->tag = tr->deftag;
3169 if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3170 tag_class[p->tclass], p->tag);
3173 CHECKTYPE(q, TBLTYPE_TypeRef);
3174 i = ((TBLTypeRef *)q->data)->typeDefId;
3176 tr = &typeDef_names[i];
3178 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, tr->pdu);
3179 p->typename = tr->name;
3181 if (tr->defclass == CLASSREF) {
3183 tr->pdu = pdu; /* remember this reference */
3185 tr = &typeDef_names[i];
3187 g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3188 i, tr->name, tr->pdu);
3190 /* evaluate reference if not done before or when below recursion limit */
3191 if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3194 tr->pdu = pdu; /* save for references we leave */
3196 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3198 g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3200 ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3203 tbl_typeref(n+1, pdu, tr->type, ni);
3207 g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3208 p->name, tr->name, tr->pdu);
3209 p->flags |= PDU_REFERENCE;
3210 p->reference = tr->pdu;
3215 g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3220 g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3221 n*2, empty, p->name, p->typename, p, TBLTYPE(p->type),
3222 tag_class[p->tclass], p->tag);
3224 if (p->value_id == -1) { /* not registered before, do it now */
3225 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3230 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3231 p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3232 p->name, p->fullname,
3233 tbl_types_ethereal_txt[p->type], p->value_id);
3235 list = g_node_next_sibling(list);
3240 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
3243 char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3246 tt = TBLTYPE(info->type);
3248 tn = info->typename;
3249 fn = info->fullname;
3250 if (info->flags & PDU_NAMEDNUM)
3251 txt += sprintf(txt, "name: %2d %s", info->tag, nn);
3253 if (info->flags & PDU_TYPEDEF)
3254 txt += sprintf(txt, "def %d: ", info->typenum);
3256 txt += sprintf(txt, " ");
3257 ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3258 txt += sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3259 tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3260 txt += sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
3261 oo = (info->flags & PDU_OPTIONAL) ? ", optional" : empty;
3262 ii = (info->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3263 nn = (info->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3264 an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3265 txt += sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
3266 if (info->flags & PDU_REFERENCE) {
3267 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3268 tt = TBLTYPE(rinfo->type);
3270 tn = rinfo->typename;
3271 fn = rinfo->fullname;
3272 txt += sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3273 if (rinfo->flags & PDU_TYPEDEF)
3274 txt += sprintf(txt, " T%d", rinfo->typenum);
3275 txt += sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3276 oo = (rinfo->flags & PDU_OPTIONAL) ? ", optional" : empty;
3277 ii = (rinfo->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3278 nn = (rinfo->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3279 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3280 tt = (rinfo->flags & PDU_TYPEDEF) ? ", typedef" : empty;
3281 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3282 tr = (rinfo->flags & PDU_TYPETREE) ? ", typetree" : empty;
3283 txt += sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3287 strcpy(txt, "no info available");
3295 showPDUtree(GNode *p, int n)
3301 info = (PDUinfo *)p->data;
3303 PDUtext(text, info);
3305 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3307 showPDUtree(g_node_first_child(p), n+1);
3309 p = g_node_next_sibling(p);
3316 build_pdu_tree(char *pduname)
3319 guint pdudef, i, tcount;
3323 if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3327 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3329 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3330 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, sd.here, pdudef);
3332 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3336 /* initialize the PDU tree, hand craft the root entry */
3338 info = g_malloc0(sizeof(PDUinfo));
3339 info->name = pduname;
3340 info->typename = pduname;
3341 info->type = TBL_SEQUENCEOF;
3342 info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3343 info->flags = PDUinfo_initflags = 0;
3344 info->value_id = -1;
3346 info->basetype = -1;
3347 info->mytype = pdudef;
3349 info->value_hf.p_id = &(info->value_id);
3350 info->value_hf.hfinfo.name = info->fullname;
3351 info->value_hf.hfinfo.abbrev = info->fullname;
3352 info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
3353 info->value_hf.hfinfo.display = BASE_DEC;
3354 info->value_hf.hfinfo.blurb = info->fullname;
3356 anonCount = 0; /* anonymous types counter */
3358 PDUtree = g_node_new(info);
3359 pabbrev_pdu_len = sprintf(fieldname, "%s.%s.", pabbrev, pduname);
3360 sav_len = pabbrev_pdu_len;
3362 /* Now build the tree for this top level PDU */
3364 g_message("******** Define main type %d, %s", pdudef, pduname);
3365 tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1); /* strip initial . for new names */
3368 g_message("%d anonymous types", anonCount);
3370 /* Now make all types used available for matching */
3372 g_message("Define the types that are actually referenced through the top level PDU");
3373 for (i=0, tcount=0; i<numTypedefs; i++) {
3374 TypeRef *tr = &(typeDef_names[i]);
3376 if (tr->pdu) { /* ignore if not used in main pdu */
3379 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3381 g_message("******** Define type %d, %s", i, tr->name);
3383 /* .... do definition ..... */
3384 info = g_malloc0(sizeof(PDUinfo));
3385 info->name = tr->name;
3386 info->typename = tr->name;
3387 info->tclass = tr->defclass;
3388 info->tag = tr->deftag;
3389 info->type = TBL_TYPEREF;
3390 info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3391 info->flags = PDUinfo_initflags = PDU_TYPETREE;
3392 info->value_id = -1;
3394 info->basetype = -1;
3397 info->value_hf.p_id = &(info->value_id);
3398 info->value_hf.hfinfo.name = info->fullname;
3399 info->value_hf.hfinfo.abbrev = info->fullname;
3400 info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
3401 info->value_hf.hfinfo.display = BASE_DEC;
3402 info->value_hf.hfinfo.blurb = info->fullname;
3404 tr->typetree = g_node_new(info);
3405 pabbrev_pdu_len = sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
3406 tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3410 g_message("%d types used", tcount);
3412 pabbrev_pdu_len = sav_len;
3414 /* and show the result */
3416 g_message("Type index:");
3417 for (i=0; i<numTypedefs; i++) {
3418 TypeRef *tr = &(typeDef_names[i]);
3424 if (tr->pdu == 0) /* skip if not used */
3428 g_message(" %3d %s, %c%d, refs: %d",
3429 i, tr->name, tag_class[tr->defclass], tr->deftag,
3430 g_ptr_array_len(tr->refs));
3432 /* get defining node for this type */
3435 p = (PDUinfo *)(tr->typetree->data);
3436 defid = p->value_id;
3438 g_message(" -- defining id=%d", defid);
3440 for(j=0; j < g_ptr_array_len(tr->refs); j++) { /* show refs, and set type_id */
3441 p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3442 if (p->mytype == (gint)i)
3443 p->type_id = defid; /* normal reference */
3445 if ((p->flags & PDU_TYPETREE) == 0) {
3446 /* we have a primitive value, find its real type */
3447 for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3448 /* look at all refs */
3449 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3450 if ((q->flags & PDU_TYPETREE) == 0)
3451 continue; /* only type trees are interresting */
3452 if (q->type != p->type)
3453 continue; /* must be same types */
3454 if (strcmp(q->name, p->name) == 0) {
3455 /* OK, take the first we find, not entirely
3456 * correct, it may be from a different
3457 * base-base type...... XXX */
3458 p->type_id = q->value_id;
3467 g_message(" %s", text);
3473 g_message("The resulting PDU tree:");
3474 showPDUtree(PDUtree, 0);
3480 #ifdef DISSECTOR_WITH_GUI
3481 /* This cannot work in tethereal.... don't include for now */
3482 #if GTK_MAJOR_VERSION >= 2
3483 #define SHOWPDU /* this needs GTK2 */
3485 #endif /* DISSECTOR_WITH_GUI */
3488 static GtkWidget *window = NULL;
3490 /* the columns in the tree view */
3493 TITLE_COLUMN, /* text in this row */
3494 DEF_COLUMN, /* definition in this row, if any */
3495 REF_COLUMN, /* referennce from this column, if any */
3496 VALUE_COLUMN, /* indicate this is a value */
3497 NAME_COLUMN, /* name of this row */
3504 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3507 PDUinfo *info, *rinfo;
3514 info = (PDUinfo *)p->data;
3516 gtk_tree_store_append (store, &iter2, iter); /* Acquire iterator */
3518 PDUtext(text, info);
3521 if (info->flags & PDU_TYPEDEF)
3522 def = info->typenum;
3524 if (info->flags & PDU_REFERENCE) {
3525 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3526 ref = rinfo->typenum;
3528 pb = GTK_STOCK_CANCEL;
3529 if (G_NODE_IS_LEAF(p)) {
3530 if (info->flags & PDU_NAMEDNUM)
3531 pb = GTK_STOCK_BOLD;
3535 fprintf(namelist, "%16s %s\n",
3536 &(TBLTYPE(info->type)[4]), info->fullname);
3539 switch (info->type) {
3540 case TBL_ENUMERATED:
3544 fprintf(namelist, "%16s %s\n",
3545 &(TBLTYPE(info->type)[4]), info->fullname);
3552 gtk_tree_store_set (store, &iter2,
3557 NAME_COLUMN, info->fullname,
3560 build_tree_view(store, g_node_first_child(p), &iter2);
3562 p = g_node_next_sibling(p);
3574 #define PATHSTACKMAX 10
3575 GtkTreePath *pathstack[PATHSTACKMAX];
3576 gint pathstackp = 0;
3578 void add_path(GtkTreePath *p)
3580 if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
3581 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
3582 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
3585 pathstack[pathstackp++] = p;
3588 GtkTreePath *pop_path() {
3590 return pathstack[--pathstackp];
3594 gboolean find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
3598 struct DefFind *df = (struct DefFind *)data;
3600 gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
3602 if (def == df->def) {
3603 df->path = gtk_tree_path_copy (path);
3611 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
3614 GtkTreePath *path, *path2;
3615 gchar *text, *oldpath, *newpath;
3621 path = gtk_tree_path_copy (spath);
3623 gtk_tree_model_get_iter (model, &iter, path);
3624 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
3626 oldpath = gtk_tree_path_to_string(path);
3627 path2 = gtk_tree_path_copy (path);
3629 add_path(gtk_tree_path_copy(path));
3631 if (ref != -1) { /* this is a reference, find matching definition */
3634 gtk_tree_model_foreach (model, find_definition, &df);
3636 gtk_tree_path_free(path);
3639 } else { /* just move to the next entry, if it exists */
3640 gtk_tree_path_next(path2);
3642 if (gtk_tree_model_get_iter (model, &iter, path2)) {
3643 gtk_tree_path_free(path);
3644 path = path2; /* OK */
3646 if (gtk_tree_path_get_depth (path) > 1)
3647 gtk_tree_path_up (path);
3652 gtk_tree_path_free (path2);
3654 gtk_tree_view_expand_to_path (treeview, path);
3655 gtk_tree_view_expand_row (treeview, path, FALSE);
3657 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3659 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3661 newpath = gtk_tree_path_to_string(path);
3664 g_message("my_signal_handler: treeview=%p, moveing from %s to %s",
3665 treeview, oldpath, newpath);
3671 /* gtk_tree_path_free(df.path); */
3676 menuitem_cb (gpointer callback_data,
3677 guint callback_action,
3681 GtkTreeModel *model;
3682 GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
3683 GtkTreeSelection *selection;
3688 gchar *oldpath, *newpath;
3689 GtkTreeViewColumn *focus_column;
3691 selection = gtk_tree_view_get_selection(treeview);
3693 model = gtk_tree_view_get_model(treeview);
3694 gtk_tree_view_get_cursor (treeview, &path, &focus_column);
3696 if (gtk_tree_model_get_iter (model, &iter, path)) {
3698 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
3699 NAME_COLUMN, &name, -1);
3700 oldpath = gtk_tree_path_to_string(path);
3703 switch (callback_action) {
3704 case 0: /* Select */
3705 gtk_tree_selection_select_path (selection, path);
3710 gtk_tree_view_expand_to_path (treeview, path);
3711 gtk_tree_view_expand_row (treeview, path, FALSE);
3713 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3715 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3717 newpath = gtk_tree_path_to_string(path);
3719 gtk_tree_path_free(path);
3721 newpath = g_strdup("** no path **");
3723 g_message("menueitem_cb: treeview=%p, moveing from %s to %s",
3724 treeview, oldpath, newpath);
3728 /* get all non anonymous names to the root */
3731 dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
3732 GTK_DIALOG_DESTROY_WITH_PARENT,
3735 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
3736 gtk_item_factory_path_from_widget (widget),
3737 callback_action, text, oldpath, newpath, name);
3739 /* Close dialog on user response */
3740 g_signal_connect (dialog,
3742 G_CALLBACK (gtk_widget_destroy),
3745 gtk_widget_show (dialog);
3750 if (newpath != empty)
3754 g_message("menuitem_cb: no iterator...");
3757 static GtkItemFactoryEntry menu_items[] = {
3758 { "/Select", NULL, menuitem_cb, 0, NULL, 0 },
3759 { "/Back", "<control>B", menuitem_cb, 1, NULL, 0 },
3760 { "/Find", "<control>F", menuitem_cb, 2, NULL, 0 },
3761 { "/Save", "<control>S", menuitem_cb, 3, NULL, 0 },
3764 static gint button_press_callback( GtkWidget *widget,
3765 GdkEventButton *event,
3768 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
3770 /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
3771 * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
3774 if (event->button == 3) {
3775 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
3782 return FALSE; /* continue handling this event */
3787 create_message_window()
3789 GtkCellRenderer *renderer;
3790 GtkTreeStore *model;
3793 GtkWidget *treeview;
3795 GtkItemFactory *item_factory;
3796 GtkAccelGroup *accel_group;
3797 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3801 /* create window, etc */
3802 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3803 gtk_window_set_title (GTK_WINDOW (window), current_pduname);
3804 g_signal_connect (window, "destroy",
3805 G_CALLBACK (gtk_widget_destroyed), &window);
3807 vbox = gtk_vbox_new (FALSE, 8);
3808 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3809 gtk_container_add (GTK_CONTAINER (window), vbox);
3811 text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
3813 gtk_box_pack_start (GTK_BOX (vbox),
3814 gtk_label_new (text),
3818 sw = gtk_scrolled_window_new (NULL, NULL);
3819 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
3820 GTK_SHADOW_ETCHED_IN);
3821 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
3822 GTK_POLICY_AUTOMATIC,
3823 GTK_POLICY_AUTOMATIC);
3824 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3826 model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3827 G_TYPE_STRING, G_TYPE_STRING);
3829 namelist = fopen("namelist.txt", "w");
3830 build_tree_view(model, PDUtree, NULL);
3834 /* create tree view */
3835 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
3836 g_object_unref (model);
3837 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
3838 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
3839 GTK_SELECTION_MULTIPLE);
3841 renderer = gtk_cell_renderer_text_new ();
3843 #if 0 /* testing pango attributes */
3846 PangoAttrList* attr;
3848 attr = pango_attr_list_new();
3849 bg = pango_attr_background_new(50000,55000,50000);
3850 bg->start_index = 0;
3851 bg->end_index = 10000;
3852 pango_attr_list_insert(attr, bg);
3854 g_object_set(renderer, "attributes", attr, NULL);
3856 #endif /* testing pango attributes */
3858 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3859 TITLE_COLUMN, "asn1 entities", renderer,
3860 "text", TITLE_COLUMN, NULL );
3862 /* renderer = gtk_cell_renderer_text_new ();
3863 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3864 * DEF_COLUMN, "type definition", renderer,
3865 * "text", DEF_COLUMN, NULL );
3867 * renderer = gtk_cell_renderer_text_new ();
3868 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3869 * REF_COLUMN, "reference", renderer,
3870 * "text", REF_COLUMN, NULL );
3872 renderer = gtk_cell_renderer_pixbuf_new ();
3873 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3874 VALUE_COLUMN, "value", renderer,
3875 "stock_id", VALUE_COLUMN, NULL );
3877 renderer = gtk_cell_renderer_text_new ();
3878 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3879 NAME_COLUMN, "fieldname", renderer,
3880 "text", NAME_COLUMN, NULL );
3882 gtk_container_add (GTK_CONTAINER (sw), treeview);
3884 /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
3888 accel_group = gtk_accel_group_new ();
3890 /* This function initializes the item factory.
3891 * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
3892 * or GTK_TYPE_OPTION_MENU.
3893 * Param 2: The path of the menu.
3894 * Param 3: A pointer to a gtk_accel_group. The item factory sets up
3895 * the accelerator table while generating menus.
3898 item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
3900 /* This function generates the menu items. Pass the item factory,
3901 the number of items in the array, the array itself, and any
3902 callback data for the the menu items. */
3903 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
3905 /* Attach the new accelerator group to the window. */
3906 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
3909 /* expand all rows after the treeview widget has been realized */
3910 g_signal_connect (treeview, "realize",
3911 G_CALLBACK (gtk_tree_view_expand_all), NULL);
3912 g_signal_connect (treeview, "row-activated",
3913 G_CALLBACK (my_signal_handler), (gpointer)model);
3915 g_signal_connect (treeview, "button_press_event",
3916 G_CALLBACK (button_press_callback), item_factory);
3918 /* g_signal_connect_swapped (treeview, "event",
3919 * G_CALLBACK (button_press_handler),
3922 gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
3925 if (!GTK_WIDGET_VISIBLE (window))
3926 gtk_widget_show_all (window);
3929 gtk_widget_destroy (window);
3933 #endif /* SHOWPDU */
3935 /************************************************************************************************
3936 * routines to find names to go with the decoded data stream *
3937 ************************************************************************************************/
3938 typedef struct _statestack statestack;
3939 struct _statestack {
3947 #define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
3948 #define STORENODE(x) { PDUstate[PDUstatec-1] = (x); }
3949 #define POPSTATE PDUstate[--PDUstatec]
3950 #define GETSTATE PDUstate[PDUstatec-1]
3951 #define GETNAME (((PDUinfo *)pos.node->data)->name)
3952 #define TYPENAME (((PDUinfo *)pos.node->data)->typename)
3953 #define GETTYPE (((PDUinfo *)pos.node->data)->type & TBL_TYPEmask)
3954 #define GETFLAGS (((PDUinfo *)pos.node->data)->flags)
3955 #define GETINFO ((PDUinfo *)pos.node->data)
3956 #define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
3957 #define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
3958 #define MATCH ((class == info->tclass) && (tag == info->tag))
3959 #define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
3960 #define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
3961 #define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
3962 #define ISCHOICE (info && (info->flags & PDU_CHOICE))
3963 #define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
3966 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
3967 pos.node=0;PUSHNODE(pos);return ret;}}
3971 showstack(statestack *pos, char *txt, int n)
3973 char buf[1024], *name, *type, *stype;
3974 char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
3980 if ( ! asn1_verbose)
3986 g_message("==underflow");
3989 rep = chs = done = ref = pop = chr = rch = sch = con = empty;
3993 name = ((PDUinfo *)g->data)->name;
3994 type = TBLTYPE(((PDUinfo *)g->data)->type);
3996 name = "node<null>";
4000 stype = TBLTYPE(typef);
4001 if (typef & TBL_REPEAT) rep = "[repeat]";
4002 if (typef & TBL_CHOICE_made) chs = "[choice]";
4003 if (typef & TBL_SEQUENCE_done) done = "[done]";
4004 if (typef & TBL_REFERENCE) ref = "[ref]";
4005 if (typef & TBL_REFERENCE_pop) pop = "[ref-pop]";
4006 if (typef & TBL_CHOICE_repeat) chr = "[chs-rep]";
4007 if (typef & TBL_REPEAT_choice) rch = "[rep-chs]";
4008 if (typef & TBL_SEQUENCE_choice)sch = "[seq-chs]";
4009 if (typef & TBL_CONSTRUCTED) con = "[constr]";
4011 i = sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
4012 pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4013 pos->name, pos->offset);
4015 for(j=1, n--; n>0; j++, n--) {
4016 p = &PDUstate[PDUstatec-j];
4018 stype = TBLTYPE(typef);
4019 rep = (typef & TBL_REPEAT) ? "[repeat]" : empty;
4020 chs = (typef & TBL_CHOICE_made) ? "[choice]" : empty;
4021 done = (typef & TBL_SEQUENCE_done) ? "[done]" : empty;
4022 ref = (typef & TBL_REFERENCE) ? "[ref]" : empty;
4023 pop = (typef & TBL_REFERENCE_pop) ? "[ref-pop]" : empty;
4024 chr = (typef & TBL_CHOICE_repeat) ? "[chs-rep]" : empty;
4025 rch = (typef & TBL_REPEAT_choice) ? "[rep-chs]" : empty;
4026 sch = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
4027 con = (typef & TBL_CONSTRUCTED) ? "[constr]" : empty;
4029 i += sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
4030 p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4031 p->name, p->offset);
4037 showrefNode(GNode *node, int n)
4039 char *name = empty, *type = empty, *tname = empty;
4040 int cls = 0, tag = 0;
4045 g_message("%*sstop, nesting too deep", 2*n, empty);
4049 info = (PDUinfo *)(node->data);
4050 type = TBLTYPE(info->type);
4052 tname = info->typename;
4053 ref = info->reference;
4057 g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4058 2*n, empty, tname, type, name, node, node->data,
4059 ref, tag_class[cls], tag);
4062 showrefNode(ref, n+1);
4066 showNode(GNode *node, int n, int m)
4068 char *name = empty, *type = empty;
4075 type = TBLTYPE(((PDUinfo *)(node->data))->type);
4076 name = ((PDUinfo *)(node->data))->name;
4077 ref = ((PDUinfo *)(node->data))->reference;
4079 g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4080 2*n, empty, type, name, node, node->data, node->next, node->prev,
4081 node->parent, node->children);
4084 g_message("%*sstop, nesting too deep", 2*n, empty);
4088 if (ref) showrefNode(ref, n+2);
4090 if (node->children) showNode(node->children, n+1, m);
4091 if (node->next) showNode(node->next, n, m);
4095 PDUreset(int count, int count2)
4099 if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
4101 PDUstatec = 0; /* stackpointer */
4102 PDUerrcount = 0; /* error counter per asn.1 message */
4104 pos.node = 0; /* sentinel */
4105 pos.name = "sentinel";
4106 pos.type = TBL_SEQUENCEOF;
4111 pos.node = PDUtree; /* root of the tree */
4113 pos.type = GETTYPE | TBL_REPEAT;
4119 GNode * /* find GNode for a choice element, 0 if none */
4120 makechoice(GNode *p, guint class, guint tag)
4125 p = g_node_first_child(p); /* the list of choices */
4126 info = 0; /* avoid gcc warning */
4129 info = ((PDUinfo *)p->data);
4131 if (info->type == TBL_CHOICE) {
4133 g_message(" using sub choice (%s)%s", info->typename, info->name);
4135 q = makechoice(p, class, tag);
4136 if (q) { /* found it */
4138 info = ((PDUinfo *)p->data);
4140 } /* continue with this level */
4144 g_message(" have %c%d, found %c%d, %s", tag_class[class], tag,
4145 tag_class[info->tclass], info->tag, info->name);
4147 if ((class == info->tclass) && (tag == info->tag))
4148 break; /* found it */
4151 p = g_node_next_sibling(p);
4154 if (p) g_message(" OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
4156 else g_message(" ...no matching choice...");
4161 /* offset is for debugging only, a reference to output on screen */
4163 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
4165 statestack pos, pos2, save_pos;
4168 int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4169 static char namestr[64]; /* enough ? */
4170 static char posstr[40];
4171 static char noname[] = "*noname*";
4172 static PDUprops constructed_save; /* for unexpectedly constructed enteties */
4174 if (PDUstatec > 0) /* don't read from below the stack */
4176 /* pos refers to the last asn1 node handled */
4178 /* a very simple, too simple??, way to handle constructed entities */
4179 if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4180 /* unexpectedly constructed, return same info as last time */
4181 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4182 showstack(&pos, posstr, 3);
4183 pos.offset = offset;
4184 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4185 PUSHNODE(pos); /* push extra, to match with a EOI operation */
4186 PUSHNODE(pos); /* restore the stack */
4187 *out = constructed_save;
4189 g_message(" return for constructed %s (%s)%s",
4190 TBLTYPE(out->type), out->typename, out->name);
4194 save_pos = pos; /* may need it again */
4198 out->typename = "*error*";
4205 if (PDUstatec <= 0) {
4206 if (PDUstatec > -10) {
4208 g_message(">>off=%d stack underflow, return", offset);
4210 if (PDUstatec == -10) {
4212 g_message(">>off=%d stack underflow, return, no more messages", offset);
4214 out->name = "*underflow*";
4215 out->flags |= OUT_FLAG_noname;
4219 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4221 showstack(&pos, posstr, 3);
4225 if (class == ASN1_EOI) { /* end of this input sequence */
4227 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4228 if (asn1_verbose) g_message(" EOI: reference pop");
4231 switch(pos.type & TBL_TYPEmask) {
4233 if (asn1_verbose) g_message(" EOI: pop typeref");
4234 pos = POPSTATE; /* remove typeref */
4236 case TBL_CHOICE_done:
4237 if (asn1_verbose) g_message(" EOI: mark choice");
4239 pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4247 pos = POPSTATE; /* this is pushed back on the stack later */
4248 if (pos.node == 0) {
4249 if (asn1_verbose) g_message(" EOI, pos.node == 0");
4250 out->name = "*no-name-EOI*";
4251 out->flags |= OUT_FLAG_noname;
4258 tmp = TBLTYPE(info->type);
4259 if (offset != pos.offset) {
4261 g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4262 tmp, ret, offset, pos.offset);
4263 while ((offset < pos.offset) && (PDUstatec > 0)) {
4266 g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
4267 offset, pos.offset);
4269 if (offset != pos.offset)
4270 PDUerrcount++; /* only count if still unequal */
4272 if (asn1_verbose) g_message(" EOI %s:%s OK, offset=%d", tmp, ret, offset);
4275 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4276 * indicated by the synthetic EOI call. */
4277 if ((class == ASN1_UNI) && (tag == ASN1_EOC)) { /* explicit EOC never has a name */
4278 PUSHNODE(pos); /* restore stack */
4279 ret = "explicit-EOC";
4280 if (asn1_verbose) g_message(" return '%s', ignore", ret);
4282 out->typename = "ASN1";
4286 /* find appropriate node for this tag */
4288 if (pos.node == 0) {
4289 if (asn1_verbose) g_message(" pos.node == 0");
4290 out->name = "*no-name*";
4291 out->flags |= OUT_FLAG_noname;
4296 /* showNode(pos.node, 3, 4); */
4298 switch (pos.type & TBL_TYPEmask) {
4299 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4303 if (pos.type & TBL_CHOICE_made) {
4304 if (asn1_verbose) g_message(" finish choice");
4312 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4313 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4315 if (asn1_verbose) g_message(" repeating choice"); /* ignore repeat */
4318 if (asn1_verbose) g_message(" seqof: repeat start");
4319 /* decide how to continue, CHILD for next instance of sequence
4320 * or NEXT for end of repeated sequence.
4321 * use the tag to make a descision */
4322 if (asn1_verbose) g_message(" seqof: first got %c%d, found %c%d",
4323 tag_class[class], tag,
4324 tag_class[info->tclass], info->tag);
4326 /* This is the start of repeating */
4329 if (asn1_verbose) g_message(" return for repeat '%s'", ret);
4330 out->type = (pos.type & TBL_TYPEmask);
4331 out->typename = info->typename;
4333 out->value_id = info->value_id;
4334 out->type_id = info->type_id;
4336 if (asn1_verbose) g_message(" anonymous: dontshow");
4338 out->flags |= OUT_FLAG_dontshow;
4344 /* find out where to go .... */
4346 CHILD; /* assume sequence is repeated */
4348 info = GETINFO; /* needed for MATCH to look ahead */
4350 g_message(" seqof: child: got %c%d, found %c%d",
4351 tag_class[class], tag,
4352 tag_class[info->tclass], info->tag);
4354 if (pos2.type & TBL_CHOICE_repeat) {
4357 g_message(" repeating a choice, %s",
4359 pos.type = TBL_CHOICE_immediate;
4361 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4362 donext = 1; /* move on */
4364 g_message(" seqof: no repeat, force next");
4366 /* following code will take the child again */
4372 } else if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4373 if (asn1_verbose) g_message(" reference pop, donext");
4376 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4377 if (pos.type & TBL_SEQUENCE_choice) {
4378 pos = POPSTATE; /* expect to find a repeat here */
4381 if (asn1_verbose) g_message(" sequence done, donext");
4385 if (pos.type & TBL_REFERENCE) {
4386 if (asn1_verbose) g_message(" reference change ref -> pop");
4387 pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4390 pos.offset = offset;
4392 ret = pos.name; /* for the debug messages */
4395 if (asn1_verbose) g_message(" donext");
4398 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4399 case TBL_SETOF: /* ?? */
4400 case TBL_SEQUENCEOF:
4401 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4402 pos.type |= TBL_REPEAT;
4406 /* remember this is the start of a repeat cycle */
4407 typeflags |= TBL_REPEAT;
4409 g_message(" seqof: set repeat mark [push,child]");
4412 g_message(" seqof: end of reapeat loop [next]");
4416 case TBL_SET: /* ?? */
4418 pos.type |= TBL_SEQUENCE_done;
4422 if (asn1_verbose) g_message(" seq [push,child]");
4425 /* no more choice */
4426 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4429 pos.type = 0; /* clear all type flags */
4431 g_message(" choice [push], %c%d, %s",
4432 tag_class[info->tclass], info->tag, GETNAME);
4433 pos.node = makechoice(pos.node, class, tag);
4434 if (pos.node == 0) {
4436 out->flags |= OUT_FLAG_noname;
4443 g_message(" '%s' %c%d will be used",
4444 ret, tag_class[info->tclass], info->tag);
4446 case TBL_CHOICE_done:
4452 if (asn1_verbose) g_message(" typeref [pop,next]");
4454 case TBL_ENUMERATED:
4456 /* skip named numbers now, call to PDUenum() will retrieve a name */
4459 case TBL_CHOICE_immediate:
4460 if (asn1_verbose) g_message(" immediate choice [no next]");
4469 if (pos.node == 0) {
4470 ret = "*no-name-2*";
4471 if (asn1_verbose) g_message(" return '%s'", ret);
4473 out->flags |= OUT_FLAG_noname;
4477 ret = pos.name = GETNAME;
4478 pos.type = GETTYPE | (pos.type & ~TBL_TYPEmask);
4481 /* pos now points to the prospective current node, go check it ********************/
4482 if (asn1_verbose) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4483 (ISOPTIONAL)?", optional":empty,
4484 (ISIMPLICIT)?", implicit":empty,
4485 tag_class[info->tclass], info->tag );
4487 if (ISOPTIONAL) { /* must check the tag */
4488 while(! MATCH) { /* check optional here again...? */
4490 g_message(" got %c%d, found %c%d", tag_class[class], tag,
4491 tag_class[info->tclass], info->tag);
4493 if (pos.node == 0) {
4496 pos = save_pos; /* reset for next time */
4497 pos.type |= TBL_SEQUENCE_done;
4499 pos.type &= ~TBL_SEQUENCE_done;
4501 out->flags |= OUT_FLAG_dontshow;
4503 g_message(" end of optional list, constructed, expect value next time");
4506 out->flags |= OUT_FLAG_noname;
4508 g_message(" *end of optional list...");
4509 info = 0; /* this is not valid any more... */
4511 break; /* end of list */
4514 if (asn1_verbose) g_message(" optional, %s", GETNAME);
4516 if (pos.node && ! cons_handled) {
4517 ret = pos.name = GETNAME;
4520 /* pos now refers to node with name we want, optional nodes skipped */
4523 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4524 pos2 = pos; /* save current state */
4528 g_message(" already pushed, skip next push");
4530 typeflags &= ~TBL_CHOICE_made;
4534 g_message(" immediate choice [push], %c%d, %s",
4535 tag_class[info->tclass], info->tag, GETNAME);
4536 pos.node = makechoice(pos.node, class, tag);
4537 if (pos.node == 0) {
4543 out->type = (pos.type & TBL_TYPEmask);
4544 out->flags |= OUT_FLAG_type;
4546 sprintf(namestr, "%s!%s", ret, GETNAME);
4549 g_message(" %s:%s will be used", TBLTYPE(pos.type), ret);
4550 if (typeflags & TBL_REPEAT) {
4551 pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
4553 pos.type |= TBL_SEQUENCE_choice;
4556 g_message(" return from immediate choice [%s] '%s'",
4557 TBLTYPE(pos.type), ret);
4559 out->data = pos.node; /* for access to named numbers... */
4561 out->type = (pos.type & TBL_TYPEmask);
4564 out->typename = info->typename;
4565 out->fullname = info->fullname;
4566 out->value_id = info->value_id;
4567 out->type_id = info->type_id;
4572 typeflags |= TBL_CHOICE_made;
4575 if (asn1_verbose) g_message(" matching choice '%s'", ret);
4577 if ( ! cons ) { /* ISIMPLICIT was not OK for all */
4578 pos = pos2; /* reset for continuation */
4583 g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4584 (ISOPTIONAL)?", optional":empty,
4585 (ISIMPLICIT)?", implicit":empty,
4586 tag_class[info->tclass], info->tag );
4588 g_message(" using: unknown '%s'", ret);
4591 /* must follow references now */
4592 if (pos.type == TBL_TYPEREF) {
4593 out->typename = info->typename;
4594 out->type_id = info->typenum;
4595 out->flags |= OUT_FLAG_typename;
4597 PUSHNODE(pos); /* remember where we were */
4598 if (asn1_verbose) g_message(" typeref [push]");
4599 typeflags |= TBL_REFERENCE;
4600 if (info->reference == 0) { /* resolved ref to universal type.... */
4601 /* showNode(pos.node, 3, 4); */
4602 pos.type = GETTYPE; /* the resulting type */
4604 tmp = "inknown tag";
4605 if ((info->tclass == ASN1_UNI) && (info->tag < 31)) {
4606 tmp = asn1_tag[info->tag];
4607 pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
4610 g_message(" indirect typeref to %s:%s, %s [%c%d]",
4611 TBLTYPE(pos.type), info->typename, tmp,
4612 tag_class[info->tclass], info->tag );
4614 out->fullname = info->fullname;
4615 donext = (ISANONYMOUS); /* refereing entity has no name ? */
4616 pos.node = info->reference;
4620 g_message(" typeref %s %s", TBLTYPE(pos.type), GETNAME);
4621 /* keep name from before going through the reference, unless anonymous */
4622 if (donext) /* refering entity has no name */
4623 ret = GETNAME; /* a better name */
4625 /* handle choice here ? !!mm!! */
4627 out->type = (pos.type & TBL_TYPEmask);
4628 out->flags |= OUT_FLAG_type;
4629 /* showNode(pos.node, 3, 4); */
4632 out->data = pos.node;
4633 out->flags |= OUT_FLAG_data;
4635 g_message(" typeref set named number list node %p", pos.node);
4639 pos.type = TBL_TYPEREF_nopop;
4640 if (asn1_verbose) g_message(" typeref pop");
4641 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
4642 /* do not enter the named-number list */
4644 pos.type = TBL_TYPEREF_nopop;
4645 if (asn1_verbose) g_message(" typeref [pop]");
4647 typeflags |= TBL_REFERENCE;
4652 if (cons && ! cons_handled) { /* This entity is constructed, expected ? */
4654 case TBL_BOOLEAN: /* these are not expected to be constructed */
4656 case TBL_OCTETSTRING:
4660 case TBL_ENUMERATED:
4662 typeflags |= TBL_CONSTRUCTED;
4663 /* this entry has no extra info, next is the same */
4664 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
4665 if (asn1_verbose) g_message(" dontshow and set constructed flag");
4667 default: /* others, such as sequences, are expected to be constructed */
4674 if (asn1_verbose) g_message(" anonymous: dontshow");
4675 if (asn1_debug) /* this entry has no extra info, next is the same */
4676 out->flags |= OUT_FLAG_dontshow;
4678 out->name = empty; /* show it, but no name */
4681 if (out->name != empty)
4684 if ( ! (out->flags & OUT_FLAG_data))
4685 out->data = pos.node; /* for access to named numbers... */
4687 pos.type |= typeflags;
4690 if ( ! (out->flags & OUT_FLAG_type))
4691 out->type = pos.type;
4693 out->type &= TBL_TYPEmask;
4695 if (ret == noname) {
4697 out->flags |= OUT_FLAG_noname;
4700 if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
4701 out->typename = info->typename;
4702 out->type_id = info->typenum;
4705 if (info && (out->value_id == -1)) {
4706 out->value_id = info->value_id;
4707 out->type_id = info->type_id;
4710 if ((out->fullname == 0) && info)
4711 out->fullname = info->fullname;
4713 if (typeflags & TBL_CONSTRUCTED)
4714 constructed_save = *out;
4717 g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
4718 out->value_id, out->type_id);
4724 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
4729 static char unnamed[] = "*unnamed*";
4731 (void) cls; (void) tag; /* make a reference */
4733 if (props->flags & OUT_FLAG_noname)
4737 list = (GNode *)props->data;
4740 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
4742 return "*list-still-0*";
4745 if ((PDUinfo *)list->data)
4746 name = ((PDUinfo *)list->data)->name;
4750 for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
4751 info = (PDUinfo *)list->data;
4752 if (value == info->tag) {
4761 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
4765 #endif /* READSYNTAX */
4767 /* * * * * * * * * * * * * * * * * * * * * * * * */
4768 /* Routines to handle parsing a list of ports */
4769 /* * * * * * * * * * * * * * * * * * * * * * * * */
4771 #define SKIPWHITE(_s) { while(isspace(*(_s))) { (_s)++; } }
4773 /* insert error text in front of spec
4774 * with a delimeter we can recognize on next attempt
4776 void insert_error(gchar *s, int len, gchar *err, guint mark)
4784 mark = (mark < slen) ? mark : slen; /* clamp mark within the string */
4786 snprintf(news, len, "[%s] %.*s|%s", err, (int)mark, s, s + mark);
4787 strncpy(s, news, len);
4791 /* parse a range of port numbers: a,b-c,d
4793 GSList *parse_port_range(gchar *s, int len)
4795 GSList *list = NULL;
4796 guint n, count, fill, fillstart = 0;
4801 if (s == 0) return 0;
4806 if (*es == '[') { /* an old error message */
4807 while(*es != ']') { es++; };
4811 memmove(orgs, es, strlen(es)+1); /* remove old error message */
4817 SKIPWHITE(s); /* for better position of error indicator */
4818 n = strtoul(s, &es, 0);
4819 if ( (s == es) || /* no character processed */
4820 (n > 0xffff) ) { /* port number out of range */
4822 if (s == es) es++; /* err indicator after error pos */
4823 insert_error(orgs, len, "syntax error", es - orgs);
4824 g_slist_free (list);
4826 } else { /* OK, have a port number */
4827 if (fill) { /* create a range of numbers */
4829 while(++fillstart < n) {
4830 list = g_slist_append (list, GINT_TO_POINTER (fillstart));
4833 insert_error(orgs, len, "too many ports", es - orgs);
4834 g_slist_free (list);
4839 list = g_slist_append (list, GINT_TO_POINTER (n));
4845 continue; /* a missig comma is OK */
4848 case ',': /* on to the next port number */
4850 case '-': /* start a port range */
4854 case '\0': /* OK, finished */
4856 default: /* some error */
4857 insert_error(orgs, len, "invalid character", es - orgs);
4858 g_slist_free (list);
4867 /* build text representation of given port list
4869 void show_port_range(GSList *list, gchar *buf, int len)
4872 int this, last, size;
4877 this = GPOINTER_TO_INT(list->data);
4878 if ((last+1) == this) {
4883 size += snprintf(&buf[size], len - size, "%c%d", delim, last);
4887 buf[size++] = delim;
4888 size += snprintf(&buf[size], len - size, "%d", this);
4892 list = g_slist_next(list);
4897 size += snprintf(&buf[size], len - size, "%c%d", delim, last);
4900 /* end of port list management routines */
4904 proto_register_asn1(void) {
4906 static const enum_val_t type_recursion_opts[] = {
4920 static gint *ett[1+MAX_NEST+MAXPDU];
4924 module_t *asn1_module;
4927 asn1_logfile = get_tempfile_path(ASN1LOGFILE);
4929 current_pduname = g_strdup("ASN1");
4930 asn1_pduname = g_strdup(current_pduname);
4932 proto_asn1 = proto_register_protocol("ASN.1 decoding",
4936 for (i=0, j=1; i<MAX_NEST; i++, j++) {
4937 ett[j] = &ett_seq[i];
4940 for(i=0; i<MAXPDU; i++, j++) {
4941 ett[j] = &ett_pdu[i];
4945 proto_register_subtree_array(ett, array_length(ett));
4947 asn1_module = prefs_register_protocol(proto_asn1,
4948 proto_reg_handoff_asn1);
4949 #ifdef JUST_ONE_PORT
4950 prefs_register_uint_preference(asn1_module, "tcp_port",
4952 "The TCP port on which "
4953 "ASN.1 messages will be read",
4954 10, &global_tcp_port_asn1);
4955 prefs_register_uint_preference(asn1_module, "udp_port",
4957 "The UDP port on which "
4958 "ASN.1 messages will be read",
4959 10, &global_udp_port_asn1);
4960 prefs_register_uint_preference(asn1_module, "sctp_port",
4962 "The SCTP port on which "
4963 "ASN.1 messages will be read",
4964 10, &global_sctp_port_asn1);
4966 snprintf(tmpstr, sizeof(tmpstr), "%d", TCP_PORT_ASN1);
4967 global_tcp_ports_asn1 = strdup(tmpstr);
4969 snprintf(tmpstr, sizeof(tmpstr), "%d", UDP_PORT_ASN1);
4970 global_udp_ports_asn1 = strdup(tmpstr);
4972 snprintf(tmpstr, sizeof(tmpstr), "%d", SCTP_PORT_ASN1);
4973 global_sctp_ports_asn1 = strdup(tmpstr);
4975 prefs_register_string_preference(asn1_module, "tcp_ports",
4977 "The TCP ports on which "
4978 "ASN.1 messages will be read",
4979 &global_tcp_ports_asn1);
4980 prefs_register_string_preference(asn1_module, "udp_ports",
4982 "The UDP ports on which "
4983 "ASN.1 messages will be read",
4984 &global_udp_ports_asn1);
4985 prefs_register_string_preference(asn1_module, "sctp_ports",
4987 "The SCTP ports on which "
4988 "ASN.1 messages will be read",
4989 &global_sctp_ports_asn1);
4990 #endif /* JUST_ONE_PORT */
4992 prefs_register_bool_preference(asn1_module, "desegment_messages",
4994 "Desegment ASN.1 messages that span TCP segments",
4997 old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
4999 bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
5002 prefs_register_string_preference(asn1_module, "file",
5003 "ASN.1 type table file",
5004 "Compiled ASN.1 description of ASN.1 types",
5006 prefs_register_string_preference(asn1_module, "pdu_name",
5008 "Name of top level PDU",
5010 prefs_register_uint_preference(asn1_module, "first_pdu_offset",
5011 "Offset to first PDU in first tcp packet",
5012 "Offset for non-reassembled packets, "
5013 "wrong if this happens on other than the first packet!",
5014 10, &first_pdu_offset);
5015 prefs_register_bool_preference(asn1_module, "flat",
5017 "Show full names for all values",
5019 prefs_register_enum_preference(asn1_module, "type_recursion",
5020 "Eliminate references to level",
5021 "Allow this recursion level for eliminated type references",
5022 &type_recursion_level,
5023 type_recursion_opts, FALSE);
5024 prefs_register_bool_preference(asn1_module, "debug",
5026 "Extra output useful for debuging",
5029 prefs_register_bool_preference(asn1_module, "message_win",
5031 "show full message description",
5034 prefs_register_obsolete_preference(asn1_module, "message_win");
5036 prefs_register_bool_preference(asn1_module, "verbose_log",
5037 "Write very verbose log",
5038 "log to file $TMP/" ASN1LOGFILE,
5042 /* The registration hand-off routing */
5045 proto_reg_handoff_asn1(void) {
5046 static int asn1_initialized = FALSE;
5047 static dissector_handle_t asn1_handle;
5053 #ifdef JUST_ONE_PORT
5054 if (asn1_verbose) g_message("prefs change: tcpport=%d, udpport=%d, sctpport=%d, desegnment=%d, "
5055 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5056 global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
5057 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5059 if (asn1_verbose) g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegnment=%d, "
5060 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5061 global_tcp_ports_asn1, global_udp_ports_asn1, global_sctp_ports_asn1, asn1_desegment,
5062 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5063 #endif /* JUST_ONE_PORT */
5065 if(!asn1_initialized) {
5066 asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
5067 asn1_initialized = TRUE;
5068 } else { /* clean up ports and their lists */
5069 #ifdef JUST_ONE_PORT
5070 dissector_delete("tcp.port", tcp_port_asn1, asn1_handle);
5071 dissector_delete("udp.port", udp_port_asn1, asn1_handle);
5072 dissector_delete("sctp.port", sctp_port_asn1, asn1_handle);
5074 list = tcp_ports_asn1;
5076 dissector_delete("tcp.port", GPOINTER_TO_INT(list->data), asn1_handle);
5077 list = g_slist_next(list);
5079 g_slist_free(tcp_ports_asn1);
5081 list = udp_ports_asn1;
5083 dissector_delete("udp.port", GPOINTER_TO_INT(list->data), asn1_handle);
5084 list = g_slist_next(list);
5086 g_slist_free(udp_ports_asn1);
5088 list = sctp_ports_asn1;
5090 dissector_delete("sctp.port", GPOINTER_TO_INT(list->data), asn1_handle);
5091 list = g_slist_next(list);
5093 g_slist_free(sctp_ports_asn1);
5094 #endif /* JUST_ONE_PORT */
5097 #ifdef JUST_ONE_PORT
5098 tcp_port_asn1 = global_tcp_port_asn1;
5099 udp_port_asn1 = global_udp_port_asn1;
5100 sctp_port_asn1 = global_sctp_port_asn1;
5102 dissector_add("tcp.port", global_tcp_port_asn1, asn1_handle);
5103 dissector_add("udp.port", global_udp_port_asn1, asn1_handle);
5104 dissector_add("sctp.port", global_sctp_port_asn1, asn1_handle);
5106 len = strlen(global_tcp_ports_asn1) + 32; /* extra for possible error message */
5107 global_tcp_ports_asn1 = realloc(global_tcp_ports_asn1, len);
5108 tcp_ports_asn1 = parse_port_range(global_tcp_ports_asn1, len);
5109 if (tcp_ports_asn1) /* no error, normalize presentation */
5110 show_port_range(tcp_ports_asn1, global_tcp_ports_asn1, len);
5112 g_message("tcp_ports: %s\n", global_tcp_ports_asn1);
5114 len = strlen(global_udp_ports_asn1) + 32; /* extra for possible error message */
5115 global_udp_ports_asn1 = realloc(global_udp_ports_asn1, len);
5116 udp_ports_asn1 = parse_port_range(global_udp_ports_asn1, len);
5117 if (udp_ports_asn1) /* no error, normalize presentation */
5118 show_port_range(udp_ports_asn1, global_udp_ports_asn1, len);
5120 g_message("udp_ports: %s\n", global_udp_ports_asn1);
5122 len = strlen(global_sctp_ports_asn1) + 32; /* extra for possible error message */
5123 global_sctp_ports_asn1 = realloc(global_sctp_ports_asn1, len);
5124 sctp_ports_asn1 = parse_port_range(global_sctp_ports_asn1, len);
5125 if (sctp_ports_asn1) /* no error, normalize presentation */
5126 show_port_range(sctp_ports_asn1, global_sctp_ports_asn1, len);
5128 g_message("sctp_ports: %s\n", global_sctp_ports_asn1);
5130 list = tcp_ports_asn1;
5132 dissector_add("tcp.port", GPOINTER_TO_INT(list->data), asn1_handle);
5133 list = g_slist_next(list);
5135 list = udp_ports_asn1;
5137 dissector_add("udp.port", GPOINTER_TO_INT(list->data), asn1_handle);
5138 list = g_slist_next(list);
5140 list = sctp_ports_asn1;
5142 dissector_add("sctp.port", GPOINTER_TO_INT(list->data), asn1_handle);
5143 list = g_slist_next(list);
5145 #endif /* JUST_ONE_PORT */
5147 if ( g_strcmp(asn1_filename, current_asn1) != 0) { /* new defintions, parse it */
5148 /* !!! should be postponed until we really need it !!! */
5150 read_asn1_type_table(asn1_filename);
5151 #endif /* READSYNTAX */
5152 g_free(current_asn1);
5153 current_asn1 = g_strdup(asn1_filename);
5155 if (g_strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
5156 if (build_pdu_tree(asn1_pduname)) {
5157 g_free(current_pduname);
5158 current_pduname = g_strdup(asn1_pduname);
5162 if (asn1_message_win) { /* show what we are prepared to recognize */
5164 gtk_widget_destroy (window);
5167 create_message_window();
5169 #endif /* SHOWPDU */
5172 /* Start the functions we need for the plugin stuff */
5174 #ifndef ENABLE_STATIC
5176 G_MODULE_EXPORT void
5177 plugin_reg_handoff(void){
5178 proto_reg_handoff_asn1();
5181 G_MODULE_EXPORT void
5182 plugin_init(plugin_address_table_t *pat
5183 #ifndef PLUGINS_NEED_ADDRESS_TABLE
5188 /* initialise the table of pointers needed in Win32 DLLs */
5189 plugin_address_table_init(pat);
5190 /* register the new protocol, protocol fields, and subtrees */
5191 if (proto_asn1 == -1) { /* execute protocol initialization only once */
5192 proto_register_asn1();
5198 /* End the functions we need for plugin stuff */