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