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