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