Tethereal/tethereal -> TShark/tshark.
[metze/wireshark/wip.git] / plugins / asn1 / packet-asn1.c
1 /******************************************************************************************************/
2 /* packet-asn1.c
3  *
4  * Copyright (c) 2003 by Matthijs Melchior <matthijs.melchior@xs4all.nl>
5  *
6  * $Id$
7  *
8  * A plugin for:
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1999 Gerald Combs
13  *
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.
18  *
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.
23  *
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.
27  */
28
29
30 /**************************************************************************
31  * This plugin will dissect BER encoded ASN.1 messages in UDP packets or in
32  * a TCP stream. It relies on wireshark to do defragmentation and re-assembly
33  * to construct complete messages.
34  *
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
39  *
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.
44  *
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:
47  *  - cd /tmp
48  *  - snacc -u /usr/include/snacc/asn1/asn-useful.asn1 -T tbl.tt /usr/include/snacc/asn1/tbl.asn1
49  *  - od -Ax -tx1 tbl.tt | text2pcap -T 801,801 - tbl.tt.pcap
50  *  - wireshark tbl.tt.pcap
51  *      GUI: Edit->Preferences->Protocols->ASN1
52  *             type table file: /tmp/tbl.tt
53  *             PDU name: TBL
54  *               [OK]
55  *  you can now browse the tbl.tt definition.
56  *
57  */
58
59
60 /* Include files */
61
62 #ifdef HAVE_CONFIG_H
63 #include "config.h"
64 #endif
65
66 #include <sys/types.h>
67 #include <sys/stat.h>
68 #include <errno.h>
69
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <ctype.h>
73 #include <time.h>
74 #include <string.h>
75
76 #include <glib.h>
77 #include <epan/packet.h>
78 #include <epan/addr_resolv.h>
79 #include <epan/prefs.h>
80 #include <epan/strutil.h>
81 #include <epan/filesystem.h>
82 #include <epan/report_err.h>
83 #include <epan/emem.h>
84 #include <epan/dissectors/packet-tcp.h>
85 #include <epan/asn1.h>
86 #include <wiretap/file_util.h>
87
88 #ifdef DISSECTOR_WITH_GUI
89 #include <gtk/gtk.h>
90 #endif
91
92 #include <epan/ipproto.h>
93
94 /* buffer lengths */
95 #define BUFLS 32
96 #define BUFLM 64
97 #define BUFLL 128
98
99 /* Define default ports */
100
101 #define TCP_PORT_ASN1 801
102 #define UDP_PORT_ASN1 801
103 #define SCTP_PORT_ASN1 801
104
105 void proto_reg_handoff_asn1(void);
106
107 /* Define the asn1 proto */
108
109 static int proto_asn1 = -1;
110
111 /* Define the tree for asn1*/
112
113 static int ett_asn1 = -1;
114
115 #define MAXPDU 64               /* max # PDU's in one packet */
116 static int ett_pdu[MAXPDU];
117
118 #define MAX_NEST 32             /* max nesting level for ASN.1 elements */
119 static int ett_seq[MAX_NEST];
120
121 /*
122  * Global variables associated with the preferences for asn1
123  */
124
125 #ifdef JUST_ONE_PORT
126 static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
127 static guint global_udp_port_asn1 = UDP_PORT_ASN1;
128 static guint global_sctp_port_asn1 = SCTP_PORT_ASN1;
129 static guint tcp_port_asn1 = TCP_PORT_ASN1;
130 static guint udp_port_asn1 = UDP_PORT_ASN1;
131 static guint sctp_port_asn1 = SCTP_PORT_ASN1;
132 #else
133 static range_t *global_tcp_ports_asn1;
134 static range_t *global_udp_ports_asn1;
135 static range_t *global_sctp_ports_asn1;
136
137 static range_t *tcp_ports_asn1;
138 static range_t *udp_ports_asn1;
139 static range_t *sctp_ports_asn1;
140 #endif /* JUST_ONE_PORT */
141
142 static gboolean asn1_desegment = TRUE;
143 static const char *asn1_filename = NULL;
144 static char *old_default_asn1_filename = NULL;
145 #define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
146 #ifdef _WIN32
147 #define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
148 static char *bad_separator_old_default_asn1_filename = NULL;
149 #endif
150 static char *current_asn1 = NULL;
151 static const char *asn1_pduname = NULL;
152 static char *current_pduname = NULL;
153 static gboolean asn1_debug = FALSE;
154 static guint first_pdu_offset = 0;
155 static gboolean asn1_message_win = FALSE;
156 static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
157 static gboolean asn1_full = FALSE; /* show full names */
158 static guint type_recursion_level = 1; /* eliminate 1 level of references */
159 static char *asn1_logfile = NULL;
160
161 #define ASN1LOGFILE "wireshark.log"
162
163 /* PDU counter, for correlation between GUI display and log file in debug mode */
164 static int pcount = 0;
165
166 static tvbuff_t *asn1_desc;     /* the PDU description */
167 static GNode *asn1_nodes = NULL;        /* GNode tree pointing to every asn1 data element */
168 static GNode *data_nodes = NULL;        /* GNode tree describing the syntax data */
169 static GNode *PDUtree = NULL;   /* GNode tree describing the expected PDU format */
170
171 static guint PDUerrcount = 0;   /* count of parse errors in one ASN.1 message */
172
173 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
174
175
176 static char pabbrev[] = "asn1"; /* field prefix */
177
178 static char fieldname[512];             /* for constructing full names */
179 static guint pabbrev_pdu_len;           /* length initial part of fieldname with 'abbrev.asn1pdu.' */
180
181 /*
182  * Text strings describing the standard, universal, ASN.1 names.
183  */
184
185 #define ASN1_EOI 4 /* this is in the class number space... */
186 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
187
188 static const char tag_class[] = "UACPX";
189
190 static const char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
191
192 static const char *asn1_con[] = { "Primitive", "Constructed" };
193
194 static const char *asn1_tag[] = {
195         /*  0 */ "EOC",             "Boolean",        "Integer",          "BitString",
196         /*  4 */ "OctetString",     "Null",           "ObjectIdentifier", "ObjectDescriptor",
197         /*  8 */ "External",        "Real",           "Enumerated",       "tag11",
198         /* 12 */ "UTF8String",      "tag13",          "tag14",            "tag15",
199         /* 16 */ "Sequence",        "Set",            "NumericString",    "PrintableString",
200         /* 20 */ "TeletexString",   "VideotexString", "IA5String",        "UTCTime",
201         /* 24 */ "GeneralTime",     "GraphicString",  "ISO646String",     "GeneralString",
202         /* 28 */ "UniversalString", "tag29",          "BMPString",        "Long tag prefix"
203 /* TT61 == TELETEX */
204 /* ISO646 == VISIBLE*/
205 };
206
207 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
208 static gboolean tbl_types_verified = FALSE;
209
210 typedef enum {  /* copied from .../snacc/c-lib/boot/tbl.h */
211         TBL_BOOLEAN = 0,
212         TBL_INTEGER = 1,
213         TBL_BITSTRING = 2,
214         TBL_OCTETSTRING = 3,
215         TBL_NULL = 4,
216         TBL_OID = 5,
217         TBL_REAL = 6,
218         TBL_ENUMERATED = 7,
219         TBL__SIMPLE = 8,        /* values smaller than this can have a value */
220         TBL_SEQUENCE = 8,
221         TBL_SET = 9,
222         TBL_SEQUENCEOF = 10,
223         TBL_SETOF = 11,
224         TBL_CHOICE = 12,
225         TBL_TYPEREF = 13,
226
227         TBL_SEQUENCEOF_start,   /* to mark potential sequence-of repeat */
228         TBL_TYPEREF_nopop,      /* typeref has been handled immediately */
229         TBL_CHOICE_done,        /* choice is finished */
230         TBL_reserved,           /* this sequence has been visited */
231         TBL_CHOICE_immediate,   /* immediate choice, no next */
232
233         TBL_INVALID             /* incorrect value for this enum */
234 } TBLTypeId;
235
236 /* Universal tags mapped to snacc ASN.1 table types */
237 static int asn1_uni_type[] = {
238         /*  0 */ TBL_INVALID,     TBL_BOOLEAN,     TBL_INTEGER,     TBL_BITSTRING,
239         /*  4 */ TBL_OCTETSTRING, TBL_NULL,        TBL_OID,         TBL_INVALID,
240         /*  8 */ TBL_INVALID,     TBL_REAL,        TBL_ENUMERATED,  TBL_INVALID,
241         /* 12 */ TBL_OCTETSTRING, TBL_INVALID,     TBL_INVALID,     TBL_INVALID,
242         /* 16 */ TBL_SEQUENCE,    TBL_SET,         TBL_OCTETSTRING, TBL_OCTETSTRING,
243         /* 20 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
244         /* 24 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
245         /* 28 */ TBL_OCTETSTRING, TBL_INVALID,     TBL_OCTETSTRING, TBL_INVALID,
246 };
247
248
249 #define TBL_REPEAT              0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
250 #define TBL_REPEAT_choice       0x00020000 /* repeating a choice */
251 #define TBL_CHOICE_made         0x00040000 /* This was a choice entry */
252 #define TBL_SEQUENCE_done       0x00080000 /* children have been processed */
253 #define TBL_CHOICE_repeat       0x00100000 /* a repeating choice */
254 #define TBL_REFERENCE           0x00200000 /* This entry is result of a typeref */
255 #define TBL_REFERENCE_pop       0x00400000 /* reference handled, do pop i.s.o. next */
256 #define TBL_SEQUENCE_choice     0x00800000 /* this sequence is a first of a repeating choice */
257 #define TBL_CONSTRUCTED         0x01000000 /* unexpectedly constructed entry */
258 #define TBL_TYPEmask            0x0000FFFF /* Mask just the type */
259
260 /* XXX - Should we use val_to_str here? */
261 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
262
263 /* text tables for debugging and GUI */
264 static const char *tbl_types[] = {
265                        /*  0 */ "tbl-boolean",
266                        /*  1 */ "tbl-integer",
267                        /*  2 */ "tbl-bitstring",
268                        /*  2 */ "tbl-octetstring",
269                        /*  4 */ "tbl-null",
270                        /*  5 */ "tbl-oid",
271                        /*  6 */ "tbl-real",
272                        /*  7 */ "tbl-enumerated",
273                        /*  8 */ "tbl-sequence",
274                        /*  9 */ "tbl-set",
275                        /* 10 */ "tbl-sequenceof",
276                        /* 11 */ "tbl-setof",
277                        /* 12 */ "tbl-choice",
278                        /* 13 */ "tbl-typeref",
279
280                        /* 14 */ "tbl-sequenceof-start",
281                        /* 15 */ "tbl-typeref-nopop",
282                        /* 16 */ "tbl-choice-done",
283                        /* 17 */ "tbl-reserved",
284                        /* 18 */ "tbl-choice-immediate",
285
286                        /* 19 */ "tbl-invalid",
287 };
288 static const char *tbl_types_asn1[] = {
289                        /*  0 */ "BOOLEAN",
290                        /*  1 */ "INTEGER",
291                        /*  2 */ "BITSTRING",
292                        /*  2 */ "OCTET STRING",
293                        /*  4 */ "NULL",
294                        /*  5 */ "OBJECT IDENTIFIER",
295                        /*  6 */ "REAL",
296                        /*  7 */ "ENUMERATED",
297                        /*  8 */ "SEQUENCE",
298                        /*  9 */ "SET",
299                        /* 10 */ "SEQUENCE OF",
300                        /* 11 */ "SET OF",
301                        /* 12 */ "CHOICE",
302                        /* 13 */ "TYPEREF",
303
304                        /* 14 */ "start-SEQUENCE OF",
305                        /* 15 */ "TYPEREF nopop",
306                        /* 16 */ "CHOICE done",
307                        /* 17 */ "Reserved",
308                        /* 18 */ "CHOICE immediate",
309
310                        /* 19 */ "INVALID entry",
311 };
312 /* conversion from snacc type to appropriate wireshark type */
313 static guint tbl_types_wireshark[] = {
314                        /*  0 */ FT_BOOLEAN,     /* TBL_BOOLEAN */
315                        /*  1 */ FT_UINT32,      /* TBL_INTEGER */
316                        /*  2 */ FT_UINT32,      /* TBL_BITSTRING */
317                        /*  2 */ FT_STRINGZ,     /* TBL_OCTETSTRING */
318                        /*  4 */ FT_NONE,        /* TBL_NULL */
319                        /*  5 */ FT_BYTES,       /* TBL_OID */
320                        /*  6 */ FT_DOUBLE,      /* TBL_REAL */
321                        /*  7 */ FT_UINT32,      /* TBL_ENUMERATED */
322                        /*  8 */ FT_NONE,        /* TBL_SEQUENCE */
323                        /*  9 */ FT_NONE,        /* TBL_SET */
324                        /* 10 */ FT_NONE,        /* TBL_SEQUENCEOF */
325                        /* 11 */ FT_NONE,        /* TBL_SETOF */
326                        /* 12 */ FT_NONE,        /* TBL_CHOICE */
327                        /* 13 */ FT_NONE,        /* TBL_TYPEREF */
328
329                        /* 14 */ FT_NONE,        /* TBL_SEQUENCEOF_start */
330                        /* 15 */ FT_NONE,        /* TBL_TYPEREF_nopop */
331                        /* 16 */ FT_NONE,        /* TBL_CHOICE_done */
332                        /* 17 */ FT_NONE,        /* TBL_reserved */
333                        /* 18 */ FT_NONE,        /* TBL_CHOICE_immediate */
334
335                        /* 19 */ FT_NONE,        /* TBL_INVALID */
336 };
337
338 static const char *tbl_types_wireshark_txt[] = {
339                        /*  0 */ "FT_BOOLEAN",   /* TBL_BOOLEAN */
340                        /*  1 */ "FT_UINT32",    /* TBL_INTEGER */
341                        /*  2 */ "FT_UINT32",    /* TBL_BITSTRING */
342                        /*  2 */ "FT_STRINGZ",   /* TBL_OCTETSTRING */
343                        /*  4 */ "FT_NONE",      /* TBL_NULL */
344                        /*  5 */ "FT_BYTES",     /* TBL_OID */
345                        /*  6 */ "FT_DOUBLE",    /* TBL_REAL */
346                        /*  7 */ "FT_UINT32",    /* TBL_ENUMERATED */
347                        /*  8 */ "FT_NONE",      /* TBL_SEQUENCE */
348                        /*  9 */ "FT_NONE",      /* TBL_SET */
349                        /* 10 */ "FT_NONE",      /* TBL_SEQUENCEOF */
350                        /* 11 */ "FT_NONE",      /* TBL_SETOF */
351                        /* 12 */ "FT_NONE",      /* TBL_CHOICE */
352                        /* 13 */ "FT_NONE",      /* TBL_TYPEREF */
353
354                        /* 14 */ "FT_NONE",      /* TBL_SEQUENCEOF_start */
355                        /* 15 */ "FT_NONE",      /* TBL_TYPEREF_nopop */
356                        /* 16 */ "FT_NONE",      /* TBL_CHOICE_done */
357                        /* 17 */ "FT_NONE",      /* TBL_reserved */
358                        /* 18 */ "FT_NONE",      /* TBL_CHOICE_immediate */
359
360                        /* 19 */ "FT_NONE",      /* TBL_INVALID */
361 };
362
363 typedef struct _PDUinfo PDUinfo;
364 struct _PDUinfo {
365         guint type;
366         const char *name;
367         const char *typename;
368         const char *fullname;
369         guchar tclass;
370         guint tag;
371         guint flags;
372         GNode *reference;
373         gint typenum;
374         gint basetype;          /* parent type */
375         gint mytype;            /* original type number, typenum may have gone through a reference */
376         gint value_id;          /* wireshark field id for the value in this PDU */
377         gint type_id;           /* wireshark field id for the type of this PDU */
378         hf_register_info value_hf; /* wireshark field info for this value */
379 };
380
381
382 /* bits in the flags collection */
383 #define PDU_OPTIONAL     1
384 #define PDU_IMPLICIT     2
385 #define PDU_NAMEDNUM     4
386 #define PDU_REFERENCE    8
387 #define PDU_TYPEDEF   0x10
388 #define PDU_ANONYMOUS 0x20
389 #define PDU_TYPETREE  0x40
390
391 #define PDU_CHOICE    0x08000000   /* manipulated by the PDUname routine */
392
393 static guint PDUinfo_initflags = 0;     /* default flags for newly allocated PDUinfo structs */
394
395 /* description of PDU properties as passed from the matching routine
396  * to the decoder and GUI.
397  */
398 typedef struct _PDUprops PDUprops;
399 struct _PDUprops {
400         guint type;     /* value from enum TBLTypeId */
401         const char *name;
402         const char *typename;
403         const char *fullname;
404         guint flags;
405         gpointer data;
406         gint value_id;
407         gint type_id;
408 };
409 /* flags defined in PDUprops.flags */
410 #define OUT_FLAG_type           1
411 #define OUT_FLAG_data           2
412 #define OUT_FLAG_typename       4
413 #define OUT_FLAG_dontshow       8
414 #define OUT_FLAG_noname      0x10
415 #define OUT_FLAG_constructed 0x20
416
417 static PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
418 static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
419
420 static const char empty[] = "";         /* address of the empt string, avoids many tests for NULL */
421 #define MAX_OTSLEN 256          /* max printed size for an octet string */
422
423
424 #undef NEST                     /* show nesting of asn.1 enties */
425
426 #ifdef NEST                     /* only for debugging */
427 /* show nesting, only for debugging... */
428 #define MAXTAGS MAX_NEST
429 static struct {
430         guchar cls;
431         guchar tag;
432 } taglist[MAXTAGS];
433
434 static char *showtaglist(guint level)
435 {
436         static char tagtxt[BUFLM];
437         char *p = tagtxt;
438         guint i;
439
440 #ifdef ALLTAGS
441         for(i=0; i<= level; i++) {
442                 switch(taglist[i].cls) {
443                 case ASN1_UNI: *p++ = 'U'; break;
444                 case ASN1_APL: *p++ = 'A'; break;
445                 case ASN1_CTX: *p++ = 'C'; break;
446                 case ASN1_PRV: *p++ = 'P'; break;
447                 default:       *p++ = 'x'; break;
448                 }
449                 p += sprintf(p, "%d.", taglist[i].tag);
450         }
451 #else /* only context tags */
452         *p++ = 'C';
453         for(i=0; i<= level; i++) {
454                 if (taglist[i].cls == ASN1_CTX) {
455                         p += sprintf(p, "%d.", taglist[i].tag);
456                 }
457         }
458 #endif
459         *--p = 0;               /* remove trailing '.' */
460         return tagtxt;
461 }
462
463 static guint
464 get_context(guint level)
465 {
466         guint ctx = 0;
467         guint i;
468
469         for(i=0; i<=level; i++) {
470                 if (taglist[i].cls == ASN1_CTX)
471                         ctx = (ctx << 8) | taglist[i].tag;
472         }
473         return ctx;
474 }
475 #endif /* NEST, only for debugging */
476
477
478 /* Convert a bit string to an ascii representation for printing
479  * -- not thread safe ...
480  */
481 static const char *showbits(guchar *val, guint count)
482 {
483         static char str[BUFLM];
484         guint i;
485         char *p = str;
486
487         if (count > 32)
488                 return "*too many bits*";
489
490         if (val != 0) {
491                 for(i=0; i<count; i++) {
492                         if (i && ((i & 7) == 0)) *p++ = ' ';
493                         *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
494                 }
495         }
496         *p = 0;
497         return str;
498 }
499
500 /* get bitnames string for bits set */
501 static const char *
502 showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
503 {
504         static char str[BUFLL];
505         guint i;
506         char *p = str;
507
508         if (props->flags & OUT_FLAG_noname)
509                 return empty;
510
511         if (count > 32)
512                 return "*too many bits, no names...*";
513
514         if (val != NULL) {
515                 for(i=0; i<count; i++) {
516                         if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
517                                 p += sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
518                         }
519                 }
520                 if (p > str)
521                         --p;    /* remove terminating , */
522         }
523         *p = 0;
524         return str;
525
526
527
528 }
529 /* Convert an oid to its conventional text representation
530  * -- not thread safe...
531  */
532 static char *showoid(subid_t *oid, guint len)
533 {
534         static char str[BUFLM];
535         guint i;
536         char *p = str;
537
538         if (oid != NULL) {
539                 for(i=0; i<len; i++) {
540                         if (i) *p++ = '.';
541                         p += sprintf(p, "%lu", (unsigned long)oid[i]);
542                 }
543         }
544         *p = 0;
545         return str;
546 }
547
548 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
549 static char *
550 showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
551 {
552         guint dohex = 0;
553         guint i;
554         char *str, *p;
555         const char *endstr = empty;
556
557         if (len == 0) {
558                 str = g_malloc(1);
559                 str[0] = 0;
560         } else {
561                 for (i=0; i<len; i++) {
562                         if (!isprint(octets[i])) /* maybe isblank() as well ... */
563                                 dohex++;
564                 }
565                 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
566                         len = MAX_OTSLEN;
567                         endstr = "...."; /* this is 5 bytes !! */
568                 }
569                 if (dohex) {
570                         str = p = g_malloc(len*2 + 5);
571                         for (i=0; i<len; i++) {
572                                 p += sprintf(p, "%2.2X", octets[i]);
573                         }
574                         strcpy(p, endstr);
575                 } else {
576                         if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
577                                 str = p = g_malloc(len*3+2);
578                                 for (i=0; i<len; i++) {
579                                         p += sprintf(p, "%2.2X", octets[i]);
580                                 }
581                                 *p++ = ' '; /* insert space */
582                                 strncpy(p, octets, len);
583                                 p[len] = 0;
584                         } else {
585                                 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
586                                 str = g_malloc(len+5);
587                                 strncpy(str, octets, len);
588                                 strcpy(&str[len], endstr);
589                         }
590                 }
591         }
592         return str;
593 }
594
595 /* allow NULL pointers in strcmp, handle them as empty strings */
596 static int
597 g_strcmp(gconstpointer a, gconstpointer b)
598 {
599         if (a == 0) a = empty;
600         if (b == 0) b = empty;
601         return strcmp(a, b);
602 }
603
604 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
605 /* WARNING   WARNING   WARNING   WARNING   WARNING   WARNING */
606 /*                                                           */
607 /* Most of the following routine is guesswork in order to    */
608 /* speed up resynchronisation if the dissector lost the      */
609 /* encoding due to incomplete captures, or a capture that    */
610 /* starts in the middle of a fragmented ip packet            */
611 /* If this poses to many problems, these settings can be     */
612 /* made part of the protocol settings in the user interface  */
613 /*************************************************************/
614
615 /* check length for a reasonable value, return a corrected value */
616 static int
617 checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
618 {
619         int newlen = len;
620
621         if ( ! def) {
622                 g_snprintf(lenstr, strmax, "indefinite");
623                 return len;
624         }
625
626         if (len < 0)            /* negative ..... */
627                 newlen = 4;
628
629         if (cls != ASN1_UNI) {  /* don't know about the tags */
630                 if (len > 131071)
631                         newlen = 64;
632         } else {
633                 switch (tag) {
634                 case ASN1_EOC:  /* End Of Contents    */
635                 case ASN1_NUL:  /* Null               */
636                         newlen = 0;
637                         break;
638                 case ASN1_BOL:  /* Boolean            */
639                         newlen = 1;
640                         break;
641                 case ASN1_INT:  /* Integer            */
642                 case ASN1_ENUM: /* Enumerated         */
643                         if (len > 8)
644                                 newlen = 4;
645                         break;
646                 case ASN1_BTS:  /* Bit String         */
647                         if (len > 8)
648                                 newlen = 4;
649                         break;
650                 case ASN1_OTS:  /* Octet String       */
651                 case ASN1_NUMSTR: /* Numerical String   */
652                 case ASN1_PRNSTR: /* Printable String   */
653                 case ASN1_TEXSTR: /* Teletext String    */
654                 case ASN1_VIDSTR: /* Video String       */
655                 case ASN1_IA5STR: /* IA5 String         */
656                 case ASN1_GRASTR: /* Graphical String   */
657                 case ASN1_VISSTR: /* Visible String     */
658                 case ASN1_GENSTR: /* General String     */
659                 if (len > 65535)
660                         newlen = 32;
661                 break;
662                 case ASN1_OJI:          /* Object Identifier  */
663                 case ASN1_OJD:          /* Description        */
664                 case ASN1_EXT:          /* External           */
665                         if (len > 64)
666                                 newlen = 16;
667                         break;
668                 case ASN1_REAL:         /* Real               */
669                         if (len >16)
670                                 newlen = 8;
671                         break;
672                 case ASN1_SEQ:          /* Sequence           */
673                 case ASN1_SET:          /* Set                */
674                         if (len > 65535)
675                                 newlen = 64;
676                         break;
677                 case ASN1_UNITIM:       /* Universal Time     */
678                 case ASN1_GENTIM:       /* General Time       */
679                         if (len > 32)
680                                 newlen = 15;
681                         break;
682
683                 default:
684                         if (len > 131071)
685                                 newlen = 64;
686                         break;
687                 }
688         }
689
690         if (newlen != len) {
691                 /* a change was needed.... */
692                 g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
693         } else {
694                 g_snprintf(lenstr, strmax, "%d", len);
695         }
696         return newlen;
697 }
698
699 static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
700 static void PDUreset(int count, int counr2);
701
702 static void
703 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
704
705   ASN1_SCK asn1;
706   guint cls, con, tag, def, len, offset, reassembled;
707   char lenstr[BUFLS];
708   char tagstr[BUFLS];
709   char headstr[BUFLL];
710   char offstr[BUFLS];
711   const char *name, *tname;
712   volatile guint boffset;
713   volatile int i = 0;           /* PDU counter */
714   proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
715   PDUprops props;
716   static guint lastseq;
717
718   pcount++;
719   boffset = 0;
720
721   reassembled = 1;              /* UDP is not a stream, and thus always reassembled .... */
722   if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
723           struct tcpinfo *info = (struct tcpinfo *)pinfo->private_data;
724           gint delta = info->seq - lastseq;
725           reassembled = info->is_reassembled;
726           lastseq = info->seq;
727
728           if (asn1_verbose)
729                   g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
730                             info->seq, delta, reassembled);
731   } else {
732           if (asn1_verbose)
733                   g_message("dissect_asn1: udp");
734   }
735
736   /* Set the protocol column */
737   if(check_col(pinfo->cinfo, COL_PROTOCOL)){
738     col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
739   }
740
741   if(check_col(pinfo->cinfo, COL_INFO))
742     col_clear(pinfo->cinfo, COL_INFO);
743
744
745   offstr[0] = 0;
746   if ((first_pdu_offset > 0) && !reassembled) {
747           boffset = first_pdu_offset;
748           g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
749   }
750
751   /* open BER decoding */
752   asn1_open(&asn1, tvb, boffset);
753
754   asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
755
756   asn1_close(&asn1, &offset);
757
758   PDUreset(pcount, 0);          /* arguments are just for debugging */
759   getPDUprops(&props, boffset, cls, tag, con);
760   name = props.name;
761   tname = props.typename;
762
763   len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
764
765   if (asn1_debug) {
766
767           g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
768
769           g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
770                    offstr,
771                    tname,
772                    name,
773                    pcount,
774                    asn1_cls[cls],
775                    asn1_con[con],
776                    ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
777                    lenstr,
778                    boffset,
779                    tvb_length(tvb)
780                   );
781   } else {
782           if (props.flags & OUT_FLAG_noname) {
783                   g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
784                   name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
785           }
786           g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
787   }
788
789   /* Set the info column */
790   if(check_col(pinfo->cinfo, COL_INFO)){
791     col_add_str(pinfo->cinfo, COL_INFO, headstr );
792   }
793
794   /*
795    * If we have a non-null tree (ie we are building the proto_tree
796    * instead of just filling out the columns ), then add a BER
797    * tree node
798    */
799
800   /* ignore the tree here, must decode BER to know how to reassemble!! */
801 /* if(tree) { */
802
803     TRY {                       /* catch incomplete PDU's */
804
805         ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
806                                             def? (int) (offset - boffset + len) :  -1,
807                                             "ASN.1 %s", current_pduname);
808
809         tree2 = proto_item_add_subtree(ti, ett_asn1);
810
811         proto_tree_add_item_hidden(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
812                                    def? (int) (offset - boffset + len) :  -1, TRUE);
813
814         offset = boffset; /* the first packet */
815         while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
816             ti2 = 0;
817             boffset = offset;
818             /* open BER decoding */
819             asn1_open(&asn1, tvb, offset);
820             asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
821             asn1_close(&asn1, &offset);
822
823             PDUreset(pcount, i+1);
824             getPDUprops(&props, boffset, cls, tag, con);
825             name = props.name;
826             tname = props.typename;
827
828             if (!def)
829                     len = tvb_length_remaining(tvb, offset);
830
831             len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
832
833             if (asn1_debug) {
834
835                     g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
836
837                     g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
838                              asn1_cls[cls],
839                              asn1_con[con],
840                              ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
841                              lenstr,
842                              boffset,
843                              tvb_length_remaining(tvb, offset) );
844
845                     if (props.value_id == -1)
846                             ti2 = proto_tree_add_text(tree2, tvb, boffset,
847                                                       def? (int) (offset - boffset + len) :  -1,
848                                                       "%s: (%s)%s %d-%d %s", current_pduname,
849                                                       tname, name, pcount, i+1, headstr);
850                     else {
851                             ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
852                                                       def? (int) (offset - boffset + len) :  -1,
853                                                       "%s: (%s)%s %d-%d %s ~", current_pduname,
854                                                       tname, name, pcount, i+1, headstr);
855
856                              if (props.type_id != -1)
857                                  proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
858                                                       def? (int) (offset - boffset + len) :  -1, TRUE);
859
860                     }
861             } else {
862                     if (props.flags & OUT_FLAG_noname) {
863                             g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
864                             name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
865                     }
866                     if (props.value_id == -1)
867                             ti2 = proto_tree_add_text(tree2, tvb, boffset,
868                                                       def? (int) (offset - boffset + len) :  -1,
869                                                       "%s: (%s)%s", current_pduname, tname, name);
870                     else {
871                             ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
872                                                       def? (int) (offset - boffset + len) :  -1,
873                                                       "%s: (%s)%s ~", current_pduname, tname, name);
874                             if (props.type_id != -1)
875                                 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
876                                                       def? (int) (offset - boffset + len) :  -1, TRUE);
877                     }
878             }
879             asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
880
881 #ifdef NEST
882             taglist[0].cls = cls;
883             taglist[0].tag = tag;
884 #endif /* NEST */
885
886             if (!def) len++; /* make sure we get an exception if we run off the end! */
887
888             offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
889
890             proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
891
892             i++; /* one more full message handled */
893
894             if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
895                     proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
896         }
897         if(check_col(pinfo->cinfo, COL_INFO))
898                 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
899         if (ti)
900                 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
901     }
902     CATCH(BoundsError) {
903             RETHROW;
904     }
905     CATCH(ReportedBoundsError) {
906             if(check_col(pinfo->cinfo, COL_INFO))
907                     col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
908             if (ti)
909                     proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
910             if (ti2)
911                     proto_item_append_text(ti2, " (incomplete)");
912             if (asn1_desegment) {
913                     pinfo->desegment_offset = boffset;
914                     pinfo->desegment_len = 1;
915                     if (asn1_verbose)
916                             g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
917                                       boffset, 1, pinfo->can_desegment);
918             } else {
919                     RETHROW;
920             }
921     }
922     ENDTRY;
923 /* } */
924   if (asn1_verbose)
925         g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
926                    pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
927 }
928
929 /* decode an ASN.1 sequence, until we have consumed the specified length */
930 static guint
931 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
932 {
933   ASN1_SCK asn1;
934   guint ret, cls, con, tag, def, len, boffset, soffset, eos;
935   guint value;
936   const char *clsstr, *constr, *tagstr;
937   char tagbuf[BUFLM];
938   char lenbuf[BUFLM];
939   char nnbuf[BUFLS];
940   proto_tree *ti, *pt2;
941   guchar *octets, *bits, unused;
942   subid_t *oid;
943   /* the debugging formats */
944   static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s";          /* decimal */
945   static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s";       /* enum */
946   static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s";        /* octet string */
947   static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s";       /* bit field */
948   static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s";            /* constructed */
949   static char matchind[] = " ~"; /* indication of possible match */
950   const char *name, *ename, *tname;
951   char *oname;
952   PDUprops props;
953
954   ti = 0;                       /* suppress gcc warning */
955
956   soffset = offset; /* where this sequence starts */
957   eos = offset + tlen;
958   while (offset < eos) {        /* while this entity has not ended... */
959           boffset = offset;
960           asn1_open(&asn1, tvb, offset);
961           ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
962           asn1_close(&asn1, &offset); /* mark current position */
963           if (ret != ASN1_ERR_NOERROR) {
964                 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
965                 break;
966           }
967
968           getPDUprops(&props, boffset, cls, tag, con);
969           name = props.name;
970           tname = props.typename;
971           if (asn1_full)
972                   name = &props.fullname[pabbrev_pdu_len];      /* no abbrev.pduname */
973           if (asn1_debug) {     /* show both names */
974                   sprintf(fieldname, "%s[%s]", props.name, props.fullname);
975                   name = fieldname;
976           }
977
978           clsstr = asn1_cls[cls];
979           constr = asn1_con[con];
980           if ((cls == ASN1_UNI) && ( tag < 32 )) {
981                   tagstr = asn1_tag[tag];
982           } else {
983                   g_snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
984                   tagstr = tagbuf;
985           }
986
987           len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
988
989           if (def) {
990                   g_snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
991           } else {
992                   strncpy(nnbuf, "NN-", sizeof(nnbuf));
993                                 /* make sure we get an exception if we run off the end! */
994                   len = tvb_length_remaining(tvb, offset) + 1;
995           }
996           if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
997                   /* just give type name if we don't know any better */
998                   tname = tagstr;
999                   name = nnbuf; /* this is better than just empty.... */
1000           }
1001
1002 #ifdef NEST
1003           taglist[level].cls = cls;
1004           taglist[level].tag = tag;
1005 #endif /* NEST */
1006
1007           oname  = 0;
1008           if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
1009                 cls = ASN1_UNI;
1010                 tag = ASN1_GENSTR;
1011                 oname = g_malloc(strlen(name) + 32);
1012                 sprintf(oname, "%s ** nesting cut off **", name);
1013                 name = oname;
1014           }
1015           switch(cls) {
1016             case ASN1_UNI:      /* fprintf(stderr, "Universal\n"); */
1017               switch(tag) {
1018                 case ASN1_INT:
1019                       ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1020                       asn1_close(&asn1, &offset); /* mark where we are now */
1021                       if (asn1_debug) {
1022                               if ( (props.value_id == -1) ||
1023                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1024                                         /* unknown or unexpected: just text */
1025                                         proto_tree_add_text(pt, tvb, boffset,
1026                                                         offset - boffset, textfmt_d, boffset,
1027                                                         clsstr, constr, tagstr, tname, name, value,
1028                                                         empty);
1029                               else {
1030                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1031                                                         offset - boffset, value, textfmt_d, boffset,
1032                                                         clsstr, constr, tagstr, tname, name, value,
1033                                                         matchind);
1034                                         if (props.type_id != -1)
1035                                                 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1036                                                                 boffset, offset - boffset, value);
1037                               }
1038                       } else {
1039                               if ( (props.value_id == -1) ||
1040                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1041                                         /* unknown or unexpected, just text */
1042                                         proto_tree_add_text(pt, tvb, boffset,
1043                                                         offset - boffset,
1044                                                         "(%s)%s: %d", tname, name, value);
1045                               else {
1046                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1047                                                         offset - boffset, value,
1048                                                         "(%s)%s: %d ~", tname, name, value);
1049                                         if (props.type_id != -1)
1050                                                 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1051                                                                 boffset, offset - boffset, value);
1052                               }
1053                       }
1054                       break;
1055
1056                 case ASN1_ENUM:
1057                       ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1058                       asn1_close(&asn1, &offset); /* mark where we are now */
1059                       ename = getPDUenum(&props, boffset, cls, tag, value);
1060                       if (asn1_debug) {
1061                               if ( (props.value_id == -1) ||
1062                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1063                                         /* unknown or unexpected, just text */
1064                                         proto_tree_add_text(pt, tvb, boffset,
1065                                                         offset - boffset,
1066                                                         textfmt_e, boffset, clsstr, constr, tagstr,
1067                                                         tname, name, value, ename, empty);
1068                               else {
1069                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1070                                                         offset - boffset, value,
1071                                                         textfmt_e, boffset, clsstr, constr, tagstr,
1072                                                         tname, name, value, ename, matchind);
1073                                         if (props.type_id != -1)
1074                                                 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1075                                                                 boffset, offset - boffset, value);
1076                               }
1077                       } else {
1078                               if ( (props.value_id == -1) ||
1079                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1080                                         /* unknown or unexpected, just text */
1081                                         proto_tree_add_text(pt, tvb, boffset,
1082                                                         offset - boffset,
1083                                                         "(%s)%s: %d:%s", tname, name, value, ename);
1084                               else {
1085                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1086                                                         offset - boffset, value,
1087                                                         "(%s)%s: %d:%s ~", tname, name, value, ename);
1088                                         if (props.type_id != -1)
1089                                                 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1090                                                                 boffset, offset - boffset, value);
1091                               }
1092                       }
1093                       break;
1094
1095                 case ASN1_BOL:
1096                       ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1097                       asn1_close(&asn1, &offset); /* mark where we are now */
1098                       if (asn1_debug) {
1099                               if ( (props.value_id == -1) ||
1100                                    (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1101                                         /* unknown or unexpected, just text */
1102                                         proto_tree_add_text(pt, tvb, boffset,
1103                                                         offset - boffset,
1104                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1105                                                         tname, name, value? "true" : "false", empty);
1106                               else {
1107                                         proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1108                                                         offset - boffset, value != 0,
1109                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1110                                                         tname, name, value? "true" : "false", matchind);
1111                                         if (props.type_id != -1)
1112                                                 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1113                                                                 boffset, offset - boffset, value != 0);
1114                               }
1115                       } else {
1116                               if ( (props.value_id == -1) ||
1117                                    (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1118                                         /* unknown or unexpected, just text */
1119                                         proto_tree_add_text(pt, tvb, boffset,
1120                                                         offset - boffset,
1121                                                         "(%s)%s: %s", tname, name,
1122                                                         value? "true" : "false");
1123                               else {
1124                                         proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1125                                                         offset - boffset, value != 0,
1126                                                         "(%s)%s: %s ~", tname, name,
1127                                                         value? "true" : "false");
1128                                         if (props.type_id != -1)
1129                                                 proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
1130                                                                 boffset, offset - boffset, value != 0);
1131                               }
1132                       }
1133                       break;
1134
1135                 case ASN1_OTS:
1136                 case ASN1_NUMSTR:
1137                 case ASN1_PRNSTR:
1138                 case ASN1_TEXSTR:
1139                 case ASN1_IA5STR:
1140                 case ASN1_GENSTR:
1141                 case ASN1_UNITIM:
1142                 case ASN1_GENTIM:
1143                         /* read value, \0 terminated */
1144                       ret = asn1_string_value_decode(&asn1, len, &octets);
1145                       asn1_close(&asn1, &offset); /* mark where we are now */
1146                       ename = showoctets(octets, len, (tag == ASN1_OTS) ? 4 : 0 );
1147                       if (asn1_debug) {
1148                               if ( (props.value_id == -1) ||
1149                                    (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1150                                         /* unknown or unexpected, just text */
1151                                         proto_tree_add_text(pt, tvb, boffset,
1152                                                         offset - boffset,
1153                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1154                                                         tname, name, ename, empty);
1155                               else {
1156                                         proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1157                                                         offset - boffset, octets, /* \0 termnated */
1158                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1159                                                         tname, name, ename, matchind);
1160                                         if (props.type_id != -1)
1161                                                 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1162                                                                 boffset, offset - boffset, octets);
1163                               }
1164                       } else {
1165                               if ( (props.value_id == -1) ||
1166                                    (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1167                                         /* unknown or unexpected, just text */
1168                                         proto_tree_add_text(pt, tvb, boffset,
1169                                                         offset - boffset,
1170                                                         "(%s)%s: %s", tname, name, ename);
1171                               else {
1172                                         proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1173                                                         offset - boffset, octets, /* \0 terminated */
1174                                                         "(%s)%s: %s ~", tname, name, ename);
1175                                         if (props.type_id != -1)
1176                                                 proto_tree_add_string_hidden(pt, props.type_id, tvb,
1177                                                                 boffset, offset - boffset, octets);
1178                               }
1179                       }
1180                       g_free(octets);
1181                       g_free(ename);
1182                       break;
1183
1184                 case ASN1_BTS:
1185                       ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1186                       asn1_close(&asn1, &offset); /* mark where we are now */
1187                       ename = showbitnames(bits, (con*8)-unused, &props, offset);
1188                       if (asn1_debug) {
1189                               if ( (props.value_id == -1) ||
1190                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1191                                         /* unknown or unexpected, just text */
1192                                         proto_tree_add_text(pt, tvb, boffset,
1193                                                         offset - boffset,
1194                                                         textfmt_b, boffset, clsstr, constr, tagstr,
1195                                                         tname, name,
1196                                                         showbits(bits, (con*8)-unused), ename, empty);
1197                               else {
1198                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1199                                                         offset - boffset, *bits, /* XXX length ? XXX */
1200                                                         textfmt_b, boffset, clsstr, constr, tagstr,
1201                                                         tname, name,
1202                                                         showbits(bits, (con*8)-unused),ename, matchind);
1203                                         if (props.type_id != -1)
1204                                                 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1205                                                                 boffset, offset - boffset, *bits);
1206                               }
1207
1208                       } else {
1209                               if ( (props.value_id == -1) ||
1210                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1211                                         /* unknown or unexpected, just text */
1212                                         proto_tree_add_text(pt, tvb, boffset,
1213                                                         offset - boffset,
1214                                                         "(%s)%s: %s:%s", tname, name,
1215                                                         showbits(bits, (con*8)-unused), ename);
1216                               else {
1217                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1218                                                         offset - boffset, *bits, /* XXX length ? XXX */
1219                                                         "(%s)%s: %s:%s ~", tname, name,
1220                                                         showbits(bits, (con*8)-unused), ename);
1221                                         if (props.type_id != -1)
1222                                                 proto_tree_add_uint_hidden(pt, props.type_id, tvb,
1223                                                                 boffset, offset - boffset, *bits);
1224                               }
1225                       }
1226                       g_free(bits);
1227                       break;
1228
1229                 case ASN1_SET:
1230                 case ASN1_SEQ:
1231                                 /* show full sequence length */
1232                       if (asn1_debug) {
1233                               ename = empty;
1234                               if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1235                                       ename = ", noshow";
1236                               if ( (props.flags & OUT_FLAG_constructed))
1237                                       ename = ", unexpected constructed";
1238
1239                               if (props.value_id == -1)
1240                                       ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1241                                                              textfmt_c, boffset, clsstr, constr, tagstr,
1242                                                              tname, name, ename, empty);
1243                               else {
1244                                       ti = proto_tree_add_item(pt, props.value_id, tvb,
1245                                                               boffset, 1, TRUE);
1246                                       /* change te text to to what I really want */
1247                                       proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1248                                                              tagstr, tname, name, ename, matchind);
1249                                       if (props.type_id != -1)
1250                                               proto_tree_add_item_hidden(pt, props.type_id, tvb,
1251                                                               boffset, 1, TRUE);
1252                               }
1253                       } else {
1254                               if (props.value_id == -1) {
1255                                       if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1256                                               ti = proto_tree_add_text(pt, tvb, boffset,
1257                                                                        offset - boffset + len,
1258                                                                        "(%s)%s", tname, name);
1259                               } else {
1260                                       if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1261                                               ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1262                                                                        boffset, offset - boffset + len,
1263                                                                        "(%s)%s ~", tname, name);
1264                                       else {
1265                                               /* don't care about the text */
1266                                               ti = proto_tree_add_item_hidden(pt, props.value_id, tvb,
1267                                                           boffset, 1, TRUE);
1268                                       }
1269                                       if (props.type_id != -1)
1270                                               proto_tree_add_item_hidden(pt, props.type_id, tvb,
1271                                                           boffset, 1, TRUE);
1272                               }
1273                       }
1274                       if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1275
1276                       if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1277                               pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1278                       else
1279                               pt2 = pt;
1280
1281                       offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1282
1283                       if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1284                               proto_item_set_len(ti, offset - boffset);
1285
1286                       break;
1287
1288                 case ASN1_EOC:
1289                       if (asn1_debug) { /* don't show if not debugging */
1290                               proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1291                                                   boffset, clsstr, constr, tagstr, tname, name,
1292                                                   offset - soffset, empty);
1293                       }
1294                       getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1295                       return offset;
1296
1297                 case ASN1_OJI:
1298                       ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1299                       asn1_close(&asn1, &offset); /* mark where we are now */
1300                       ename = showoid(oid, con);
1301                       if (asn1_debug) {
1302                               if ( (props.value_id == -1) ||
1303                                    (tbl_types_wireshark[props.type] != FT_BYTES) )
1304                                       /* unknown or unexpected, just text */
1305                                       proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1306                                                           boffset, clsstr, constr, tagstr, tname, name,
1307                                                           ename, empty);
1308                               else {
1309                                       proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1310                                                                  offset - boffset, ename,/* XXX length?*/
1311                                                                  "(%s)%s: %s ~", tname, name, ename);
1312                                         if (props.type_id != -1)
1313                                                 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1314                                                                 boffset, offset - boffset, ename);
1315                               }
1316                       } else {
1317                               if ( (props.value_id == -1) ||
1318                                    (tbl_types_wireshark[props.type] != FT_BYTES) )
1319                                         /* unknown or unexpected, just text */
1320                                         proto_tree_add_text(pt, tvb, boffset,
1321                                                         offset - boffset,
1322                                                         "(%s)%s: %s", tname, name, ename);
1323                               else {
1324                                         proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1325                                                         offset - boffset, ename, /* XXX length ? */
1326                                                         "(%s)%s: %s ~", tname, name, ename);
1327                                         if (props.type_id != -1)
1328                                                 proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
1329                                                                 boffset, offset - boffset, ename);
1330                               }
1331                       }
1332                       g_free(oid);
1333                       break;
1334
1335                 case ASN1_NUL:
1336                       if (asn1_debug) {
1337                               proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1338                                                   boffset, clsstr, constr, tagstr, tname, name,
1339                                                   "[NULL]", empty);
1340                       } else {
1341                               proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1342                                                   "(%s)%s: [NULL]", tname, name);
1343                       }
1344                       offset += len; /* skip value ... */
1345                       break;
1346
1347                 case ASN1_OJD:
1348                 case ASN1_EXT:
1349                 case ASN1_REAL:
1350                 case ASN1_VIDSTR:
1351                 case ASN1_GRASTR:
1352                 case ASN1_VISSTR:
1353
1354                 default:
1355                       if (asn1_debug) {
1356                               ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1357                                                        textfmt_s, boffset, clsstr, constr, tagstr,
1358                                                        tname, name, lenbuf, empty);
1359                       } else {
1360                               ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1361                                                        "(%s)%s: %s bytes", tname, name, lenbuf);
1362                       }
1363                       proto_item_append_text(ti, " *"); /* indicate default is used */
1364                       offset += len; /* skip value ... */
1365                       break;
1366               };
1367               break;
1368
1369             case ASN1_CTX:              /* fprintf(stderr, "Context\n"); */
1370             case ASN1_APL:              /* fprintf(stderr, "Application\n"); */
1371             case ASN1_PRV:              /* fprintf(stderr, "Private\n"); */
1372
1373                   if (def && !con) {
1374                         if (props.value_id == -1) /* type unknown, handle as string */
1375                                 goto dostring;
1376                         switch(props.type) {
1377                                 /* this is via the asn1 description, don't trust the length */
1378                         case TBL_INTEGER:
1379                                 if (len > 4)
1380                                         goto dostring;
1381                                 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1382                                 asn1_close(&asn1, &offset); /* mark where we are now */
1383                                 if (asn1_debug) {
1384                                         if ( (props.value_id == -1) ||
1385                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1386                                                 /* unknown or unexpected, just text */
1387                                                 proto_tree_add_text(pt, tvb,
1388                                                             boffset, offset - boffset,
1389                                                             textfmt_d, boffset, clsstr, constr,
1390                                                             tagstr, tname, name, value, empty);
1391                                         else {
1392                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1393                                                             boffset, offset - boffset, value,
1394                                                             textfmt_d, boffset, clsstr, constr,
1395                                                             tagstr, tname, name, value, matchind);
1396                                                 if (props.type_id != -1)
1397                                                         proto_tree_add_uint_hidden(pt, props.type_id,
1398                                                                 tvb, boffset, offset - boffset, value);
1399                                         }
1400                                 } else {
1401                                         if ( (props.value_id == -1) ||
1402                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1403                                                 /* unknown or unexpected, just text */
1404                                                 proto_tree_add_text(pt, tvb,
1405                                                             boffset, offset - boffset,
1406                                                             "(%s)%s: %d", tname, name, value);
1407                                         else {
1408                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1409                                                             boffset, offset - boffset, value,
1410                                                             "(%s)%s: %d ~", tname, name, value);
1411                                                 if (props.type_id != -1)
1412                                                         proto_tree_add_uint_hidden(pt, props.type_id,
1413                                                                 tvb, boffset, offset - boffset, value);
1414                                         }
1415                                 }
1416                                 break;
1417
1418                         case TBL_ENUMERATED:
1419                                 if (len > 4)
1420                                         goto dostring;
1421                                 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1422                                 asn1_close(&asn1, &offset); /* mark where we are now */
1423                                 ename = getPDUenum(&props, boffset, cls, tag, value);
1424                                 if (asn1_debug) {
1425                                         if ( (props.value_id == -1) ||
1426                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1427                                                 /* unknown or unexpected, just text */
1428                                                 proto_tree_add_text(pt, tvb,
1429                                                            boffset, offset - boffset,
1430                                                            textfmt_e, boffset, clsstr, constr,
1431                                                            tagstr, tname, name, value, ename, empty);
1432                                         else {
1433                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1434                                                            boffset, offset - boffset, value,
1435                                                            textfmt_e, boffset, clsstr, constr,
1436                                                            tagstr, tname, name, value, ename, matchind);
1437                                                 if (props.type_id != -1)
1438                                                         proto_tree_add_uint_hidden(pt, props.type_id,
1439                                                                 tvb, boffset, offset - boffset, value);
1440                                         }
1441                                 } else {
1442                                         if ( (props.value_id == -1) ||
1443                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1444                                                 /* unknown or unexpected, just text */
1445                                                 proto_tree_add_text(pt, tvb,
1446                                                            boffset, offset - boffset,
1447                                                            "(%s)%s: %d:%s", tname, name, value, ename);
1448                                         else {
1449                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1450                                                           boffset, offset - boffset, value,
1451                                                           "(%s)%s: %d:%s ~", tname, name, value, ename);
1452                                                 if (props.type_id != -1)
1453                                                         proto_tree_add_uint_hidden(pt, props.type_id,
1454                                                                 tvb, boffset, offset - boffset, value);
1455                                         }
1456                                 }
1457                                 break;
1458                         case TBL_BITSTRING:
1459                                 if (len > (1+4)) /* max 32 bits ...?.. */
1460                                         goto dostring;
1461                                                                 /* read value */
1462                                 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1463                                 asn1_close(&asn1, &offset); /* mark where we are now */
1464                                 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1465                                 if (asn1_debug) {
1466                                         if ( (props.value_id == -1) ||
1467                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1468                                                 /* unknown or unexpected, just text */
1469                                                 proto_tree_add_text(pt, tvb,
1470                                                             boffset, offset - boffset,
1471                                                             textfmt_b, boffset, clsstr, constr,
1472                                                             tagstr, tname, name,
1473                                                             showbits(bits, (con*8)-unused), ename,
1474                                                             empty);
1475                                         else {
1476                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1477                                                             boffset, offset - boffset, *bits,
1478                                                             textfmt_b, boffset, clsstr, constr,
1479                                                             tagstr, tname, name,
1480                                                             showbits(bits, (con*8)-unused), ename,
1481                                                             matchind);
1482                                                 if (props.type_id != -1)
1483                                                         proto_tree_add_uint_hidden(pt, props.type_id,
1484                                                                  tvb, boffset, offset - boffset, *bits);
1485                                         }
1486                                 } else {
1487                                         if ( (props.value_id == -1) ||
1488                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1489                                                 /* unknown or unexpected, just text */
1490                                                 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1491                                                             "(%s)%s: %s:%s", tname, name,
1492                                                             showbits(bits, (con*8)-unused), ename);
1493                                         else {
1494                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1495                                                             boffset, offset - boffset, *bits,
1496                                                             "(%s)%s: %s:%s ~", tname, name,
1497                                                             showbits(bits, (con*8)-unused), ename);
1498                                                 if (props.type_id != -1)
1499                                                         proto_tree_add_uint_hidden(pt, props.type_id,
1500                                                                 tvb, boffset, offset - boffset, *bits);
1501                                         }
1502                                 }
1503                                 g_free(bits);
1504                                 break;
1505                         case TBL_BOOLEAN:
1506                                 if (len > 1)
1507                                         goto dostring;
1508                                 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1509                                 asn1_close(&asn1, &offset); /* mark where we are now */
1510                                 if (asn1_debug) {
1511                                         if ( (props.value_id == -1) ||
1512                                              (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1513                                                 /* unknown or unexpected, just text */
1514                                                 proto_tree_add_text(pt, tvb,
1515                                                             boffset, offset - boffset,
1516                                                             textfmt_s, boffset, clsstr, constr,
1517                                                             tagstr, tname, name,
1518                                                             value? "true" : "false", empty);
1519                                         else {
1520                                                 proto_tree_add_boolean_format(pt, props.value_id,  tvb,
1521                                                             boffset, offset - boffset, value != 0,
1522                                                             textfmt_s, boffset, clsstr, constr,
1523                                                             tagstr, tname, name,
1524                                                             value? "true" : "false", matchind);
1525                                                 if (props.type_id != -1)
1526                                                         proto_tree_add_boolean_hidden(pt, props.type_id,
1527                                                           tvb, boffset, offset - boffset, value != 0);
1528                                         }
1529                                 } else {
1530                                         if ( (props.value_id == -1) ||
1531                                              (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1532                                                 /* unknown or unexpected, just text */
1533                                                 proto_tree_add_text(pt, tvb,
1534                                                             boffset, offset - boffset,
1535                                                             "(%s)%s: %s", tname, name,
1536                                                             value? "true" : "false");
1537                                         else {
1538                                                 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1539                                                             boffset, offset - boffset, value != 0,
1540                                                             "(%s)%s: %s ~", tname, name,
1541                                                             value? "true" : "false");
1542                                                 if (props.type_id != -1)
1543                                                         proto_tree_add_boolean_hidden(pt, props.type_id,
1544                                                           tvb, boffset, offset - boffset, value != 0);
1545                                         }
1546                                 }
1547                                 break;
1548                         case TBL_NULL:
1549                                 if (len > 0)
1550                                         goto dostring;
1551                                 if (asn1_debug) {
1552                                         proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1553                                                             textfmt_s, boffset, clsstr, constr,
1554                                                             tagstr, tname, name, "[NULL]", empty);
1555                                 } else {
1556                                         proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1557                                                             "(%s)%s: [NULL]", tname, name);
1558                                 }
1559                                 offset += len; /* skip value ... */
1560                                 break;
1561                         default:
1562                         dostring:
1563                                 props.value_id = -1; /* unlikely this is correct, dont use it */
1564                                 /* fallthrough */
1565                         case TBL_OCTETSTRING:
1566                                 /* defined length, not constructed, must be a string.... */
1567                                 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1568                                 asn1_close(&asn1, &offset); /* mark where we are now */
1569                                 ename = showoctets(octets, len, 2); /* convert octets to printable */
1570                                 if (asn1_debug) {
1571                                         if ( (props.value_id == -1) ||
1572                                              (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1573                                                 /* unknown or unexpected, just text */
1574                                                 proto_tree_add_text(pt, tvb,
1575                                                             boffset, offset - boffset,
1576                                                             textfmt_s, boffset, clsstr, constr,
1577                                                             tagstr, tname, name, ename, empty);
1578                                         else {
1579                                                 proto_tree_add_string_format(pt, props.value_id, tvb,
1580                                                             boffset, offset - boffset, octets, /* XXX */
1581                                                             textfmt_s, boffset, clsstr, constr,
1582                                                             tagstr, tname, name, ename, matchind);
1583                                                 if (props.type_id != -1)
1584                                                         proto_tree_add_string_hidden(pt, props.type_id,
1585                                                                 tvb, boffset, offset - boffset, octets);
1586                                         }
1587                                 } else {
1588                                         if ( (props.value_id == -1) ||
1589                                              (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1590                                                 /* unknown or unexpected, just text */
1591                                                 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1592                                                             "(%s)%s: %s", tname, name, ename);
1593                                         else {
1594                                                 proto_tree_add_string_format(pt, props.value_id, tvb,
1595                                                             boffset, offset - boffset, octets, /* XXX */
1596                                                             "(%s)%s: %s ~", tname, name, ename);
1597                                                 if (props.type_id != -1)
1598                                                         proto_tree_add_string_hidden(pt, props.type_id,
1599                                                                 tvb, boffset, offset - boffset, octets);
1600                                         }
1601                                 }
1602                                 g_free(octets);
1603                                 g_free(ename);
1604                                 break;
1605                         }
1606                   } else {
1607                         /* indefinite length or constructed.... must be a sequence .... */
1608                         /* show full sequence length */
1609                         if (asn1_debug) {
1610                                 ename = empty;
1611                                 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1612                                         ename = ", noshow";
1613                                 if ( (props.flags & OUT_FLAG_constructed))
1614                                         ename = ", unexpected constructed";
1615
1616                                 if (props.value_id == -1)
1617                                       ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1618                                                                  textfmt_c, boffset, clsstr, constr,
1619                                                                  tagstr, tname, name, ename, empty);
1620                                 else {
1621                                       ti = proto_tree_add_item(pt, props.value_id, tvb,
1622                                                               boffset, 1, TRUE);
1623                                       /* change te text to to what I really want */
1624                                       if (ti) {
1625                                         proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1626                                                              tagstr, tname, name, ename, matchind);
1627                                         if (props.type_id != -1)
1628                                               proto_tree_add_item_hidden(pt, props.type_id, tvb,
1629                                                               boffset, 1, TRUE);
1630                                       } else {
1631                                         ti = proto_tree_add_text(pt, tvb, boffset,
1632                                                                  offset - boffset + len,
1633                                                                  textfmt_c, boffset, clsstr, constr,
1634                                                                  tagstr, tname, name, ename, empty);
1635                                       }
1636                                 }
1637                         } else {
1638                                 if (props.value_id == -1) {
1639                                         if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1640                                                 ti = proto_tree_add_text(pt, tvb, boffset,
1641                                                          offset - boffset + len, "(%s)%s", tname, name);
1642                                 } else {
1643                                         if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1644                                                 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1645                                                                 boffset, 1,
1646                                                                 "(%s)%s ~", tname, name);
1647                                         else {
1648                                                 /* don't care about the text */
1649                                                 ti = proto_tree_add_item_hidden(pt, props.value_id,
1650                                                              tvb,  boffset, 1, TRUE);
1651                                         }
1652                                         if (props.type_id != -1)
1653                                                 proto_tree_add_item_hidden(pt, props.type_id,
1654                                                              tvb,  boffset, 1, TRUE);
1655                                 }
1656                         }
1657
1658                         if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1659
1660                         if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1661                                 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1662                         else
1663                                 pt2 = pt;
1664
1665                         offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1666
1667                         if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1668                                 proto_item_set_len(ti, offset - boffset);
1669                   }
1670               break;
1671
1672             default:            /* fprintf(stderr, "Other\n"); */
1673                   if (asn1_debug) {
1674                           ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1675                                                    textfmt_s, boffset, clsstr, constr, tagstr,
1676                                                    tname, name, lenbuf, empty);
1677                   } else {
1678                           ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1679                                                    "(%s)%s: %s bytes %s data", tname, name,
1680                                                    lenbuf, clsstr);
1681                   }
1682                   proto_item_append_text(ti, " *"); /* indicate default is used */
1683                   offset += len; /* skip value ... */
1684                   break;
1685           }
1686           g_free(oname); /* XXX, memory management ? */
1687   }
1688   /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1689
1690   getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1691
1692   return offset;
1693 }
1694 #define READSYNTAX
1695 #ifdef READSYNTAX
1696
1697 /************************************************************************************************/
1698 /*  search throug the ASN.1 description for appropriate names                                   */
1699 /************************************************************************************************/
1700
1701 guint lev_limit = G_MAXINT;
1702
1703 int icount = 0;                 /* item counter */
1704
1705 static guint
1706 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1707 {
1708         ASN1_SCK asn1;
1709         guint eos, ret, cls, con, tag, def, len, value;
1710         guchar *octets, *bits, unused;
1711         subid_t *oid;
1712         const char *clsstr, *constr, *tagstr;
1713         char tagbuf[BUFLM];
1714         char lenbuf[BUFLM];
1715         GNode *cur_node = 0;
1716
1717         eos = offset + size;
1718
1719         if (level > lev_limit)
1720                 return eos;
1721
1722         while(offset < eos) {
1723                 if (ptr)        /* build pointer tree to all asn1 enteties */
1724                         cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
1725
1726                 asn1_open(&asn1, tvb, offset);
1727                 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1728                 asn1_close(&asn1, &offset); /* mark where we are */
1729                 icount++;
1730                 clsstr = asn1_cls[cls];
1731                 constr = asn1_con[con];
1732                 if ((cls == ASN1_UNI) && ( tag < 32 )) {
1733                         tagstr = asn1_tag[tag];
1734                 } else {
1735                         g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1736                         tagstr = tagbuf;
1737                 }
1738                 if (def) {
1739                         g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1740                 } else {
1741                         strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1742                         len = tvb_length_remaining(tvb, offset);
1743                 }
1744
1745                 switch(cls) {
1746                 case ASN1_UNI:  /* fprintf(stderr, "Universal\n"); */
1747                         switch(tag) {
1748                         case ASN1_INT:
1749                         case ASN1_ENUM:
1750                                 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1751                                 asn1_close(&asn1, &offset); /* mark where we are */
1752                                 break;
1753
1754                         case ASN1_BOL:
1755                                 ret = asn1_bool_decode(&asn1, len, &value); /* read value */
1756                                 asn1_close(&asn1, &offset); /* mark where we are */
1757                                 break;
1758
1759                         case ASN1_OTS:
1760                         case ASN1_NUMSTR:
1761                         case ASN1_PRNSTR:
1762                         case ASN1_TEXSTR:
1763                         case ASN1_IA5STR:
1764                         case ASN1_GENSTR:
1765                         case ASN1_UNITIM:
1766                         case ASN1_GENTIM:
1767                                 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1768                                 asn1_close(&asn1, &offset); /* mark where we are */
1769                                 g_free(octets);
1770                                 break;
1771
1772                         case ASN1_BTS:
1773                                 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1774                                 asn1_close(&asn1, &offset); /* mark where we are */
1775                                 g_free(bits);
1776                                 break;
1777
1778                         case ASN1_SET:
1779                         case ASN1_SEQ:
1780                                 if (len == 0) /* don't recurse if offset isn't going to change */
1781                                         return offset;
1782
1783                                 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1784                                 break;
1785
1786                         case ASN1_EOC:
1787                                 return offset;
1788
1789                         case ASN1_OJI:
1790                                 ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1791                                 asn1_close(&asn1, &offset); /* mark where we are */
1792                                 g_free(oid);
1793                                 break;
1794
1795                         case ASN1_NUL:
1796                                 offset += len;
1797                                 break;
1798
1799                         case ASN1_OJD:
1800                         case ASN1_EXT:
1801                         case ASN1_REAL:
1802                         case ASN1_VIDSTR:
1803                         case ASN1_GRASTR:
1804                         case ASN1_VISSTR:
1805
1806                         default:
1807                                 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1808                                 offset += len; /* skip value ... */
1809                                 break;
1810                         };
1811                         break;
1812
1813                 case ASN1_CTX:          /* fprintf(stderr, "Context\n"); */
1814                         tagstr = tagbuf;
1815                         g_snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
1816                         if (def && !con) {
1817                                 /* defined length, not constructed, must be a string.... */
1818                                 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1819                                 asn1_close(&asn1, &offset); /* mark where we are */
1820                                 g_free(octets);
1821                         } else {
1822                                 /* indefinite length or constructed.... must be a sequence .... */
1823                                 if (len == 0) /* don't recurse if offset isn't going to change */
1824                                         return offset;
1825
1826                                 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1827                         }
1828                         break;
1829
1830                 default:                /* fprintf(stderr, "Other\n"); */
1831                         if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1832                         offset += len; /* skip value ... */
1833                         break;
1834                 }
1835         }
1836         return offset;
1837 }
1838
1839 static void showGNodes(GNode *p, int n);
1840
1841 #if 0
1842 static gboolean
1843 myLeaf(GNode *node, gpointer data)
1844 {
1845         ASN1_SCK asn1;
1846         guint ret, cls, con, tag, def, len;
1847         char *clsstr, *constr, *tagstr;
1848         char tagbuf[BUFLM];
1849         char lenbuf[BUFLM];
1850
1851         (void) data;                    /* make a reference */
1852         asn1_open(&asn1, asn1_desc, (int)node->data);
1853
1854         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1855
1856         clsstr = asn1_cls[cls];
1857         constr = asn1_con[con];
1858         if ((cls == ASN1_UNI) && ( tag < 32 )) {
1859                 tagstr = asn1_tag[tag];
1860         } else {
1861                 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1862                 tagstr = tagbuf;
1863         }
1864         if (def) {
1865                 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1866         } else {
1867                 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1868         }
1869
1870         if (asn1_verbose)
1871                 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1872
1873         return FALSE;
1874 }
1875
1876 static void
1877 list_modules(void)
1878 {
1879         if (asn1_verbose) g_message("build GNode tree:");
1880         showGNodes(g_node_first_child(asn1_nodes), 0);
1881         if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1882                   g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1883                   g_node_max_height (asn1_nodes),
1884                   g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1885                   g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1886
1887         g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1888
1889 }
1890 #endif
1891
1892 static void
1893 tt_build_tree(void)             /* build a GNode tree with all offset's to ASN.1 entities */
1894 {
1895         if (asn1_nodes)
1896                 g_node_destroy(asn1_nodes);
1897         asn1_nodes = g_node_new(0);
1898         icount = 0;
1899         parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1900 }
1901
1902
1903 /*****************************************************************************************************/
1904
1905 static guint anonCount;  /* for naming anonymous types */
1906
1907 typedef struct _TBLModule       TBLModule;
1908 typedef struct _TBLTypeDef      TBLTypeDef;
1909 typedef struct _TBLTag          TBLTag;
1910 typedef struct _TBLType         TBLType;
1911 typedef struct _TBLTypeRef      TBLTypeRef;
1912 typedef struct _TBLNamedNumber  TBLNamedNumber;
1913 typedef struct _TBLRange        TBLRange;
1914
1915 enum _tbl_t {
1916         TBLTYPE_Module,
1917         TBLTYPE_TypeDef,
1918         TBLTYPE_Tag,
1919         TBLTYPE_Type,
1920         TBLTYPE_TypeRef,
1921         TBLTYPE_NamedNumber,
1922         TBLTYPE_Range
1923 };
1924 typedef enum _tbl_t tbl_t;
1925 /* text for 'tbl_t' type for debugging */
1926 static const char *data_types[] = {
1927                         "Module",
1928                         "TypeDef",
1929                         "Tag",
1930                         "Type",
1931                         "TypeRef",
1932                         "NamedNumber",
1933                         "Range",
1934 };
1935
1936 enum _TBLTypeContent_t {
1937         TBLTYPETYPE_None,
1938         TBLTYPETYPE_Primitive,
1939         TBLTYPETYPE_Elements,
1940         TBLTYPETYPE_TypeRef
1941 };
1942 typedef enum _TBLTypeContent_t TBLTypeContent_t;
1943
1944 struct _TBLNamedNumber {
1945         tbl_t   type;
1946         guchar  *name;
1947         guint   value;
1948 };
1949
1950 struct _TBLRange {
1951         tbl_t   type;
1952         guint   from;
1953         guint   to;
1954 };
1955
1956 struct _TBLTypeRef {
1957         tbl_t   type;
1958         guint   typeDefId;
1959         gboolean implicit;
1960 };
1961
1962 struct _TBLTag {
1963         tbl_t   type;
1964         guint   tclass;
1965         guint   code;
1966 };
1967
1968 struct _TBLType {
1969         tbl_t   type;
1970         guint   typeId;
1971         gboolean        optional;
1972         TBLTypeContent_t content;
1973         guchar  *fieldName;
1974         gboolean anonymous;
1975         gboolean constraint;
1976 };
1977
1978 struct _TBLTypeDef {
1979         tbl_t   type;
1980         guint   typeDefId;
1981         guchar  *typeName;
1982         guchar  isPdu;
1983 };
1984
1985 struct _TBLModule {
1986         tbl_t   type;
1987         guchar  *name;
1988         subid_t *id;
1989         guint   isUseful;
1990 };
1991
1992 struct _TT {
1993         guint   totalNumModules;
1994         guint   totalNumTypeDefs;
1995         guint   totalNumTypes;
1996         guint   totalNumTags;
1997         guint   totalNumStrings;
1998         guint   totalLenStrings;
1999 } TT;
2000
2001 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2002
2003 static guint
2004 get_asn1_int(guint want_tag, guint offset)
2005 {
2006         ASN1_SCK asn1;
2007         guint ret, cls, con, tag, def, len;
2008         guint value;
2009
2010         /* g_message("%d get_asn1_int", offset); */
2011
2012         asn1_open(&asn1, asn1_desc, offset);
2013
2014         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2015         if (ret == ASN1_ERR_NOERROR) {
2016                          /* do not check class, both Unversal and Context are OK */
2017                 if (con == ASN1_PRI && tag == want_tag) {
2018                         if (def) {
2019                                 asn1_uint32_value_decode(&asn1, len, &value);
2020                                 return value;
2021                         } else
2022                                 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2023                 } else
2024                         ret = ASN1_ERR_WRONG_TYPE;
2025         }
2026         g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2027
2028         return 0;
2029 }
2030
2031 static subid_t *                        /* with prepended length ..... */
2032 get_asn1_oid(guint want_tag, guint offset)
2033 {
2034         ASN1_SCK asn1;
2035         guint ret, cls, con, tag, def, len;
2036         subid_t *oid;
2037
2038         /* g_message("%d get_asn1_oid", offset); */
2039
2040         asn1_open(&asn1, asn1_desc, offset);
2041
2042         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2043         if (ret == ASN1_ERR_NOERROR) {
2044                         /* do not check class, both Unversal and Context are OK */
2045                 if ((con == ASN1_PRI) && (tag == want_tag))     {
2046                         if (def) {
2047                                 asn1_oid_value_decode(&asn1, len, &oid, &con);
2048                                 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2049                                 memmove(&oid[1], oid, con*sizeof(guint));
2050                                 oid[0] = con;
2051                                 return oid;
2052                         } else
2053                                 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2054                 } else
2055                         ret = ASN1_ERR_WRONG_TYPE;
2056         }
2057         g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2058
2059         return 0;
2060 }
2061
2062 static guchar *                 /* 0 terminated string */
2063 get_asn1_string(guint want_tag, guint offset)
2064 {
2065         ASN1_SCK asn1;
2066         guint ret, cls, con, tag, def, len;
2067         guchar *octets;
2068
2069         /* g_message("%d get_asn1_string", offset); */
2070
2071         asn1_open(&asn1, asn1_desc, offset);
2072
2073         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2074         if (ret == ASN1_ERR_NOERROR) {
2075                         /* do not check class, both Unversal and Context are OK */
2076                 if ((con == ASN1_PRI) && (tag == want_tag))     {
2077                         if (def) {
2078                                 asn1_string_value_decode(&asn1, len, &octets);
2079                                 octets = g_realloc(octets, len+1); /* need space for sentinel */
2080                                 octets[len] = 0;
2081                                 return octets;
2082                         } else
2083                                 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2084                 } else
2085                         ret = ASN1_ERR_WRONG_TYPE;
2086         }
2087         g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2088
2089         return 0;
2090 }
2091
2092 static guint
2093 get_asn1_uint(guint offset)
2094 {
2095         ASN1_SCK asn1;
2096         guint ret, len, value;
2097
2098         /* g_message( "%d get_asn1_uint", offset); */
2099
2100         asn1_open(&asn1, asn1_desc, offset);
2101
2102         ret = asn1_uint32_decode(&asn1, &value, &len);
2103
2104         if (ret != ASN1_ERR_NOERROR) {
2105                 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2106                 value = 0;
2107         }
2108         return value;
2109 }
2110
2111 static gboolean
2112 check_tag(guint want_tag, guint offset)
2113 {
2114         ASN1_SCK asn1;
2115         guint ret, cls, con, tag, def, len;
2116
2117         asn1_open(&asn1, asn1_desc, offset);
2118
2119         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2120         if (ret == ASN1_ERR_NOERROR) {
2121                 ret = (tag == want_tag) ? TRUE : FALSE;
2122                 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2123                 return ret;
2124         }
2125         g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2126
2127         return FALSE;
2128 }
2129
2130 #if 0
2131 static gboolean
2132 constructed(guint offset)
2133 {
2134         ASN1_SCK asn1;
2135         guint ret, cls, con, tag, def, len;
2136
2137         /* g_message("%d constructed?", offset); */
2138
2139         asn1_open(&asn1, asn1_desc, offset);
2140
2141         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2142         if (ret == ASN1_ERR_NOERROR) {
2143                 if (con) {
2144                         return TRUE;
2145                 }
2146                 return FALSE;
2147         }
2148         /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2149
2150         return FALSE;
2151 }
2152 #endif
2153
2154 static void
2155 define_constraint(GNode *p, GNode *q)
2156 {
2157         TBLRange *range = g_malloc(sizeof(TBLRange));
2158         g_node_append_data(q, range);
2159
2160         range->type = TBLTYPE_Range;
2161
2162         /* g_message("define_constraint %p, %p", p, q); */
2163
2164         p = g_node_first_child(p);
2165
2166         range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2167         p = g_node_next_sibling(p);
2168
2169         range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2170
2171 }
2172
2173 static void
2174 define_namednumber(GNode *p, GNode *q)
2175 {
2176         TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2177         g_node_append_data(q, num);
2178
2179         num->type = TBLTYPE_NamedNumber;
2180
2181         /* g_message("define_namednumber %p, %p", p, q); */
2182
2183         p = g_node_first_child(p);
2184
2185         num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2186         p = g_node_next_sibling(p);
2187
2188         num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2189 }
2190
2191 static void
2192 define_typeref(GNode *p, GNode *q)
2193 {
2194         TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2195         g_node_append_data(q, ref);
2196
2197         ref->type = TBLTYPE_TypeRef;
2198
2199         /* g_message("define_typeref %p, %p", p, q); */
2200
2201         p = g_node_first_child(p);
2202
2203         ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2204         p = g_node_next_sibling(p);
2205
2206         ref->implicit = get_asn1_int(ASN1_BOL, GPOINTER_TO_UINT(p->data));
2207 }
2208
2209 static void
2210 define_tag(GNode *p, GNode *q)
2211 {
2212         TBLTag *type = g_malloc(sizeof(TBLTag));
2213         g_node_append_data(q, type);
2214
2215         type->type = TBLTYPE_Tag;
2216
2217         /* g_message("define_tag %p, %p", p, q); */
2218
2219         p = g_node_first_child(p);
2220
2221         type->tclass = get_asn1_int(ASN1_ENUM, GPOINTER_TO_UINT(p->data));
2222         p = g_node_next_sibling(p);
2223
2224         type->code = get_asn1_int(ASN1_INT, GPOINTER_TO_UINT(p->data));
2225
2226 }
2227
2228 static void
2229 define_type(GNode *p, GNode *q)
2230 {
2231         GNode *r;
2232         TBLType *type = g_malloc(sizeof(TBLType));
2233
2234         GNode *t = g_node_append_data(q, type);
2235
2236         type->type = TBLTYPE_Type;
2237
2238         /* g_message("define_type %p, %p", p, q); */
2239
2240         type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2241         p = g_node_next_sibling(p);
2242
2243         type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2244         p = g_node_next_sibling(p);
2245
2246         if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
2247                 r = g_node_first_child(p);
2248                 while (r) {
2249                         define_tag(r, t);
2250                         r = g_node_next_sibling(r);
2251                 }
2252                 p = g_node_next_sibling(p);
2253         }
2254
2255         if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
2256                 g_warning("expect tag 3, ERROR");
2257         }
2258         r = g_node_first_child(p);
2259                 /* a choice ... */
2260         type->content = TBLTYPETYPE_None;
2261         if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
2262         if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
2263         if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
2264         switch(type->content) {
2265                 case TBLTYPETYPE_Primitive:
2266                         break;
2267                 case TBLTYPETYPE_Elements:
2268                         r = g_node_first_child(r);
2269                         while (r) {
2270                                 define_type(g_node_first_child(r), t);
2271                                 r = g_node_next_sibling(r);
2272                         }
2273                         break;
2274                 case TBLTYPETYPE_TypeRef:
2275                         define_typeref(r, t);
2276                         break;
2277                 case TBLTYPETYPE_None:
2278                         g_warning("expected a contents choice, error");
2279                         break;
2280         }
2281         p = g_node_next_sibling(p);
2282
2283         type->fieldName = 0;
2284         type->anonymous = FALSE;
2285         if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
2286                 type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
2287                 p = g_node_next_sibling(p);
2288         } else {
2289                 type->anonymous = TRUE;
2290         }
2291
2292         type->constraint = FALSE;
2293         if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
2294                 type->constraint = TRUE;
2295                 define_constraint(p, t);
2296                 p = g_node_next_sibling(p);
2297         }
2298
2299         if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
2300                 r =  g_node_first_child(p);
2301                 while(r) {
2302                         define_namednumber(r, t);
2303                         r = g_node_next_sibling(r);
2304                 }
2305         }
2306 }
2307
2308 static void
2309 define_typedef(GNode *p, GNode *q)
2310 {
2311         TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2312
2313         GNode *t = g_node_append_data(q, type_def);
2314
2315         /* g_message("define_typedef %p, %p", p, q); */
2316
2317         type_def->type = TBLTYPE_TypeDef;
2318
2319         p = g_node_first_child(p);
2320
2321         type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2322         p = g_node_next_sibling(p);
2323
2324         type_def->typeName = get_asn1_string(ASN1_PRNSTR, GPOINTER_TO_UINT(p->data));
2325         p = g_node_next_sibling(p);
2326
2327         define_type(g_node_first_child(p), t);
2328         p = g_node_next_sibling(p);
2329
2330         type_def->isPdu = (p != 0);  /* true if it exists, value ignored */
2331 }
2332
2333 static void
2334 define_module(GNode *p, GNode *q)
2335 {
2336         TBLModule *module = g_malloc(sizeof(TBLModule));
2337
2338         GNode *m = g_node_append_data(q, module);
2339
2340         /* g_message("define_module %p %p", p, q); */
2341
2342         module->type = TBLTYPE_Module;
2343
2344         p = g_node_first_child(p);
2345
2346         module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2347         p = g_node_next_sibling(p);
2348
2349         module->id = 0;
2350         if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */
2351                 module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
2352                 p = g_node_next_sibling(p);
2353         }
2354
2355         module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
2356         p = g_node_next_sibling(p);
2357
2358         p = g_node_first_child(p);
2359         while (p) {
2360                 define_typedef(p, m);
2361                 p = g_node_next_sibling(p);
2362         }
2363 }
2364
2365 typedef struct _SearchDef SearchDef;
2366 struct _SearchDef {
2367         const char *key;
2368         GNode *here;
2369 };
2370
2371 static gboolean
2372 is_typedef(GNode *node, gpointer data)
2373 {
2374         TBLTypeDef *d = (TBLTypeDef *)node->data;
2375         SearchDef *s = (SearchDef *)data;
2376
2377         if (d == 0) return FALSE;
2378         if (d->type != TBLTYPE_TypeDef) return FALSE;
2379         if (strcmp(s->key, d->typeName) == 0) {
2380                 s->here = node;
2381                 return TRUE;
2382         }
2383         return FALSE;
2384 }
2385
2386 typedef struct _TypeRef TypeRef;
2387 struct _TypeRef {
2388         GNode *type;
2389         char *name;
2390         guchar defclass;
2391         guint deftag;
2392         GNode *pdu;             /* location in PDU descriptor tree */
2393         guint level;            /* recursion counter */
2394         GNode *typetree;
2395         GPtrArray *refs;        /* pointers to PDUinfo structures teferencing this entry */
2396 };
2397
2398 typedef struct _NameDefs NameDefs;
2399 struct _NameDefs {
2400         guint max;
2401         guint used;
2402         TypeRef *info;
2403 };
2404 #define ALLOC_INCR 4
2405 #define CLASSREF (ASN1_PRV+1)
2406
2407 static gboolean
2408 is_named(GNode *node, gpointer data)
2409 {
2410         TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2411         NameDefs *n = (NameDefs *)data;
2412         guint oldmax;
2413
2414         if (num == 0) return FALSE;
2415         if (num->type != TBLTYPE_NamedNumber) return FALSE;
2416
2417         if (num->value >= n->max) { /* need larger array */
2418                 oldmax = n->max;
2419                 n->max = num->value + ALLOC_INCR;
2420                 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2421                 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2422         }
2423         if (num->value > n->used)  /* track max used value, there may be holes... */
2424                 n->used = num->value;
2425
2426         n->info[num->value].name = num->name;
2427
2428         return FALSE;
2429 }
2430
2431 static gboolean
2432 index_typedef(GNode *node, gpointer data)
2433 {
2434         TBLTypeDef *d = (TBLTypeDef *)node->data;
2435         NameDefs *n = (NameDefs *)data;
2436         TypeRef *t;
2437         TBLTag *tag;
2438         guint oldmax;
2439
2440         if (d == 0) return FALSE;
2441         if (d->type != TBLTYPE_TypeDef) return FALSE;
2442
2443         if (d->typeDefId >= n->max) { /* need larger array */
2444                 oldmax = n->max;
2445                 n->max = d->typeDefId + ALLOC_INCR;
2446                 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2447                 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2448         }
2449         if (d->typeDefId > n->used)  /* track max used value, there may be holes... */
2450                 n->used = d->typeDefId;
2451
2452         t = &(n->info[d->typeDefId]);
2453         t->name = d->typeName;
2454         t->type = node;
2455         t->refs = g_ptr_array_new();    /* collect references here */
2456         node = g_node_first_child(node); /* the real type */
2457         tag = (TBLTag *)node->data;
2458         if ((tag->type == TBLTYPE_Type) && (((TBLType *)tag)->typeId == TBL_CHOICE)) {
2459                 /* no reasonable default... ! */
2460                 t->defclass = 3; /* Private .... */
2461                 t->deftag= 9999; /* a random value */
2462         } else {
2463                 node = g_node_first_child(node); /* the default tag */
2464                 tag = (TBLTag *)node->data;
2465                 switch(tag->type) {
2466                 case TBLTYPE_Tag:
2467                         t->defclass = tag->tclass;
2468                         t->deftag = tag->code;
2469                         break;
2470                 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2471                         t->defclass = CLASSREF; /* invalid class.. */
2472                         t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2473                         break;
2474                 default:
2475                         g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2476                                         data_types[tag->type]);
2477                         t->defclass = 3; /* Private .... */
2478                         t->deftag= 9998; /* another random value */
2479                         break;
2480                 }
2481         }
2482
2483         return FALSE;
2484 }
2485
2486 static TypeRef *typeDef_names = 0;
2487 static guint numTypedefs = 0;
2488
2489 static gboolean
2490 free_node_data(GNode *node, gpointer data _U_)
2491 {
2492         g_free(node->data);
2493         return FALSE;
2494 }
2495
2496 static void
2497 get_values(void)                /* collect values from ASN.1 tree */
2498                                 /* coded according to the tbl.asn1 description of snacc output */
2499 {                               /* This routine does not leave references to the tvbuff or */
2500                                 /* to the asn1_nodes, both can be freed by the caller of this.*/
2501         GNode *p;
2502         SearchDef sd;
2503         NameDefs nd;
2504         guint i;
2505         char X;
2506         const char *t, *s, *E;
2507         static char missing[] = "  **missing**  ";
2508
2509         if (asn1_verbose) g_message("interpreting tree");
2510         typeDef_names = 0;  /* just forget allocated any data .... */
2511
2512         if (data_nodes) {
2513                 g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2514                     free_node_data, NULL);
2515                 g_node_destroy(data_nodes);
2516         }
2517
2518         data_nodes = g_node_new(0);
2519
2520         p = g_node_first_child(asn1_nodes); /* top of the data tree */
2521
2522         p = g_node_first_child(p);
2523         TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2524         p = g_node_next_sibling(p);
2525         TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2526         p = g_node_next_sibling(p);
2527         TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2528         p = g_node_next_sibling(p);
2529         TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2530         p = g_node_next_sibling(p);
2531         TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2532         p = g_node_next_sibling(p);
2533         TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2534         p = g_node_next_sibling(p);
2535
2536         p = g_node_first_child(p);
2537         while (p) {
2538                 define_module(p, data_nodes);
2539                 p = g_node_next_sibling(p);
2540         }
2541
2542         /* g_message("finished with tree"); */
2543
2544         if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2545                 sd.key = "TBLTypeId";
2546                 sd.here = 0;
2547                 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2548                 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", sd.here);
2549                 if (sd.here) {
2550                         nd.max = 8;
2551                         nd.used = 0;
2552                         nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2553                         g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2554                                                 (gpointer)&nd);
2555                         if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, nd.info);
2556                         E = empty;
2557                         for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2558                                 X = 'X';
2559                                 t = TBLTYPE(i);
2560                                 s = nd.info[i].name;
2561                                 if (s == 0) s = missing;
2562                                 if (g_strcmp(t, s) == 0) { /* OK ! */
2563                                         X = ' ';
2564                                         t = empty;
2565                                 } else {
2566                                         E = ", X  with errors  X";
2567                                 }
2568                                 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2569                         }
2570                         if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2571                 }
2572                 tbl_types_verified = TRUE;
2573         }
2574         /* build table with typedef names */
2575         nd.max = 8;
2576         nd.used = 0;
2577         nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2578         g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2579         if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, nd.info);
2580
2581         for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2582                 TypeRef *ref = &(nd.info[i]);
2583                 t = ref->name;
2584                 if (t == 0) {
2585                         t = ref->name = missing;
2586                         if (asn1_verbose) g_message("  %3d %s", i, t);
2587                 } else {
2588                         if (asn1_verbose) g_message("  %3d %s, %c%d", i, t,
2589                                                     tag_class[ref->defclass], ref->deftag);
2590                 }
2591                 if (ref->pdu) { /* should be 0 */
2592                         if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, ref->pdu);
2593                 }
2594         }
2595         typeDef_names = nd.info;
2596         numTypedefs = i;
2597         if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
2598
2599 }
2600
2601 static void
2602 showGNode(GNode *p, int n)
2603 {
2604         if (p == 0) return;
2605         n *=2; /* 2 spaces per level */
2606         if (p->data) { /* show value ... */
2607                 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
2608                 switch (((TBLTag *)p->data)->type) {
2609                 case TBLTYPE_Module: {
2610                         TBLModule *m = (TBLModule *)p->data;
2611                         if (asn1_verbose)
2612                                 g_message("%*smodule %s%s", n, empty, m->name,
2613                                                 m->isUseful ? ", useful" : empty);
2614                         };
2615                         break;
2616                 case TBLTYPE_TypeDef: {
2617                         TBLTypeDef *t = (TBLTypeDef *)p->data;
2618                         if (asn1_verbose)
2619                                 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
2620                                                 t->isPdu ? ", isPDU" : empty);
2621                         };
2622                         break;
2623                 case TBLTYPE_Type: {
2624                         TBLType *t = (TBLType *)p->data;
2625                         const char *fn, *s = empty;
2626                         if (t->fieldName)
2627                                 s = t->fieldName;
2628                         /* typeId is a value from enum TBLTypeId */
2629                         fn = TBLTYPE(t->typeId);
2630                         if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
2631                                         t->optional ? " opt" : empty, s );
2632                         };
2633                         break;
2634                 case TBLTYPE_Tag: {
2635                         TBLTag *t = (TBLTag *)p->data;
2636                         const char *s = empty;
2637                         if ((t->tclass == ASN1_UNI) && (t->code < 32))
2638                                 s = asn1_tag[t->code];
2639                         if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
2640                                                     tag_class[t->tclass], t->code, s);
2641                         };
2642                         break;
2643                 case TBLTYPE_NamedNumber: {
2644                         TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
2645                         if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
2646                                                     nn->value, nn->name);
2647                         };
2648                         break;
2649                 case TBLTYPE_Range: {
2650                         TBLRange *r = (TBLRange *)p->data;
2651                         if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
2652                                                     r->from, r->to );
2653                         };
2654                         break;
2655                 case TBLTYPE_TypeRef: {
2656                         TBLTypeRef *r = (TBLTypeRef *)p->data;
2657                         const char *s = empty;
2658                         if (typeDef_names)
2659                                 s = typeDef_names[r->typeDefId].name;
2660                         if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
2661                                                   r->typeDefId, s, r->implicit ? ", implicit" : empty );
2662                         };
2663                         break;
2664                 default: {
2665                         TBLTag *x = (TBLTag *)p->data;
2666                         if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
2667                         };
2668                         break;
2669                 }
2670         } else {        /* just show tree */
2671                 if (asn1_verbose)
2672                         g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
2673                                   n, empty, p, p->data, p->next, p->prev, p->parent, p->children);
2674         }
2675 }
2676
2677 static void
2678 showGNodes(GNode *p, int n)
2679 {
2680         if (p == 0) return;
2681         showGNode(p, n);
2682         showGNodes(p->children, n+1);
2683         showGNodes(p->next, n);
2684 }
2685
2686 static void showGenv(GNode *p, int n, int m)
2687 {
2688         int i;
2689
2690         if (p == 0) return;
2691         if (n > m) {
2692                 if (asn1_verbose) g_message("%*s.....", n*2, empty);
2693                 return;
2694         }
2695
2696         for(i=0; p && (i < 3); p = p->next, i++) {
2697                 showGNode(p, n);
2698                 showGenv(p->children, n+1, m);
2699         }
2700         if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
2701
2702 }
2703
2704 static void
2705 debug_dump_TT(void)             /* dump contents of TT struct, for debugging */
2706 {
2707         if (asn1_verbose)
2708                 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
2709                         TT.totalNumModules,
2710                         TT.totalNumTypeDefs,
2711                         TT.totalNumTypes,
2712                         TT.totalNumTags,
2713                         TT.totalNumStrings,
2714                         TT.totalLenStrings);
2715 }
2716
2717 static void
2718 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
2719                 const gchar *message, gpointer user_data)
2720 {
2721 static FILE* logf = 0;
2722 static char eol[] = "\r\n";
2723
2724         (void) log_domain; (void) log_level; (void) user_data; /* make references */
2725
2726         if (logf == NULL && asn1_logfile) {
2727                 logf = eth_fopen(asn1_logfile, "w");
2728         }
2729         if (logf) {
2730         fputs(message, logf);
2731         fputs(eol, logf);
2732         fflush(logf);   /* debugging ... */
2733         }
2734 }
2735
2736 static void
2737 read_asn1_type_table(const char *filename)
2738 {
2739         FILE *f;
2740         guint size;
2741         guchar *data;
2742         struct stat stat;
2743
2744         if ((filename == 0) || (strlen(filename) == 0))
2745                 return;         /* no filename provided */
2746
2747         f = eth_fopen(filename, "rb");
2748         if (f == 0) {
2749                 /*
2750                  * Ignore "file not found" errors if it's the old default
2751                  * ASN.1 file name, as we never shipped such a file.
2752                  * Also, on Win32, ignore the earlier default, which
2753                  * had a "/" rather than a "\" as the last pathname
2754                  * separator.
2755                  */
2756 #ifdef _WIN32
2757                 if (strcmp(filename, bad_separator_old_default_asn1_filename) != 0)
2758 #endif
2759                         if ((strcmp(filename, old_default_asn1_filename) != 0) || errno != ENOENT)
2760                                 report_open_failure(filename, errno, FALSE);
2761                 return;
2762         }
2763         fstat(fileno(f), &stat);
2764         size = (int)stat.st_size;
2765         if (size == 0) {
2766                 if (asn1_verbose) g_message("file %s is empty, ignored", filename);
2767                 fclose(f);
2768                 return;
2769         }
2770         if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
2771
2772         data = g_malloc(size);
2773         if (fread(data, size, 1, f) < 1) {
2774                 g_warning("error reading %s, %s", filename, strerror(errno));
2775         }
2776         fclose(f);
2777
2778         if (asn1_verbose) {
2779           /* ***** from the time when logging was just in a console... *****
2780            * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
2781            *            "  Sleep 5 sec...");
2782            * Sleep(5 * 1000);
2783            */
2784
2785                 static guint mylogh = 0;
2786
2787                 g_message("logging to file %s", asn1_logfile);
2788
2789                 if (mylogh == 0) {
2790                         mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2791                                                     | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
2792                 }
2793         }
2794
2795         asn1_desc = tvb_new_real_data(data, size, size);
2796
2797         tt_build_tree();
2798         if (asn1_verbose) g_message("read %d items from %s", icount, filename);
2799
2800 #if 0
2801         list_modules();
2802 #endif
2803
2804         get_values();
2805
2806         g_node_destroy(asn1_nodes);     asn1_nodes = 0;
2807 #ifndef _WIN32          /* tvb_free not yet exported to plugins... */
2808         tvb_free(asn1_desc);
2809 #endif
2810                                         asn1_desc = 0;
2811         g_free(data);                   data = 0;
2812
2813         showGNodes(data_nodes, 0);
2814
2815         debug_dump_TT();
2816 }
2817
2818
2819 /* XXX - Shoudn't we make sure we're not dereferencing a NULL pointer here? */
2820 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
2821         g_warning("**** unexpected type %s, want %s, at line %d", \
2822                         data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
2823
2824
2825 static void
2826 save_reference(PDUinfo *p)
2827 {
2828         gint i = p->mytype;
2829
2830         if (i == -1)
2831                 i = p->basetype;
2832
2833         g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
2834 }
2835
2836 static void
2837 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex);
2838
2839
2840
2841         /* evaluate typeref, pointer to current pdu node and typedef */
2842 static void
2843 tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
2844 {
2845         GNode *q;
2846         PDUinfo *p = (PDUinfo *)pdu->data, *p1;
2847         guint nvals;
2848         value_string *v;
2849
2850         if (n > 40) {  /* don't believe this....! ...... stop recursion ...... */
2851                 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
2852                 return;
2853         }
2854
2855         CHECKTYPE(tree, TBLTYPE_TypeDef);
2856
2857         if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
2858                                     p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2859
2860         p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
2861         p->flags |= PDU_TYPEDEF;
2862
2863         tree = g_node_first_child(tree);                /* move to its underlying type */
2864         CHECKTYPE(tree, TBLTYPE_Type);
2865         p->type = ((TBLType *)tree->data)->typeId;
2866
2867         q = g_node_first_child(tree);           /* the tag of this type entry ... is optional... */
2868         if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
2869                 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
2870                         guint xcls, xtag;
2871                         xcls = p->tclass;
2872                         xtag = p->tag;
2873                                 /* XXX -- hack -- hack -- hack -- hack -- hack --
2874                                  * only change tag when class+tag == EOC,
2875                                  * or class is a reference,
2876                                  * or new class is not universal.
2877                                  */
2878                         if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
2879                                         (((TBLTag *)q->data)->tclass != ASN1_UNI) ) {
2880                                 p->tclass = ((TBLTag *)q->data)->tclass;
2881                                 p->tag = ((TBLTag *)q->data)->code;
2882                                 if (asn1_verbose)
2883                                         g_message("%*s*change typeref tag from %c%d to %c%d",
2884                                                   n*2, empty,
2885                                                   tag_class[xcls],
2886                                                   xtag,
2887                                                   tag_class[p->tclass],
2888                                                   p->tag);
2889                         } else {
2890                                 if (asn1_verbose)
2891                                         g_message("%*sNOT changing tag from %c%d to %c%d",
2892                                                   n*2, empty,
2893                                                   tag_class[xcls],
2894                                                   xtag,
2895                                                   tag_class[((TBLTag *)q->data)->tclass],
2896                                                   ((TBLTag *)q->data)->code);
2897
2898                         }
2899                 }
2900         } else {
2901                 char ss[128];
2902
2903                 ss[0] = 0;
2904                 if (p->tclass==CLASSREF)
2905                         g_snprintf(ss, 128, ", CLASSREF %d", p->tag);
2906                 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
2907
2908                 if (p->tclass==CLASSREF) {
2909                         TypeRef *tr;
2910                         int i = p->basetype;
2911                         /* CLASSREF....., get it defined using type of the reference */
2912
2913                         /* p->basetype may be -1 .... ? XXX */
2914                         if (i == -1)
2915                                 i = p->tag;
2916                         tr = &typeDef_names[i];
2917                         if (asn1_verbose)
2918                                 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
2919                                           p->tag, tr->name, tr->pdu);
2920
2921                         tbl_typeref(n+1, pdu, tr->type, fullindex);
2922
2923                         return;
2924                 }
2925         }
2926
2927         if (asn1_verbose)
2928                 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
2929                           p->name, p->typename, p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2930
2931         switch(p->type) {
2932         case TBL_BITSTRING:
2933         case TBL_ENUMERATED:
2934                 /* names do not have a fullname */
2935                 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
2936                         /* read the enumeration [save min-max somewhere ?] */
2937                 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type]; /* XXX change field type... */
2938
2939                 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2940
2941                 save_reference(p);
2942
2943                 if (asn1_verbose)
2944                         g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2945                                   p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2946                                   p->name, p->fullname,
2947                                   tbl_types_wireshark_txt[p->type], p->value_id);
2948                 p1 = p;
2949                 nvals = 0;
2950                 while((q = g_node_next_sibling(q))) {
2951                         CHECKTYPE(q, TBLTYPE_NamedNumber);
2952                         p = g_malloc0(sizeof(PDUinfo));
2953                         nvals++;
2954                         p->type = TBL_ENUMERATED;
2955                         p->name = (((TBLNamedNumber *)q->data)->name);
2956                         p->tag = (((TBLNamedNumber *)q->data)->value);
2957                         p->flags = PDU_NAMEDNUM;
2958                         if (asn1_verbose) g_message("%*s  %3d %s", n*2, empty, p->tag, p->name);
2959                         g_node_append_data(pdu, p);
2960                 }
2961
2962                 /* list all enum values in the field structure for matching */
2963                 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
2964                 q = g_node_first_child(pdu);
2965                 nvals = 0;
2966                 while(q) {
2967                         p = (PDUinfo *)q->data;
2968                         v[nvals].value = p->tag;
2969                         v[nvals].strptr = p->name;
2970 /* g_message("enumval2:  %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
2971                         nvals++;
2972                         q = g_node_next_sibling(q);
2973                 }
2974                 /* last entry is already initialized to { 0, NULL } */
2975
2976                 break;
2977
2978         case TBL_CHOICE:
2979                 if (p->value_id == -1) { /* not yet registered ..... */
2980                         p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
2981                         proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2982
2983                         save_reference(p);
2984
2985                         if (asn1_verbose)
2986                                 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
2987                                           p->mytype, p->typenum, p->basetype, p->flags, p->typename,
2988                                           p->name, p->fullname,
2989                                           tbl_types_wireshark_txt[p->type], p->value_id);
2990                 }
2991                 tbl_type(n, pdu, q, fullindex);
2992                 break;
2993
2994         default:
2995                 if (p->value_id == -1) { /* not yet registered ..... */
2996                         p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
2997                         proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
2998
2999                         save_reference(p);
3000
3001                         if (asn1_verbose)
3002                                 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3003                                           p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3004                                           p->name, p->fullname,
3005                                           tbl_types_wireshark_txt[p->type], p->value_id);
3006                 }
3007                 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
3008         }
3009 }
3010
3011 static void
3012 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
3013 {
3014         GNode *q, *pdu1;
3015         PDUinfo *p, *p1;
3016         guint ni;
3017         guint nvals;
3018         value_string *v;
3019
3020         if (n > 40) {  /* don't believe this....! ...... stop recursion ...... */
3021                 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3022                 return;
3023         }
3024
3025         /* showGenv(list, n, n+1); */
3026
3027         ni = fullindex;
3028         pdu1 = pdu;             /* save start location for append */
3029         while (list) {          /* handle all entries */
3030                 if (asn1_verbose)
3031                         g_message("%*s+handle a %s, list=%p", n*2, empty,
3032                                   data_types[((TBLTag *)list->data)->type], list);
3033
3034                 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
3035                         list = g_node_next_sibling(list);
3036                         if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
3037                         if (list == 0)
3038                                 break;
3039                 }
3040
3041                 /******* change to positive comparation, but leave comment for reference
3042                  * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3043                  *      CHECKTYPE(list, TBLTYPE_Type);
3044                  */
3045
3046                 if (((TBLTag *)list->data)->type == TBLTYPE_Type) {
3047                         CHECKTYPE(list, TBLTYPE_Type);
3048
3049                         p = g_malloc0(sizeof(PDUinfo));
3050                         pdu = g_node_append_data(pdu1, p);
3051
3052                         p->type = ((TBLType *)list->data)->typeId;
3053                         p->typename = tbl_types_asn1[p->type]; /* the default type */
3054                         p->typenum = -1;
3055                         p->mytype = -1;
3056                         p->basetype = ((PDUinfo *)pdu1->data)->typenum;
3057                         p->flags = PDUinfo_initflags;
3058                         p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
3059                         p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
3060
3061                         if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
3062                                 /* assign an anonymous name [XXX refer to parent typename...] */
3063                                 ((TBLType *)list->data)->fieldName =
3064                                                         g_strdup_printf("anon%d", anonCount++);
3065                         }
3066                         p->name = ((TBLType *)list->data)->fieldName;
3067
3068                         ni = fullindex;
3069                         ni += snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
3070                         p->fullname = g_strdup(fieldname);
3071
3072                         /* initialize field info */
3073                         p->value_id = -1;
3074                         p->type_id = -1;
3075                         p->value_hf.p_id = &(p->value_id);
3076                         p->value_hf.hfinfo.name = p->fullname;
3077                         p->value_hf.hfinfo.abbrev = p->fullname;
3078                         p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3079                         p->value_hf.hfinfo.display = BASE_DEC;
3080                         p->value_hf.hfinfo.blurb = p->fullname;
3081                         /* all the other fields are already 0 ! */
3082
3083                         if (p->type < TBL__SIMPLE) {
3084                                 /* only register fields with a value here, postpone others */
3085                                 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3086
3087                                 save_reference(p);
3088
3089                                 if (asn1_verbose)
3090                                         g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3091                                                   p->mytype, p->typenum, p->basetype, p->flags,
3092                                                   p->typename, p->name, p->fullname,
3093                                                   tbl_types_wireshark_txt[p->type], p->value_id);
3094                         }
3095
3096                         q = g_node_first_child(list);
3097                 } else {
3098                         p = (PDUinfo *)pdu->data;
3099                         q = list;
3100                 }
3101
3102
3103                 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
3104
3105                 switch (p->type) {
3106                 case TBL_BOOLEAN:
3107                 case TBL_INTEGER:
3108                 case TBL_OCTETSTRING:
3109                 case TBL_NULL:
3110                 case TBL_OID:
3111                 case TBL_REAL:
3112                         CHECKTYPE(q, TBLTYPE_Tag);
3113                         p->tclass = ((TBLTag *)q->data)->tclass;
3114                         p->tag = ((TBLTag *)q->data)->code;
3115                         break;
3116
3117                 case TBL_BITSTRING:
3118                 case TBL_ENUMERATED:
3119                         CHECKTYPE(q, TBLTYPE_Tag);
3120                         p->tclass = ((TBLTag *)q->data)->tclass;
3121                         p->tag = ((TBLTag *)q->data)->code;
3122                         if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
3123                                 /* read the enumeration [save min-max somewhere ?] */
3124                         nvals = 0;
3125                         p1 = p;
3126                         while((q = g_node_next_sibling(q))) {
3127                                 CHECKTYPE(q, TBLTYPE_NamedNumber);
3128                                 p = g_malloc0(sizeof(PDUinfo));
3129                                 nvals++;
3130                                 p->type = TBL_ENUMERATED;
3131                                 p->name = (((TBLNamedNumber *)q->data)->name);
3132                                 p->tag = (((TBLNamedNumber *)q->data)->value);
3133                                 p->flags = PDU_NAMEDNUM;
3134                                 if (asn1_verbose) g_message("%*s  %3d %s", n*2, empty, p->tag, p->name);
3135                                 g_node_append_data(pdu, p);
3136                         }
3137
3138                         /* list all enum values in the field structure for matching */
3139                         p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3140                         q = g_node_first_child(pdu);
3141                         nvals = 0;
3142                         while(q) {
3143                                 p = (PDUinfo *)q->data;
3144                                 v[nvals].value = p->tag;
3145                                 v[nvals].strptr = p->name;
3146                         /* g_message("enumval1:  %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3147                                 nvals++;
3148                                 q = g_node_next_sibling(q);
3149                         }
3150                         /* last entry is already initialized to { 0, NULL } */
3151
3152                         break;
3153
3154                 case TBL_SEQUENCE:
3155                 case TBL_SET:
3156                 case TBL_SEQUENCEOF:
3157                 case TBL_SETOF:
3158                 case TBL_CHOICE:
3159                         CHECKTYPE(q, TBLTYPE_Tag);
3160                         q = g_node_first_child(list);
3161                         tbl_type(n+1, pdu, q, ni);
3162                         break;
3163
3164                 case TBL_TYPEREF: {     /* may have a tag ... */
3165                         TypeRef *tr;
3166                         guint i;
3167                         if(!q){
3168                                 break;
3169                         }
3170                         if ( ((TBLTag *)q->data)->type == TBLTYPE_Tag) {
3171                                 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3172                                         p->tclass = ((TBLTag *)q->data)->tclass;
3173                                         p->tag = ((TBLTag *)q->data)->code;
3174                                         if (asn1_verbose)
3175                                                 g_message("%*s*insert type tag %c%d", n*2, empty,
3176                                                           tag_class[p->tclass], p->tag);
3177                                 }
3178                                 q = g_node_next_sibling(q);
3179                         } else { /* use default tag for this type */
3180                                 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3181                                 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != ASN1_UNI)) ||
3182                                                                 ((p->tclass | p->tag) == 0 )) {
3183                                         /* not implicit, use this tag */
3184                                         p->tclass = tr->defclass;
3185                                         p->tag = tr->deftag;
3186                                         if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3187                                                                     tag_class[p->tclass], p->tag);
3188                                 }
3189                         }
3190                         CHECKTYPE(q, TBLTYPE_TypeRef);
3191                         i = ((TBLTypeRef *)q->data)->typeDefId;
3192                         p->mytype = i;
3193                         tr = &typeDef_names[i];
3194                         if (asn1_verbose)
3195                                 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, tr->pdu);
3196                         p->typename = tr->name;
3197
3198                         if (tr->defclass == CLASSREF) {
3199                                 if (tr->pdu == 0)
3200                                         tr->pdu = pdu;  /* remember this reference */
3201                                 i = tr->deftag;
3202                                 tr =  &typeDef_names[i];
3203                                 if (asn1_verbose)
3204                                         g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3205                                                   i, tr->name, tr->pdu);
3206                         }
3207                         /* evaluate reference if not done before or when below recursion limit */
3208                         if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3209                                 tr->level++;
3210                                 if (tr->pdu == 0) {
3211                                         tr->pdu = pdu; /* save for references we leave */
3212                                 }
3213                                 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3214                                 if (asn1_verbose)
3215                                         g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3216                                                   p->name,
3217                                                   ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3218                                                   tr->name,
3219                                                   pdu);
3220                                 tbl_typeref(n+1, pdu, tr->type, ni);
3221                                 tr->level--;
3222                         } else {
3223                                 if (asn1_verbose)
3224                                         g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3225                                                   p->name, tr->name, tr->pdu);
3226                                 p->flags |= PDU_REFERENCE;
3227                                 p->reference = tr->pdu;
3228                         }
3229                         };
3230                         break;
3231                 default:
3232                         g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3233                         break;
3234                 }
3235
3236                 if (asn1_verbose)
3237                         g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3238                                   n*2, empty, p->name, p->typename, p, TBLTYPE(p->type),
3239                                   tag_class[p->tclass], p->tag);
3240
3241                 if (p->value_id == -1) { /* not registered before, do it now */
3242                         proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3243
3244                         save_reference(p);
3245
3246                         if (asn1_verbose)
3247                                 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3248                                           p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3249                                           p->name, p->fullname,
3250                                           tbl_types_wireshark_txt[p->type], p->value_id);
3251                         }
3252                 list = g_node_next_sibling(list);
3253         }
3254 }
3255
3256 static void
3257 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
3258 {
3259         PDUinfo *rinfo;
3260         const char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3261
3262         if (info) {
3263                 tt = TBLTYPE(info->type);
3264                 nn = info->name;
3265                 tn = info->typename;
3266                 fn = info->fullname;
3267                 if (info->flags & PDU_NAMEDNUM)
3268                         txt += sprintf(txt, "name: %2d %s", info->tag, nn);
3269                 else {
3270                         if (info->flags & PDU_TYPEDEF)
3271                                 txt += sprintf(txt, "def %d: ", info->typenum);
3272                         else
3273                                 txt += sprintf(txt, "  ");
3274                         ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3275                         txt += sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3276                                      tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3277                         txt += sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
3278                         oo = (info->flags & PDU_OPTIONAL) ?  ", optional"  : empty;
3279                         ii = (info->flags & PDU_IMPLICIT) ?  ", implicit"  : empty;
3280                         nn = (info->flags & PDU_NAMEDNUM) ?  ", namednum"  : empty;
3281                         an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3282                         txt += sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
3283                         if (info->flags & PDU_REFERENCE) {
3284                                 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3285                                 tt = TBLTYPE(rinfo->type);
3286                                 nn = rinfo->name;
3287                                 tn = rinfo->typename;
3288                                 fn = rinfo->fullname;
3289                                 txt += sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3290                                 if (rinfo->flags & PDU_TYPEDEF)
3291                                         txt += sprintf(txt, " T%d", rinfo->typenum);
3292                                 txt += sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3293                                 oo = (rinfo->flags & PDU_OPTIONAL) ?  ", optional"  : empty;
3294                                 ii = (rinfo->flags & PDU_IMPLICIT) ?  ", implicit"  : empty;
3295                                 nn = (rinfo->flags & PDU_NAMEDNUM) ?  ", namednum"  : empty;
3296                                 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3297                                 tt = (rinfo->flags & PDU_TYPEDEF) ?   ", typedef"   : empty;
3298                                 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3299                                 tr = (rinfo->flags & PDU_TYPETREE) ?  ", typetree"  : empty;
3300                                 txt += sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3301                         }
3302                 }
3303         } else {
3304                 strcpy(txt, "no info available");
3305         }
3306
3307         return;
3308 }
3309
3310
3311 static void
3312 showPDUtree(GNode *p, int n)
3313 {
3314         PDUinfo *info;
3315         char text[400];
3316
3317         while (p != 0) {
3318                 info = (PDUinfo *)p->data;
3319
3320                 PDUtext(text, info);
3321
3322                 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3323
3324                 showPDUtree(g_node_first_child(p), n+1);
3325
3326                 p = g_node_next_sibling(p);
3327         }
3328
3329         return;
3330 }
3331
3332 static gboolean
3333 build_pdu_tree(const char *pduname)
3334 {
3335         SearchDef sd;
3336         guint pdudef, i, tcount;
3337         guint sav_len;
3338         PDUinfo *info;
3339
3340         if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3341
3342         if (!data_nodes) {
3343                 if (asn1_verbose) g_message("no data nodes");
3344                 return FALSE;
3345         }
3346         sd.key = pduname;
3347         sd.here = 0;
3348         g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3349         if (sd.here) {
3350                 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3351                 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, sd.here, pdudef);
3352         } else {
3353                 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3354                 return FALSE;
3355         }
3356
3357         /* If there's an existing PDU tree, free it */
3358         if (PDUtree) {
3359                 g_node_traverse(PDUtree, G_POST_ORDER, G_TRAVERSE_ALL, -1,
3360                     free_node_data, NULL);
3361                 g_node_destroy(PDUtree);
3362         }
3363
3364         /* initialize the PDU tree, hand craft the root entry */
3365
3366         info = g_malloc0(sizeof(PDUinfo));
3367         info->name = pduname;
3368         info->typename = pduname;
3369         info->type = TBL_SEQUENCEOF;
3370         info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3371         info->flags = PDUinfo_initflags = 0;
3372         info->value_id = -1;
3373         info->type_id = -1;
3374         info->basetype = -1;
3375         info->mytype = pdudef;
3376
3377         info->value_hf.p_id = &(info->value_id);
3378         info->value_hf.hfinfo.name = info->fullname;
3379         info->value_hf.hfinfo.abbrev = info->fullname;
3380         info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3381         info->value_hf.hfinfo.display = BASE_DEC;
3382         info->value_hf.hfinfo.blurb = info->fullname;
3383
3384         anonCount = 0; /* anonymous types counter */
3385
3386         PDUtree = g_node_new(info);
3387         pabbrev_pdu_len = sprintf(fieldname, "%s.%s.", pabbrev, pduname);
3388         sav_len = pabbrev_pdu_len;
3389
3390         /* Now build the tree for this top level PDU */
3391         if (asn1_verbose)
3392                 g_message("******** Define main type %d, %s", pdudef, pduname);
3393         tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1);    /* strip initial . for new names */
3394
3395         if (asn1_verbose)
3396                 g_message("%d anonymous types", anonCount);
3397
3398         /* Now make all types used available for matching */
3399         if (asn1_verbose)
3400                 g_message("Define the types that are actually referenced through the top level PDU");
3401         for (i=0, tcount=0; i<numTypedefs; i++) {
3402                 TypeRef *tr = &(typeDef_names[i]);
3403
3404                 if (tr->pdu) {  /* ignore if not used in main pdu */
3405                         tcount++;
3406                         if (i == pdudef)
3407                                 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3408                         if (asn1_verbose)
3409                                 g_message("******** Define type %d, %s", i, tr->name);
3410
3411                         /* .... do definition ..... */
3412                         info = g_malloc0(sizeof(PDUinfo));
3413                         info->name = tr->name;
3414                         info->typename = tr->name;
3415                         info->tclass = tr->defclass;
3416                         info->tag = tr->deftag;
3417                         info->type = TBL_TYPEREF;
3418                         info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3419                         info->flags = PDUinfo_initflags = PDU_TYPETREE;
3420                         info->value_id = -1;
3421                         info->type_id = -1;
3422                         info->basetype = -1;
3423                         info->mytype = i;
3424
3425                         info->value_hf.p_id = &(info->value_id);
3426                         info->value_hf.hfinfo.name = info->fullname;
3427                         info->value_hf.hfinfo.abbrev = info->fullname;
3428                         info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3429                         info->value_hf.hfinfo.display = BASE_DEC;
3430                         info->value_hf.hfinfo.blurb = info->fullname;
3431
3432                         tr->typetree = g_node_new(info);
3433                         pabbrev_pdu_len = sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
3434                         tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3435                 }
3436         }
3437         if (asn1_verbose)
3438                 g_message("%d types used", tcount);
3439
3440         pabbrev_pdu_len = sav_len;
3441
3442         /* and show the result */
3443         if (asn1_verbose)
3444                 g_message("Type index:");
3445         for (i=0; i<numTypedefs; i++) {
3446                 TypeRef *tr = &(typeDef_names[i]);
3447                 guint j, k;
3448                 gint defid;
3449                 PDUinfo *p, *q;
3450                 char text[400];
3451
3452                 if (tr->pdu == 0) /* skip if not used */
3453                         continue;
3454
3455                 if (asn1_verbose)
3456                         g_message("  %3d %s, %c%d, refs: %d",
3457                                   i, tr->name, tag_class[tr->defclass], tr->deftag,
3458                                   g_ptr_array_len(tr->refs));
3459
3460                 /* get defining node for this type */
3461                 defid = -1;
3462                 if (tr->typetree) {
3463                         p = (PDUinfo *)(tr->typetree->data);
3464                         defid = p->value_id;
3465                         if (asn1_verbose)
3466                                 g_message("      -- defining id=%d", defid);
3467                 }
3468                 for(j=0; j < g_ptr_array_len(tr->refs); j++) {  /* show refs, and set type_id */
3469                         p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3470                         if (p->mytype == (gint)i)
3471                                 p->type_id = defid;     /* normal reference */
3472                         else {
3473                                 if ((p->flags & PDU_TYPETREE) == 0) {
3474                                         /* we have a primitive value, find its real type */
3475                                         for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3476                                                         /* look at all refs */
3477                                                 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3478                                                 if ((q->flags & PDU_TYPETREE) == 0)
3479                                                         continue; /* only type trees are interresting */
3480                                                 if (q->type != p->type)
3481                                                         continue; /* must be same types */
3482                                                 if (strcmp(q->name, p->name) == 0) {
3483                                                         /* OK, take the first we find, not entirely
3484                                                          * correct, it may be from a different
3485                                                          * base-base type...... XXX */
3486                                                         p->type_id = q->value_id;
3487                                                         break;
3488                                                 }
3489                                         }
3490                                 }
3491                         }
3492
3493                         if (asn1_verbose) {
3494                                 PDUtext(text, p);
3495                                 g_message("      %s", text);
3496                         }
3497                 }
3498         }
3499
3500         if (asn1_verbose)
3501                 g_message("The resulting PDU tree:");
3502         showPDUtree(PDUtree, 0);
3503
3504         return TRUE;
3505 }
3506
3507
3508 #ifdef DISSECTOR_WITH_GUI
3509 /* This cannot work in tshark.... don't include for now */
3510 #if GTK_MAJOR_VERSION >= 2
3511 #define SHOWPDU /* this needs GTK2 */
3512 #endif
3513 #endif /* DISSECTOR_WITH_GUI */
3514 #ifdef SHOWPDU
3515
3516 static GtkWidget *window = NULL;
3517
3518 /* the columns in the tree view */
3519 enum
3520 {
3521    TITLE_COLUMN,                /* text in this row */
3522    DEF_COLUMN,                  /* definition in this row, if any */
3523    REF_COLUMN,                  /* referennce from this column, if any */
3524    VALUE_COLUMN,                /* indicate this is a value */
3525    NAME_COLUMN,                 /* name of this row */
3526    N_COLUMNS
3527 };
3528
3529 static FILE *namelist = 0;
3530
3531 static void
3532 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3533 {
3534         GtkTreeIter iter2;
3535         PDUinfo *info, *rinfo;
3536         gint def, ref;
3537         guchar *pb;
3538
3539         char text[400];
3540
3541         while (p != 0) {
3542                 info = (PDUinfo *)p->data;
3543
3544                 gtk_tree_store_append (store, &iter2, iter);  /* Acquire iterator */
3545
3546                 PDUtext(text, info);
3547
3548                 def = ref = -1;
3549                 if (info->flags & PDU_TYPEDEF)
3550                         def = info->typenum;
3551
3552                 if (info->flags & PDU_REFERENCE) {
3553                         rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3554                         ref = rinfo->typenum;
3555                 }
3556                 pb = GTK_STOCK_CANCEL;
3557                 if (G_NODE_IS_LEAF(p)) {
3558                         if (info->flags & PDU_NAMEDNUM)
3559                                 pb = GTK_STOCK_BOLD;
3560                         else {
3561                                 pb = GTK_STOCK_YES;
3562                                 if (namelist)
3563                                         fprintf(namelist, "%16s %s\n",
3564                                                 &(TBLTYPE(info->type)[4]), info->fullname);
3565                         }
3566                 } else {
3567                         switch (info->type) {
3568                         case TBL_ENUMERATED:
3569                         case TBL_BITSTRING:
3570                                 pb = GTK_STOCK_ADD;
3571                                 if (namelist)
3572                                         fprintf(namelist, "%16s %s\n",
3573                                                 &(TBLTYPE(info->type)[4]), info->fullname);
3574                                 break;
3575                         default:
3576                                 break;
3577                         }
3578                 }
3579
3580                 gtk_tree_store_set (store, &iter2,
3581                                     TITLE_COLUMN, text,
3582                                     DEF_COLUMN, def,
3583                                     REF_COLUMN, ref,
3584                                     VALUE_COLUMN, pb,
3585                                     NAME_COLUMN, info->fullname,
3586                                     -1);
3587
3588                 build_tree_view(store, g_node_first_child(p), &iter2);
3589
3590                 p = g_node_next_sibling(p);
3591         }
3592
3593         return;
3594 }
3595
3596
3597 struct DefFind {
3598         gint def;
3599         GtkTreePath *path;
3600 };
3601
3602 #define PATHSTACKMAX 10
3603 static GtkTreePath *pathstack[PATHSTACKMAX];
3604 static gint pathstackp = 0;
3605
3606 static void add_path(GtkTreePath *p)
3607 {
3608         if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
3609                 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
3610                 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
3611                 pathstackp--;
3612         }
3613         pathstack[pathstackp++] = p;
3614 }
3615
3616 static GtkTreePath *pop_path(void)
3617 {
3618         if (pathstackp > 0)
3619                 return pathstack[--pathstackp];
3620         return 0;
3621 }
3622
3623 static gboolean
3624 find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
3625 {
3626         gint def;
3627
3628         struct DefFind *df = (struct DefFind *)data;
3629
3630         gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
3631
3632         if (def == df->def) {
3633                 df->path = gtk_tree_path_copy (path);
3634                 return TRUE;
3635         }
3636         return FALSE;
3637
3638 }
3639
3640 static void
3641 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
3642 {
3643         GtkTreeIter iter;
3644         GtkTreePath *path, *path2;
3645         gchar *text, *oldpath, *newpath;
3646         gint def, ref;
3647         struct DefFind df;
3648
3649         (void) arg2;
3650
3651         path = gtk_tree_path_copy (spath);
3652
3653         gtk_tree_model_get_iter (model, &iter, path);
3654         gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
3655
3656         oldpath = gtk_tree_path_to_string(path);
3657         path2 = gtk_tree_path_copy (path);
3658
3659         add_path(gtk_tree_path_copy(path));
3660
3661         if (ref != -1) {        /* this is a reference, find matching definition */
3662                 df.def = ref;
3663                 df.path = 0;
3664                 gtk_tree_model_foreach (model, find_definition, &df);
3665                 if (df.path) {
3666                         gtk_tree_path_free(path);
3667                         path = df.path;
3668                 }
3669         } else {                /* just move to the next entry, if it exists */
3670                 gtk_tree_path_next(path2);
3671
3672                 if (gtk_tree_model_get_iter (model, &iter, path2)) {
3673                         gtk_tree_path_free(path);
3674                         path = path2;   /* OK */
3675                 } else {
3676                         if (gtk_tree_path_get_depth (path) > 1)
3677                                 gtk_tree_path_up (path);
3678                 }
3679         }
3680
3681         if (path != path2)
3682                 gtk_tree_path_free (path2);
3683
3684         gtk_tree_view_expand_to_path (treeview, path);
3685         gtk_tree_view_expand_row (treeview, path, FALSE);
3686
3687         gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3688
3689         gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3690
3691         newpath = gtk_tree_path_to_string(path);
3692
3693         if (asn1_debug)
3694                 g_message("my_signal_handler: treeview=%p, moveing from %s to %s",
3695                           treeview, oldpath, newpath);
3696
3697         g_free(text);
3698         g_free(oldpath);
3699         g_free(newpath);
3700         /* if (df.path) */
3701         /*      gtk_tree_path_free(df.path); */
3702 }
3703
3704
3705 static void
3706 menuitem_cb (gpointer             callback_data,
3707              guint                callback_action,
3708              GtkWidget           *widget)
3709 {
3710   GtkWidget *dialog;
3711   GtkTreeModel *model;
3712   GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
3713   GtkTreeSelection *selection;
3714   GtkTreeIter iter;
3715   gchar *text, *name;
3716   gint def, ref;
3717   GtkTreePath *path;
3718   gchar *oldpath, *newpath;
3719   GtkTreeViewColumn *focus_column;
3720
3721   selection = gtk_tree_view_get_selection(treeview);
3722
3723   model = gtk_tree_view_get_model(treeview);
3724   gtk_tree_view_get_cursor (treeview, &path, &focus_column);
3725
3726   if (gtk_tree_model_get_iter (model, &iter, path)) {
3727
3728           gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
3729                               NAME_COLUMN, &name, -1);
3730           oldpath = gtk_tree_path_to_string(path);
3731           newpath = empty;
3732
3733           switch (callback_action) {
3734           case 0:               /* Select */
3735                   gtk_tree_selection_select_path (selection, path);
3736                   break;
3737           case 1:               /* back */
3738                   path = pop_path();
3739                   if (path) {
3740                           gtk_tree_view_expand_to_path (treeview, path);
3741                           gtk_tree_view_expand_row (treeview, path, FALSE);
3742
3743                           gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3744
3745                           gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3746
3747                           newpath = gtk_tree_path_to_string(path);
3748
3749                           gtk_tree_path_free(path);
3750                   } else
3751                           newpath = g_strdup("** no path **");
3752                   if (asn1_debug)
3753                           g_message("menueitem_cb: treeview=%p, moveing from %s to %s",
3754                                     treeview, oldpath, newpath);
3755                   break;
3756
3757           case 2:               /* Find */
3758                   /* get all non anonymous names to the root */
3759
3760           default:
3761                   dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
3762                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
3763                                                    GTK_MESSAGE_INFO,
3764                                                    GTK_BUTTONS_CLOSE,
3765                                 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
3766                                                    gtk_item_factory_path_from_widget (widget),
3767                                                    callback_action, text, oldpath, newpath, name);
3768
3769                   /* Close dialog on user response */
3770                   g_signal_connect (dialog,
3771                                     "response",
3772                                     G_CALLBACK (gtk_widget_destroy),
3773                                     NULL);
3774
3775                   gtk_widget_show (dialog);
3776                   break;
3777           }
3778           g_free(text);
3779           g_free(name);
3780           if (newpath != empty)
3781                   g_free(newpath);
3782           g_free(oldpath);
3783   } else
3784           g_message("menuitem_cb: no iterator...");
3785 }
3786
3787 static GtkItemFactoryEntry menu_items[] = {
3788   { "/Select",  NULL,         menuitem_cb, 0, NULL, 0 },
3789   { "/Back",    "<control>B", menuitem_cb, 1, NULL, 0 },
3790   { "/Find",    "<control>F", menuitem_cb, 2, NULL, 0 },
3791   { "/Save",    "<control>S", menuitem_cb, 3, NULL, 0 },
3792 };
3793
3794 static gint button_press_callback( GtkWidget      *widget,
3795                                    GdkEventButton *event,
3796                                    gpointer        data )
3797 {
3798         GtkTreeView *treeview = GTK_TREE_VIEW(widget);
3799
3800         /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
3801          *   " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
3802          *                 event->y_root );
3803          */
3804         if (event->button == 3) {
3805                 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
3806                                              event->x_root,
3807                                              event->y_root,
3808                                              event->button,
3809                                              event->time);
3810                 return TRUE;
3811         }
3812         return FALSE;           /* continue handling this event */
3813 }
3814
3815
3816 static void
3817 create_message_window(void)
3818 {
3819         GtkCellRenderer *renderer;
3820         GtkTreeStore *model;
3821         GtkWidget *vbox;
3822         GtkWidget *sw;
3823         GtkWidget *treeview;
3824         gchar *text;
3825         GtkItemFactory *item_factory;
3826         GtkAccelGroup *accel_group;
3827         gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3828
3829     if ( ! window) {
3830
3831         /* create window, etc */
3832         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3833         gtk_window_set_title (GTK_WINDOW (window), current_pduname);
3834         g_signal_connect (window, "destroy",
3835                           G_CALLBACK (gtk_widget_destroyed), &window);
3836
3837         vbox = gtk_vbox_new (FALSE, 8);
3838         gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3839         gtk_container_add (GTK_CONTAINER (window), vbox);
3840
3841         text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
3842
3843         gtk_box_pack_start (GTK_BOX (vbox),
3844                             gtk_label_new (text),
3845                             FALSE, FALSE, 0);
3846         g_free(text);
3847
3848         sw = gtk_scrolled_window_new (NULL, NULL);
3849         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
3850                                              GTK_SHADOW_ETCHED_IN);
3851         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
3852                                         GTK_POLICY_AUTOMATIC,
3853                                         GTK_POLICY_AUTOMATIC);
3854         gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3855
3856         model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3857                                    G_TYPE_STRING, G_TYPE_STRING);
3858
3859         namelist = eth_fopen("namelist.txt", "w");
3860         build_tree_view(model, PDUtree, NULL);
3861         fclose(namelist);
3862         namelist = 0;
3863
3864         /* create tree view */
3865         treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
3866         g_object_unref (model);
3867         gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
3868         gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
3869                                      GTK_SELECTION_MULTIPLE);
3870
3871         renderer = gtk_cell_renderer_text_new ();
3872
3873 #if 0 /* testing pango attributes */
3874 {
3875         PangoAttribute* bg;
3876         PangoAttrList* attr;
3877
3878         attr = pango_attr_list_new();
3879         bg = pango_attr_background_new(50000,55000,50000);
3880         bg->start_index = 0;
3881         bg->end_index = 10000;
3882         pango_attr_list_insert(attr, bg);
3883
3884         g_object_set(renderer, "attributes", attr, NULL);
3885 }
3886 #endif /* testing pango attributes */
3887
3888         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3889                                                      TITLE_COLUMN, "asn1 entities", renderer,
3890                                                      "text", TITLE_COLUMN, NULL );
3891
3892         /* renderer = gtk_cell_renderer_text_new ();
3893          * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3894          *                                           DEF_COLUMN, "type definition", renderer,
3895          *                                           "text", DEF_COLUMN, NULL );
3896          *
3897          * renderer = gtk_cell_renderer_text_new ();
3898          * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3899          *                                           REF_COLUMN, "reference", renderer,
3900          *                                           "text", REF_COLUMN, NULL );
3901          */
3902         renderer = gtk_cell_renderer_pixbuf_new ();
3903         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3904                                                      VALUE_COLUMN, "value", renderer,
3905                                                      "stock_id", VALUE_COLUMN, NULL );
3906
3907         renderer = gtk_cell_renderer_text_new ();
3908         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
3909                                                      NAME_COLUMN, "fieldname", renderer,
3910                                                      "text", NAME_COLUMN, NULL );
3911
3912         gtk_container_add (GTK_CONTAINER (sw), treeview);
3913
3914         /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
3915
3916         /* create menu */
3917
3918         accel_group = gtk_accel_group_new ();
3919
3920         /* This function initializes the item factory.
3921          * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
3922          *          or GTK_TYPE_OPTION_MENU.
3923          * Param 2: The path of the menu.
3924          * Param 3: A pointer to a gtk_accel_group.  The item factory sets up
3925          *          the accelerator table while generating menus.
3926          */
3927
3928         item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
3929
3930         /* This function generates the menu items. Pass the item factory,
3931            the number of items in the array, the array itself, and any
3932            callback data for the the menu items. */
3933         gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
3934
3935         /* Attach the new accelerator group to the window. */
3936         gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
3937
3938
3939         /* expand all rows after the treeview widget has been realized */
3940         g_signal_connect (treeview, "realize",
3941                           G_CALLBACK (gtk_tree_view_expand_all), NULL);
3942         g_signal_connect (treeview, "row-activated",
3943                           G_CALLBACK (my_signal_handler), (gpointer)model);
3944
3945         g_signal_connect (treeview, "button_press_event",
3946                           G_CALLBACK (button_press_callback), item_factory);
3947
3948         /* g_signal_connect_swapped (treeview, "event",
3949          *                               G_CALLBACK (button_press_handler),
3950          *                              menu);
3951          */
3952         gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
3953     }
3954
3955     if (!GTK_WIDGET_VISIBLE (window))
3956             gtk_widget_show_all (window);
3957     else
3958             {
3959                     gtk_widget_destroy (window);
3960                     window = NULL;
3961             }
3962 }
3963 #endif /* SHOWPDU */
3964
3965 /************************************************************************************************
3966  *    routines to find names to go with the decoded data stream                                 *
3967  ************************************************************************************************/
3968 #define PDUSTATE_STACK_SIZE 1024
3969 typedef struct _statestack statestack;
3970 static struct _statestack {
3971         GNode *node;
3972         guint type;
3973         guint offset;
3974         const char *name;
3975 } PDUstate[PDUSTATE_STACK_SIZE];
3976 static gint PDUstatec = 0;
3977
3978 /* XXX - Shouldn't we do bounds checking here? */
3979 #define PUSHNODE(x)   { PDUstate[PDUstatec++] = (x); }
3980 #define POPSTATE      PDUstate[--PDUstatec]
3981
3982 static const char *
3983 getname(GNode *node) {
3984         if (node == NULL || node->data == NULL)
3985                 THROW(ReportedBoundsError);
3986
3987         return ((PDUinfo *)node->data)->name;
3988 }
3989
3990 static guint
3991 gettype(GNode *node) {
3992         if (node == NULL || node->data == NULL)
3993                 THROW(ReportedBoundsError);
3994
3995         return ((PDUinfo *)node->data)->type & TBL_TYPEmask;
3996 }
3997
3998 static gpointer
3999 getinfo(GNode *node) {
4000         if (node == NULL)
4001                 THROW(ReportedBoundsError);
4002
4003         return node->data;
4004 }
4005
4006 #define NEXT          {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
4007 #define CHILD         {pos.node = g_node_first_child(pos.node);pos.type=0;}
4008 #define MATCH         ((class == info->tclass) && (tag == info->tag))
4009 #define ISOPTIONAL    (info && (info->flags & PDU_OPTIONAL))
4010 #define ISIMPLICIT    (info && (info->flags & PDU_IMPLICIT))
4011 #define ISREFERENCE   (info && (info->flags & PDU_REFERENCE))
4012 #define ISCHOICE      (info && (info->flags & PDU_CHOICE))
4013 #define ISANONYMOUS   (info && (info->flags & PDU_ANONYMOUS))
4014
4015 #undef CHECKP
4016 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
4017                                 pos.node=NULL;PUSHNODE(pos);return ret;}}
4018
4019
4020 static void
4021 showstack(statestack *pos, char *txt, int n)
4022 {
4023         char buf[1024];
4024         const char *name, *type, *stype;
4025         const char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
4026         int i, j;
4027         GNode *g;
4028         statestack *p;
4029         guint typef;
4030
4031         if ( ! asn1_verbose)
4032                 return;
4033
4034         if (n>PDUstatec)
4035                 n = PDUstatec;
4036         if (n<0) {
4037                 g_message("==underflow");
4038                 return;
4039         }
4040         rep = chs = done = ref = pop = chr = rch = sch = con = empty;
4041
4042         g = pos->node;
4043         if (g) {
4044                 name = ((PDUinfo *)g->data)->name;
4045                 type = TBLTYPE(((PDUinfo *)g->data)->type);
4046         } else {
4047                 name = "node<null>";
4048                 type = "?";
4049         }
4050         typef = pos->type;
4051         stype = TBLTYPE(typef);
4052         if (typef & TBL_REPEAT)         rep  = "[repeat]";
4053         if (typef & TBL_CHOICE_made)    chs  = "[choice]";
4054         if (typef & TBL_SEQUENCE_done)  done = "[done]";
4055         if (typef & TBL_REFERENCE)      ref  = "[ref]";
4056         if (typef & TBL_REFERENCE_pop)  pop  = "[ref-pop]";
4057         if (typef & TBL_CHOICE_repeat)  chr  = "[chs-rep]";
4058         if (typef & TBL_REPEAT_choice)  rch  = "[rep-chs]";
4059         if (typef & TBL_SEQUENCE_choice)sch  = "[seq-chs]";
4060         if (typef & TBL_CONSTRUCTED)    con  = "[constr]";
4061
4062         i = sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
4063                     pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4064                     pos->name, pos->offset);
4065
4066         for(j=1, n--; n>0; j++, n--) {
4067                 p = &PDUstate[PDUstatec-j];
4068                 typef = p->type;
4069                 stype = TBLTYPE(typef);
4070                 rep  = (typef & TBL_REPEAT)         ? "[repeat]"  : empty;
4071                 chs  = (typef & TBL_CHOICE_made)    ? "[choice]"  : empty;
4072                 done = (typef & TBL_SEQUENCE_done)  ? "[done]"    : empty;
4073                 ref  = (typef & TBL_REFERENCE)      ? "[ref]"     : empty;
4074                 pop  = (typef & TBL_REFERENCE_pop)  ? "[ref-pop]" : empty;
4075                 chr  = (typef & TBL_CHOICE_repeat)  ? "[chs-rep]" : empty;
4076                 rch  = (typef & TBL_REPEAT_choice)  ? "[rep-chs]" : empty;
4077                 sch  = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
4078                 con  = (typef & TBL_CONSTRUCTED)    ? "[constr]"  : empty;
4079
4080                 i += sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
4081                         p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4082                         p->name, p->offset);
4083         }
4084         g_message(buf);
4085 }
4086
4087 static void
4088 showrefNode(GNode *node, int n)
4089 {
4090         const char *name = empty, *type = empty, *tname = empty;
4091         int cls = 0, tag = 0;
4092         PDUinfo *info;
4093         GNode *ref = 0;
4094
4095         if (n > 10) {
4096                 g_message("%*sstop, nesting too deep", 2*n, empty);
4097                 return;
4098         }
4099         if (node->data) {
4100                 info = (PDUinfo *)(node->data);
4101                 type = TBLTYPE(info->type);
4102                 name = info->name;
4103                 tname = info->typename;
4104                 ref  = info->reference;
4105                 cls = info->tclass;
4106                 tag = info->tag;
4107         }
4108         g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4109                  2*n, empty, tname, type, name, node, node->data,
4110                   ref, tag_class[cls], tag);
4111
4112         if (ref)
4113                 showrefNode(ref, n+1);
4114 }
4115
4116 static void
4117 showNode(GNode *node, int n, int m)
4118 {
4119         const char *name = empty, *type = empty;
4120         GNode *ref = 0;
4121
4122         if (n > m)
4123                 return;
4124
4125         if (node->data) {
4126                 type = TBLTYPE(((PDUinfo *)(node->data))->type);
4127                 name = ((PDUinfo *)(node->data))->name;
4128                 ref  = ((PDUinfo *)(node->data))->reference;
4129         }
4130         g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4131                  2*n, empty, type, name, node, node->data, node->next, node->prev,
4132                                                         node->parent, node->children);
4133
4134         if (m > 10) {
4135                 g_message("%*sstop, nesting too deep", 2*n, empty);
4136                 return;
4137         }
4138
4139         if (ref) showrefNode(ref, n+2);
4140
4141         if (node->children) showNode(node->children, n+1, m);
4142         if (node->next) showNode(node->next, n, m);
4143 }
4144
4145 static void
4146 PDUreset(int count, int count2)
4147 {
4148         statestack pos;
4149
4150         if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
4151
4152         PDUstatec = 0; /* stackpointer */
4153         PDUerrcount = 0; /* error counter per asn.1 message */
4154
4155         pos.node = NULL; /* sentinel */
4156         pos.name = "sentinel";
4157         pos.type = TBL_SEQUENCEOF;
4158         pos.offset = 0;
4159         PUSHNODE(pos);
4160
4161         if (PDUtree) {
4162                 pos.node = PDUtree; /* root of the tree */
4163                 pos.name = getname(pos.node);
4164                 pos.type = gettype(pos.node) | TBL_REPEAT;
4165                 pos.offset = 0;
4166                 PUSHNODE(pos);
4167         }
4168 }
4169
4170 static GNode *                  /* find GNode for a choice element, 0 if none */
4171 makechoice(GNode *p, guint class, guint tag)
4172 {
4173         GNode *q;
4174         PDUinfo *info;
4175
4176         p = g_node_first_child(p); /* the list of choices */
4177         info = 0;               /* avoid gcc warning */
4178
4179         while (p) {
4180                 info = ((PDUinfo *)p->data);
4181
4182                 if (info->type == TBL_CHOICE) {
4183                         if (asn1_verbose)
4184                                 g_message("    using sub choice (%s)%s", info->typename, info->name);
4185
4186                         q = makechoice(p, class, tag);
4187                         if (q) { /* found it */
4188                                 p = q;
4189                                 info = ((PDUinfo *)p->data);
4190                                 break;
4191                         } /* continue with this level */
4192
4193                 } else {
4194                         if (asn1_verbose)
4195                                 g_message("    have %c%d, found %c%d, %s", tag_class[class], tag,
4196                                             tag_class[info->tclass], info->tag, info->name);
4197
4198                         if ((class == info->tclass) && (tag == info->tag))
4199                                 break;  /* found it */
4200                 }
4201
4202                 p = g_node_next_sibling(p);
4203         }
4204         if (asn1_verbose) {
4205                 if (p) g_message("    OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
4206                                  info->name);
4207                 else   g_message("    ...no matching choice...");
4208         }
4209         return p;
4210 }
4211
4212                 /* offset is for debugging only, a reference to output on screen */
4213 static PDUprops *
4214 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
4215 {
4216         statestack pos, pos2, save_pos;
4217         PDUinfo *info;
4218         const char *ret, *tmp;
4219         int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4220         static char namestr[64]; /* enough ? */
4221         static char posstr[40];
4222         static char noname[] = "*noname*";
4223         static PDUprops constructed_save; /* for unexpectedly constructed enteties */
4224
4225         if (PDUstatec > 0)      /* don't read from below the stack */
4226                 pos = POPSTATE;
4227         /* pos refers to the last asn1 node handled */
4228
4229         /* a very simple, too simple??, way to handle constructed entities */
4230         if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4231                         /* unexpectedly constructed, return same info as last time */
4232                 sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4233                 showstack(&pos, posstr, 3);
4234                 pos.offset = offset;
4235                 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4236                 PUSHNODE(pos);  /* push extra, to match with a EOI operation */
4237                 PUSHNODE(pos);  /* restore the stack */
4238                 *out = constructed_save;
4239                 if (asn1_verbose)
4240                         g_message("  return for constructed %s (%s)%s",
4241                                   TBLTYPE(out->type), out->typename, out->name);
4242                 return out;
4243         }
4244
4245         save_pos = pos; /* may need it again */
4246
4247         out->type = 0;
4248         out->name = 0;
4249         out->typename = "*error*";
4250         out->fullname = 0;
4251         out->flags = 0;
4252         out->data = 0;
4253         out->value_id = -1;
4254         out->type_id = -1;
4255
4256         if (PDUstatec <= 0) {
4257                 if (PDUstatec > -10) {
4258                         if (asn1_verbose)
4259                                 g_message(">>off=%d stack underflow, return", offset);
4260                 }
4261                 if (PDUstatec == -10) {
4262                         if (asn1_verbose)
4263                                 g_message(">>off=%d stack underflow, return, no more messages", offset);
4264                 }
4265                 out->name = "*underflow*";
4266                 out->flags |= OUT_FLAG_noname;
4267                 PDUerrcount++;
4268                 return out;
4269         }
4270         sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4271
4272         showstack(&pos, posstr, 3);
4273
4274         ret = noname;
4275
4276         if (class == ASN1_EOI) { /* end of this input sequence */
4277
4278                 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4279                         if (asn1_verbose) g_message("    EOI: reference pop");
4280                         pos = POPSTATE;
4281                 } else
4282                 switch(pos.type & TBL_TYPEmask) {
4283                 case TBL_TYPEREF:
4284                         if (asn1_verbose) g_message("    EOI: pop typeref");
4285                         pos = POPSTATE; /* remove typeref */
4286                         break;
4287                 case TBL_CHOICE_done:
4288                         if (asn1_verbose) g_message("    EOI: mark choice");
4289                         pos = POPSTATE;
4290                         pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4291                         PUSHNODE(pos);
4292                         break;
4293                 default:
4294                         break;
4295                 }
4296
4297
4298                 pos = POPSTATE; /* this is pushed back on the stack later */
4299                 if (pos.node == NULL) {
4300                         if (asn1_verbose) g_message("  EOI, pos.node == NULL");
4301                         out->name = "*no-name-EOI*";
4302                         out->flags |= OUT_FLAG_noname;
4303                         PDUerrcount++;
4304                         return out;
4305                 }
4306
4307                 info = getinfo(pos.node);
4308                 ret = info->name;
4309                 tmp = TBLTYPE(info->type);
4310                 if (offset != pos.offset) {
4311                         if (asn1_verbose)
4312                                 g_message("  *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4313                                           tmp, ret, offset, pos.offset);
4314                         while ((offset < pos.offset) && (PDUstatec > 0)) {
4315                                 pos = POPSTATE;
4316                                 if (asn1_verbose)
4317                                         g_message("  EOI extra pop, EOIoffset=%d, stack=%d",
4318                                                   offset, pos.offset);
4319                         }
4320                         if (offset != pos.offset)
4321                                 PDUerrcount++; /* only count if still unequal */
4322                 } else {
4323                         if (asn1_verbose) g_message("  EOI %s:%s OK, offset=%d", tmp, ret, offset);
4324                 }
4325         } else {
4326                 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4327                  * indicated by the synthetic EOI call. */
4328                 if ((class == ASN1_UNI) && (tag == ASN1_EOC)) { /* explicit EOC never has a name */
4329                         PUSHNODE(pos); /* restore stack */
4330                         ret = "explicit-EOC";
4331                         if (asn1_verbose) g_message("  return '%s', ignore", ret);
4332                         out->name = ret;
4333                         out->typename = "ASN1";
4334                         return out;
4335                 }
4336
4337                 /* find appropriate node for this tag */
4338
4339                 if (pos.node == NULL) {
4340                         if (asn1_verbose) g_message("  pos.node == NULL");
4341                         out->name = "*no-name*";
4342                         out->flags |= OUT_FLAG_noname;
4343                         PDUerrcount++;
4344                         return out;
4345                 }
4346
4347                 /* showNode(pos.node, 3, 4); */
4348
4349                 switch (pos.type & TBL_TYPEmask) {
4350                 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4351                 case TBL_SET:
4352                         break;
4353                 default:
4354                         if (pos.type & TBL_CHOICE_made) {
4355                                 if (asn1_verbose) g_message("    finish choice");
4356                                 donext = 1;
4357                         }
4358                         break;
4359                 }
4360
4361                 info = getinfo(pos.node);
4362
4363                 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4364                         switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4365                         case TBL_CHOICE:
4366                                 if (asn1_verbose) g_message("    repeating choice"); /* ignore repeat */
4367                                 break;
4368                         default:
4369                                 if (asn1_verbose) g_message("    seqof: repeat start");
4370                                 /* decide how to continue, CHILD for next instance of sequence
4371                                  * or NEXT for end of repeated sequence.
4372                                  * use the tag to make a descision */
4373                                 if (asn1_verbose) g_message("    seqof: first got %c%d, found %c%d",
4374                                                         tag_class[class], tag,
4375                                                         tag_class[info->tclass], info->tag);
4376                                 if ( MATCH ) {
4377                                         /* This is the start of repeating */
4378                                         PUSHNODE(pos);
4379                                         ret = getname(pos.node);
4380                                         if (asn1_verbose) g_message("  return for repeat '%s'", ret);
4381                                         out->type = (pos.type & TBL_TYPEmask);
4382                                         out->typename = info->typename;
4383                                         out->name = ret;
4384                                         out->value_id = info->value_id;
4385                                         out->type_id = info->type_id;
4386                                         if (ISANONYMOUS) {
4387                                                 if (asn1_verbose) g_message("    anonymous: dontshow");
4388                                                 if (asn1_debug)
4389                                                         out->flags |= OUT_FLAG_dontshow;
4390                                                 else
4391                                                         out->name = empty;
4392                                         }
4393                                         return out;
4394                                 } else {
4395                                         /* find out where to go .... */
4396                                         pos2 = pos;
4397                                         CHILD;  /* assume sequence is repeated */
4398                                         if (pos.node) {
4399                                                 info = getinfo(pos.node);       /* needed for MATCH to look ahead */
4400                                                 if (asn1_verbose)
4401                                                     g_message("    seqof: child: got %c%d, found %c%d",
4402                                                               tag_class[class], tag,
4403                                                               tag_class[info->tclass], info->tag);
4404                                         }
4405                                         if (pos2.type & TBL_CHOICE_repeat) {
4406                                                 pos = POPSTATE;
4407                                                 if (asn1_verbose)
4408                                                         g_message("    repeating a choice, %s",
4409                                                                   getname(pos.node));
4410                                                 pos.type = TBL_CHOICE_immediate;
4411                                         } else {
4412                                                 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4413                                                         donext = 1;     /* move on */
4414                                                         if (asn1_verbose)
4415                                                           g_message("    seqof: no repeat, force next");
4416                                                 }
4417                                                 /* following code will take the child again */
4418                                                 pos = pos2;
4419                                         }
4420                                 }
4421                                 break;
4422                         }
4423                 } else  if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4424                         if (asn1_verbose) g_message("    reference pop, donext");
4425                         pos = POPSTATE;
4426                         donext = 1;
4427                 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4428                         if (pos.type & TBL_SEQUENCE_choice) {
4429                                 pos = POPSTATE; /* expect to find a repeat here */
4430                         } else {
4431                                 donext = 1;
4432                                 if (asn1_verbose) g_message("    sequence done, donext");
4433                         }
4434                 }
4435
4436                 if (pos.type & TBL_REFERENCE) {
4437                         if (asn1_verbose) g_message("    reference change ref -> pop");
4438                         pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4439                 }
4440
4441                 pos.offset = offset;
4442
4443                 ret = pos.name; /* for the debug messages */
4444
4445                 if (donext) {
4446                         if (asn1_verbose) g_message("    donext");
4447                         NEXT;
4448                 } else {
4449                         switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4450                         case TBL_SETOF:         /* ?? */
4451                         case TBL_SEQUENCEOF:
4452                                 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4453                                         pos.type |= TBL_REPEAT;
4454                                         PUSHNODE(pos);
4455                                         CHILD;
4456                                         pushed++;
4457                                                 /* remember this is the start of a repeat cycle */
4458                                         typeflags |= TBL_REPEAT;
4459                                         if (asn1_verbose)
4460                                                 g_message("    seqof: set repeat mark [push,child]");
4461                                 } else {
4462                                         if (asn1_verbose)
4463                                                 g_message("    seqof: end of reapeat loop [next]");
4464                                         NEXT;
4465                                 }
4466                                 break;
4467                         case TBL_SET:           /* ?? */
4468                         case TBL_SEQUENCE:
4469                                 pos.type |= TBL_SEQUENCE_done;
4470                                 PUSHNODE(pos);
4471                                 CHILD;
4472                                 pushed++;
4473                                 if (asn1_verbose) g_message("    seq [push,child]");
4474                                 break;
4475                         case TBL_CHOICE:
4476                                                 /* no more choice */
4477                                 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4478                                 PUSHNODE(pos);
4479
4480                                 pos.type = 0; /* clear all type flags */
4481                                 if (asn1_verbose)
4482                                         g_message("    choice [push], %c%d, %s",
4483                                                   tag_class[info->tclass], info->tag, getname(pos.node));
4484                                 pos.node = makechoice(pos.node, class, tag);
4485                                 if (pos.node == NULL) {
4486                                         pos = POPSTATE;
4487                                         out->flags |= OUT_FLAG_noname;
4488                                         PDUerrcount++;
4489                                 }
4490                                 info = getinfo(pos.node);
4491
4492                                 ret = getname(pos.node);
4493                                 if (asn1_verbose)
4494                                         g_message("    '%s' %c%d will be used",
4495                                                   ret, tag_class[info->tclass], info->tag);
4496                                 break;
4497                         case TBL_CHOICE_done:
4498                                 NEXT;
4499                                 break;
4500                         case TBL_TYPEREF:
4501                                 pos = POPSTATE;
4502                                 NEXT;
4503                                 if (asn1_verbose) g_message("    typeref [pop,next]");
4504                                 break;
4505                         case TBL_ENUMERATED:
4506                         case TBL_BITSTRING:
4507                                 /* skip named numbers now, call to PDUenum() will retrieve a name */
4508                                 NEXT;
4509                                 break;
4510                         case TBL_CHOICE_immediate:
4511                                 if (asn1_verbose) g_message("    immediate choice [no next]");
4512                                 /* nothing */
4513                                 break;
4514                         default:
4515                                 NEXT;
4516                                 break;
4517                         }
4518                 }
4519
4520                 if (pos.node == NULL) {
4521                         ret = "*no-name-2*";
4522                         if (asn1_verbose) g_message("  return '%s'", ret);
4523                         out->name = ret;
4524                         out->flags |= OUT_FLAG_noname;
4525                         PDUerrcount++;
4526                         return out;
4527                 }
4528                 ret = pos.name = getname(pos.node);
4529                 pos.type = gettype(pos.node) | (pos.type & ~TBL_TYPEmask);
4530                 info = getinfo(pos.node);
4531
4532                 /* pos now points to the prospective current node, go check it ********************/
4533                 if (asn1_verbose) g_message("  candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4534                                 (ISOPTIONAL)?", optional":empty,
4535                                 (ISIMPLICIT)?", implicit":empty,
4536                                 tag_class[info->tclass], info->tag );
4537
4538                 if (ISOPTIONAL) { /* must check the tag */
4539                         while(! MATCH) {   /* check optional here again...? */
4540                                 if (asn1_verbose)
4541                                         g_message("    got %c%d, found %c%d", tag_class[class], tag,
4542                                                         tag_class[info->tclass], info->tag);
4543                                 NEXT;
4544                                 if (pos.node == NULL) {
4545                                         ret = "------";
4546                                         if (cons) {
4547                                                 pos = save_pos; /* reset for next time */
4548                                                 pos.type |= TBL_SEQUENCE_done;
4549                                                 PUSHNODE(pos);
4550                                                 pos.type &= ~TBL_SEQUENCE_done;
4551                                                 cons_handled = 1;
4552                                                 out->flags |= OUT_FLAG_dontshow;
4553                                                 if (asn1_verbose)
4554                         g_message("    end of optional list, constructed, expect value next time");
4555                                         } else {
4556                                                 PDUerrcount++;
4557                                                 out->flags |= OUT_FLAG_noname;
4558                                                 if (asn1_verbose)
4559                                                         g_message("    *end of optional list...");
4560                                                 info = 0; /* this is not valid any more... */
4561                                         }
4562                                         break;  /* end of list */
4563                                 }
4564                                 info = getinfo(pos.node);
4565                                 if (asn1_verbose) g_message("  optional, %s", getname(pos.node));
4566                         }
4567                         if (pos.node && ! cons_handled) {
4568                                 ret = pos.name = getname(pos.node);
4569                                 pos.type = gettype(pos.node);
4570                         }
4571                         /* pos now refers to node with name we want, optional nodes skipped */
4572                 }
4573
4574                 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4575                         pos2 = pos; /* save current state */
4576                         if ( ! MATCH) {
4577                                 if (! pushed) {
4578                                         if (asn1_verbose)
4579                                                 g_message("    already pushed, skip next push");
4580                                         PUSHNODE(pos);
4581                                         typeflags &= ~TBL_CHOICE_made;
4582                                 }
4583
4584                                 if (asn1_verbose && info)
4585                                         g_message("    immediate choice [push], %c%d, %s",
4586                                                   tag_class[info->tclass], info->tag, getname(pos.node));
4587                                 if (pos.node) {
4588                                         pos.node = makechoice(pos.node, class, tag);
4589                                 }
4590                                 if (pos.node == NULL) {
4591                                         pos = POPSTATE;
4592                                         PDUerrcount++;
4593                                 }
4594                                 info = getinfo(pos.node);
4595                                 pos.type = gettype(pos.node);
4596                                 out->type = (pos.type & TBL_TYPEmask);
4597                                 out->flags |= OUT_FLAG_type;
4598
4599                                 sprintf(namestr, "%s!%s", ret, getname(pos.node));
4600                                 ret = namestr;
4601                                 if (asn1_verbose)
4602                                         g_message("    %s:%s will be used", TBLTYPE(pos.type), ret);
4603                                 if (typeflags & TBL_REPEAT) {
4604                                         pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
4605                                         PUSHNODE(pos2);
4606                                         pos.type |= TBL_SEQUENCE_choice;
4607                                         PUSHNODE(pos);
4608                                         if (asn1_verbose)
4609                                                 g_message("  return from immediate choice [%s] '%s'",
4610                                                                 TBLTYPE(pos.type), ret);
4611
4612                                         out->data = pos.node; /* for access to named numbers... */
4613
4614                                         out->type = (pos.type & TBL_TYPEmask);
4615                                         out->name = ret;
4616                                         if (info) {
4617                                                 out->typename = info->typename;
4618                                                 out->fullname = info->fullname;
4619                                                 out->value_id = info->value_id;
4620                                                 out->type_id = info->type_id;
4621                                         }
4622
4623                                         return out;
4624                                 } else {
4625                                         typeflags |= TBL_CHOICE_made;
4626                                 }
4627                         } else {
4628                                 if (asn1_verbose) g_message("    matching choice '%s'", ret);
4629                         }
4630                         if ( ! cons ) { /* ISIMPLICIT was not OK for all */
4631                                 pos = pos2; /* reset for continuation */
4632                         }
4633                 }
4634                 if (asn1_verbose) {
4635                         if (info)
4636                                 g_message("  using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4637                                           (ISOPTIONAL)?", optional":empty,
4638                                           (ISIMPLICIT)?", implicit":empty,
4639                                           tag_class[info->tclass], info->tag );
4640                         else
4641                                 g_message("  using: unknown '%s'", ret);
4642                 }
4643
4644                 /* must follow references now */
4645                 if (pos.type == TBL_TYPEREF && info) {
4646                         out->typename = info->typename;
4647                         out->type_id = info->typenum;
4648                         out->flags |= OUT_FLAG_typename;
4649                         pos2 = pos;
4650                         PUSHNODE(pos);  /* remember where we were */
4651                         if (asn1_verbose) g_message("   typeref [push]");
4652                         typeflags |= TBL_REFERENCE;
4653                         if (info->reference == 0) { /* resolved ref to universal type.... */
4654                                 /* showNode(pos.node, 3, 4); */
4655                                 pos.type = gettype(pos.node); /* the resulting type */
4656                                 info = getinfo(pos.node);
4657                                 tmp = "inknown tag";
4658                                 if ((info->tclass == ASN1_UNI) && (info->tag < 31)) {
4659                                         tmp = asn1_tag[info->tag];
4660                                         pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
4661                                 }
4662                                 if (asn1_verbose && info)
4663                                         g_message("  indirect typeref to %s:%s, %s [%c%d]",
4664                                                   TBLTYPE(pos.type), info->typename, tmp,
4665                                                   tag_class[info->tclass], info->tag );
4666                         } else {
4667                                 out->fullname = info->fullname;
4668                                 donext = (ISANONYMOUS); /* refereing entity has no name ? */
4669                                 pos.node = info->reference;
4670                                 pos.type = gettype(pos.node);
4671                                 info = getinfo(pos.node);
4672                                 if (asn1_verbose)
4673                                         g_message("  typeref %s %s", TBLTYPE(pos.type), getname(pos.node));
4674                         /* keep name from before going through the reference, unless anonymous */
4675                                 if (donext) /* refering entity has no name */
4676                                         ret = getname(pos.node); /* a better name */
4677
4678                                 /* handle choice here ? !!mm!! */
4679
4680                                 out->type = (pos.type & TBL_TYPEmask);
4681                                 out->flags |= OUT_FLAG_type;
4682                                 /* showNode(pos.node, 3, 4); */
4683                                 /* ret = getname(pos.node);*/
4684
4685                                 out->data = pos.node;
4686                                 out->flags |= OUT_FLAG_data;
4687                                 if (asn1_verbose)
4688                                         g_message("  typeref set named number list node %p", pos.node);
4689
4690                                 if ( ! cons) {
4691                                         pos = POPSTATE;
4692                                         pos.type = TBL_TYPEREF_nopop;
4693                                         if (asn1_verbose) g_message("    typeref pop");
4694                                 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
4695                                                 /* do not enter the named-number list */
4696                                         pos = POPSTATE;
4697                                         pos.type = TBL_TYPEREF_nopop;
4698                                         if (asn1_verbose) g_message("    typeref [pop]");
4699                                 } else {
4700                                         typeflags |= TBL_REFERENCE;
4701                                 }
4702                         }
4703                 }
4704
4705                 if (cons && ! cons_handled) {   /* This entity is constructed, expected ? */
4706                         switch(pos.type) {
4707                         case TBL_BOOLEAN: /* these are not expected to be constructed */
4708                         case TBL_INTEGER:
4709                         case TBL_OCTETSTRING:
4710                         case TBL_NULL:
4711                         case TBL_OID:
4712                         case TBL_REAL:
4713                         case TBL_ENUMERATED:
4714                         case TBL_TYPEREF:
4715                                 typeflags |= TBL_CONSTRUCTED;
4716                                         /* this entry has no extra info, next is the same */
4717                                 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
4718                                 if (asn1_verbose) g_message("    dontshow and set constructed flag");
4719                                 break;
4720                         default: /* others, such as sequences, are expected to be constructed */
4721                                 break;
4722                         }
4723                 }
4724         }
4725
4726         if (ISANONYMOUS) {
4727                 if (asn1_verbose) g_message("    anonymous: dontshow");
4728                 if (asn1_debug) /* this entry has no extra info, next is the same */
4729                         out->flags |= OUT_FLAG_dontshow;
4730                 else
4731                         out->name = empty; /* show it, but no name */
4732         }
4733
4734         if (out->name != empty)
4735                 out->name = ret;
4736
4737         if ( ! (out->flags & OUT_FLAG_data))
4738                 out->data = pos.node; /* for access to named numbers... */
4739
4740         pos.type |= typeflags;
4741         PUSHNODE(pos);
4742
4743         if ( ! (out->flags & OUT_FLAG_type))
4744                 out->type = pos.type;
4745
4746         out->type &= TBL_TYPEmask;
4747
4748         if (ret == noname) {
4749                 PDUerrcount++;
4750                 out->flags |= OUT_FLAG_noname;
4751         }
4752
4753         if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
4754                 out->typename = info->typename;
4755                 out->type_id = info->typenum;
4756         }
4757
4758         if (info && (out->value_id == -1)) {
4759                 out->value_id = info->value_id;
4760                 out->type_id = info->type_id;
4761         }
4762
4763         if ((out->fullname == 0) && info)
4764                 out->fullname = info->fullname;
4765
4766         if (typeflags & TBL_CONSTRUCTED)
4767                 constructed_save = *out;
4768
4769         if (asn1_verbose)
4770                 g_message("  return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
4771                                                 out->value_id, out->type_id);
4772
4773         return out;
4774 }
4775
4776 static const char *
4777 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
4778 {
4779         GNode *list;
4780         PDUinfo *info;
4781         const char *ret, *name;
4782         static char unnamed[] = "*unnamed*";
4783
4784         (void) cls; (void) tag;         /* make a reference */
4785
4786         if (props->flags & OUT_FLAG_noname)
4787                 return empty;
4788
4789         ret = unnamed;
4790         list = (GNode *)props->data;
4791
4792         if (list == 0) {
4793                 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
4794                 PDUerrcount++;
4795                 return "*list-still-0*";
4796         }
4797
4798         if ((PDUinfo *)list->data)
4799                 name = ((PDUinfo *)list->data)->name;
4800         else
4801                 name = ret;
4802
4803         for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
4804                 info = (PDUinfo *)list->data;
4805                 if (value == info->tag) {
4806                         ret = info->name;
4807                         break;
4808                 }
4809         }
4810         if (ret == unnamed)
4811                 PDUerrcount++;
4812
4813         if (asn1_verbose)
4814                 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
4815         return ret;
4816 }
4817
4818 #endif /* READSYNTAX */
4819
4820 void
4821 proto_register_asn1(void) {
4822
4823   static const enum_val_t type_recursion_opts[] = {
4824           { "0", "0", 0 },
4825           { "1", "1", 1 },
4826           { "2", "2", 2 },
4827           { "3", "3", 3 },
4828           { "4", "4", 4 },
4829           { "4", "5", 5 },
4830           { "6", "6", 6 },
4831           { "7", "7", 7 },
4832           { "8", "8", 8 },
4833           { "9", "9", 9 },
4834           { NULL, NULL, -1},
4835   };
4836
4837   static gint *ett[1+MAX_NEST+MAXPDU];
4838
4839   char tmpstr[64];
4840
4841   module_t *asn1_module;
4842   int i, j;
4843
4844   asn1_logfile = get_tempfile_path(ASN1LOGFILE);
4845
4846   current_asn1 = g_strdup("");
4847   asn1_filename = g_strdup(current_asn1);
4848
4849   current_pduname = g_strdup("ASN1");
4850   asn1_pduname = g_strdup(current_pduname);
4851
4852   proto_asn1 = proto_register_protocol("ASN.1 decoding",
4853                                        "ASN1", pabbrev);
4854
4855   ett[0] = &ett_asn1;
4856   for (i=0, j=1; i<MAX_NEST; i++, j++) {
4857           ett[j] = &ett_seq[i];
4858           ett_seq[i] = -1;
4859   }
4860   for(i=0; i<MAXPDU; i++, j++) {
4861           ett[j] = &ett_pdu[i];
4862           ett_pdu[i] = -1;
4863   }
4864
4865   proto_register_subtree_array(ett, array_length(ett));
4866
4867   asn1_module = prefs_register_protocol(proto_asn1,
4868                                         proto_reg_handoff_asn1);
4869 #ifdef JUST_ONE_PORT
4870   prefs_register_uint_preference(asn1_module, "tcp_port",
4871                                  "ASN.1 TCP Port",
4872                                  "The TCP port on which "
4873                                  "ASN.1 messages will be read",
4874                                  10, &global_tcp_port_asn1);
4875   prefs_register_uint_preference(asn1_module, "udp_port",
4876                                  "ASN.1 UDP Port",
4877                                  "The UDP port on which "
4878                                  "ASN.1 messages will be read",
4879                                  10, &global_udp_port_asn1);
4880   prefs_register_uint_preference(asn1_module, "sctp_port",
4881                                  "ASN.1 SCTP Port",
4882                                  "The SCTP port on which "
4883                                  "ASN.1 messages will be read",
4884                                  10, &global_sctp_port_asn1);
4885 #else
4886   g_snprintf(tmpstr, sizeof(tmpstr), "%u", TCP_PORT_ASN1);
4887   range_convert_str(&global_tcp_ports_asn1, tmpstr, 65535);
4888
4889   g_snprintf(tmpstr, sizeof(tmpstr), "%u", UDP_PORT_ASN1);
4890   range_convert_str(&global_udp_ports_asn1, tmpstr, 65535);
4891
4892   g_snprintf(tmpstr, sizeof(tmpstr), "%u", SCTP_PORT_ASN1);
4893   range_convert_str(&global_sctp_ports_asn1, tmpstr, 65535);
4894
4895   prefs_register_range_preference(asn1_module, "tcp_ports",
4896                                  "ASN.1 TCP Ports",
4897                                  "The TCP ports on which "
4898                                  "ASN.1 messages will be read",
4899                                  &global_tcp_ports_asn1, 65535);
4900   prefs_register_range_preference(asn1_module, "udp_ports",
4901                                  "ASN.1 UDP Ports",
4902                                  "The UDP ports on which "
4903                                  "ASN.1 messages will be read",
4904                                  &global_udp_ports_asn1, 65535);
4905   prefs_register_range_preference(asn1_module, "sctp_ports",
4906                                  "ASN.1 SCTP Ports",
4907                                  "The SCTP ports on which "
4908                                  "ASN.1 messages will be read",
4909                                  &global_sctp_ports_asn1, 65535);
4910 #endif /* JUST_ONE_PORT */
4911
4912   prefs_register_bool_preference(asn1_module, "desegment_messages",
4913                                  "Desegment TCP",
4914                                  "Desegment ASN.1 messages that span TCP segments",
4915                                  &asn1_desegment);
4916
4917   old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
4918 #ifdef _WIN32
4919   bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
4920 #endif
4921
4922   prefs_register_string_preference(asn1_module, "file",
4923                                    "ASN.1 type table file",
4924                                    "Compiled ASN.1 description of ASN.1 types",
4925                                    &asn1_filename);
4926   prefs_register_string_preference(asn1_module, "pdu_name",
4927                                    "ASN.1 PDU name",
4928                                    "Name of top level PDU",
4929                                    &asn1_pduname);
4930   prefs_register_uint_preference(asn1_module, "first_pdu_offset",
4931                                  "Offset to first PDU in first tcp packet",
4932                                  "Offset for non-reassembled packets, "
4933                                  "wrong if this happens on other than the first packet!",
4934                                  10, &first_pdu_offset);
4935   prefs_register_bool_preference(asn1_module, "flat",
4936                                  "Show full names",
4937                                  "Show full names for all values",
4938                                  &asn1_full);
4939   prefs_register_enum_preference(asn1_module, "type_recursion",
4940                                  "Eliminate references to level",
4941                                  "Allow this recursion level for eliminated type references",
4942                                  &type_recursion_level,
4943                                  type_recursion_opts, FALSE);
4944   prefs_register_bool_preference(asn1_module, "debug",
4945                                  "ASN.1 debug mode",
4946                                  "Extra output useful for debuging",
4947                                  &asn1_debug);
4948 #if 0
4949   prefs_register_bool_preference(asn1_module, "message_win",
4950                                  "Show ASN.1 tree",
4951                                  "show full message description",
4952                                  &asn1_message_win);
4953 #else
4954   prefs_register_obsolete_preference(asn1_module, "message_win");
4955 #endif
4956   prefs_register_bool_preference(asn1_module, "verbose_log",
4957                                  "Write very verbose log",
4958                                  "log to file $TMP/" ASN1LOGFILE,
4959                                  &asn1_verbose);
4960 }
4961
4962 /* The registration hand-off routing */
4963
4964 static dissector_handle_t asn1_handle;
4965
4966 static void
4967 register_tcp_port(guint32 port)
4968 {
4969   dissector_add("tcp.port", port, asn1_handle);
4970 }
4971
4972 static void
4973 unregister_tcp_port(guint32 port)
4974 {
4975   dissector_delete("tcp.port", port, asn1_handle);
4976 }
4977
4978 static void
4979 register_udp_port(guint32 port)
4980 {
4981   dissector_add("udp.port", port, asn1_handle);
4982 }
4983
4984 static void
4985 unregister_udp_port(guint32 port)
4986 {
4987   dissector_delete("udp.port", port, asn1_handle);
4988 }
4989
4990 static void
4991 register_sctp_port(guint32 port)
4992 {
4993   dissector_add("sctp.port", port, asn1_handle);
4994 }
4995
4996 static void
4997 unregister_sctp_port(guint32 port)
4998 {
4999   dissector_delete("sctp.port", port, asn1_handle);
5000 }
5001
5002 void
5003 proto_reg_handoff_asn1(void) {
5004   static int asn1_initialized = FALSE;
5005 #ifndef JUST_ONE_PORT
5006   char *tcp_ports_asn1_string, *udp_ports_asn1_string, *sctp_ports_asn1_string;
5007 #endif
5008
5009   pcount = 0;
5010
5011 #ifdef JUST_ONE_PORT
5012   if (asn1_verbose) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegnment=%d, "
5013                 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5014           global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
5015           asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5016 #else
5017   if (asn1_verbose) {
5018     tcp_ports_asn1_string = range_convert_range(global_tcp_ports_asn1);
5019     udp_ports_asn1_string = range_convert_range(global_udp_ports_asn1);
5020     sctp_ports_asn1_string = range_convert_range(global_sctp_ports_asn1);
5021     g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegnment=%d, "
5022                 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5023           tcp_ports_asn1_string, udp_ports_asn1_string, sctp_ports_asn1_string, asn1_desegment,
5024           asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5025   }
5026 #endif /* JUST_ONE_PORT */
5027
5028   if(!asn1_initialized) {
5029     asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
5030     asn1_initialized = TRUE;
5031   } else {      /* clean up ports and their lists */
5032 #ifdef JUST_ONE_PORT
5033     unregister_tcp_port(tcp_port_asn1);
5034     unregister_udp_port(udp_port_asn1);
5035     unregister_sctp_port(sctp_port_asn1);
5036 #else
5037     if (tcp_ports_asn1 != NULL) {
5038       range_foreach(tcp_ports_asn1, unregister_tcp_port);
5039       g_free(tcp_ports_asn1);
5040     }
5041
5042     if (udp_ports_asn1 != NULL) {
5043       range_foreach(udp_ports_asn1, unregister_udp_port);
5044       g_free(udp_ports_asn1);
5045     }
5046
5047     if (sctp_ports_asn1 != NULL) {
5048       range_foreach(sctp_ports_asn1, unregister_sctp_port);
5049       g_free(sctp_ports_asn1);
5050     }
5051 #endif /* JUST_ONE_PORT */
5052   }
5053
5054   if (strcmp(asn1_filename, current_asn1) != 0) {
5055           /* new definitions, parse the file if we have one */
5056           /* !!! should be postponed until we really need it !!! */
5057 #ifdef READSYNTAX
5058           read_asn1_type_table(asn1_filename);
5059 #endif /* READSYNTAX */
5060           g_free(current_asn1);
5061           current_asn1 = g_strdup(asn1_filename);
5062   }
5063   if (!PDUtree ||       /* no tree built yet for PDU type */
5064       strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
5065           if (build_pdu_tree(asn1_pduname)) {
5066                   g_free(current_pduname);
5067                   current_pduname = g_strdup(asn1_pduname);
5068           }
5069   }
5070 #ifdef SHOWPDU
5071   if (asn1_message_win) {       /* show what we are prepared to recognize */
5072           if (window) {
5073                   gtk_widget_destroy (window);
5074                   window = NULL;
5075           }
5076           create_message_window();
5077   }
5078 #endif /* SHOWPDU */
5079
5080   /* If we now have a PDU tree, register for the port or ports we have */
5081   if (PDUtree) {
5082 #ifdef JUST_ONE_PORT
5083     tcp_port_asn1 = global_tcp_port_asn1;
5084     udp_port_asn1 = global_udp_port_asn1;
5085     sctp_port_asn1 = global_sctp_port_asn1;
5086
5087     register_tcp_port(tcp_port_asn1);
5088     register_udp_port(udp_port_asn1);
5089     register_sctp_port(sctp_port_asn1);
5090 #else
5091     tcp_ports_asn1 = range_copy(global_tcp_ports_asn1);
5092     udp_ports_asn1 = range_copy(global_udp_ports_asn1);
5093     sctp_ports_asn1 = range_copy(global_sctp_ports_asn1);
5094
5095     range_foreach(tcp_ports_asn1, register_tcp_port);
5096     range_foreach(udp_ports_asn1, register_udp_port);
5097     range_foreach(sctp_ports_asn1, register_sctp_port);
5098   }
5099 #endif /* JUST_ONE_PORT */
5100 }