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