tvb_free() can (now) be called from plugins on Windows
[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 /* conversion from snacc type to appropriate wireshark display type */
329 static guint tbl_display_wireshark[] = {
330                        /*  0 */ BASE_DEC,       /* TBL_BOOLEAN */
331                        /*  1 */ BASE_DEC_HEX,   /* TBL_INTEGER */
332                        /*  2 */ BASE_HEX,       /* TBL_BITSTRING */
333                        /*  2 */ BASE_NONE,      /* TBL_OCTETSTRING */
334                        /*  4 */ BASE_NONE,      /* TBL_NULL */
335                        /*  5 */ BASE_DEC,       /* TBL_OID */
336                        /*  6 */ BASE_DEC,       /* TBL_REAL */
337                        /*  7 */ BASE_DEC,       /* TBL_ENUMERATED */
338                        /*  8 */ BASE_NONE,      /* TBL_SEQUENCE */
339                        /*  9 */ BASE_NONE,      /* TBL_SET */
340                        /* 10 */ BASE_NONE,      /* TBL_SEQUENCEOF */
341                        /* 11 */ BASE_NONE,      /* TBL_SETOF */
342                        /* 12 */ BASE_NONE,      /* TBL_CHOICE */
343                        /* 13 */ BASE_NONE,      /* TBL_TYPEREF */
344
345                        /* 14 */ BASE_NONE,      /* TBL_SEQUENCEOF_start */
346                        /* 15 */ BASE_NONE,      /* TBL_TYPEREF_nopop */
347                        /* 16 */ BASE_NONE,      /* TBL_CHOICE_done */
348                        /* 17 */ BASE_NONE,      /* TBL_reserved */
349                        /* 18 */ BASE_NONE,      /* TBL_CHOICE_immediate */
350
351                        /* 19 */ BASE_NONE,      /* TBL_INVALID */
352 };
353
354 static const char *tbl_types_wireshark_txt[] = {
355                        /*  0 */ "FT_BOOLEAN",   /* TBL_BOOLEAN */
356                        /*  1 */ "FT_UINT32",    /* TBL_INTEGER */
357                        /*  2 */ "FT_UINT32",    /* TBL_BITSTRING */
358                        /*  2 */ "FT_STRINGZ",   /* TBL_OCTETSTRING */
359                        /*  4 */ "FT_NONE",      /* TBL_NULL */
360                        /*  5 */ "FT_BYTES",     /* TBL_OID */
361                        /*  6 */ "FT_DOUBLE",    /* TBL_REAL */
362                        /*  7 */ "FT_UINT32",    /* TBL_ENUMERATED */
363                        /*  8 */ "FT_NONE",      /* TBL_SEQUENCE */
364                        /*  9 */ "FT_NONE",      /* TBL_SET */
365                        /* 10 */ "FT_NONE",      /* TBL_SEQUENCEOF */
366                        /* 11 */ "FT_NONE",      /* TBL_SETOF */
367                        /* 12 */ "FT_NONE",      /* TBL_CHOICE */
368                        /* 13 */ "FT_NONE",      /* TBL_TYPEREF */
369
370                        /* 14 */ "FT_NONE",      /* TBL_SEQUENCEOF_start */
371                        /* 15 */ "FT_NONE",      /* TBL_TYPEREF_nopop */
372                        /* 16 */ "FT_NONE",      /* TBL_CHOICE_done */
373                        /* 17 */ "FT_NONE",      /* TBL_reserved */
374                        /* 18 */ "FT_NONE",      /* TBL_CHOICE_immediate */
375
376                        /* 19 */ "FT_NONE",      /* TBL_INVALID */
377 };
378
379 typedef struct _PDUinfo PDUinfo;
380 struct _PDUinfo {
381         guint type;
382         const char *name;
383         const char *typename;
384         const char *fullname;
385         guchar tclass;
386         guint tag;
387         guint flags;
388         GNode *reference;
389         gint typenum;
390         gint basetype;          /* parent type */
391         gint mytype;            /* original type number, typenum may have gone through a reference */
392         gint value_id;          /* wireshark field id for the value in this PDU */
393         gint type_id;           /* wireshark field id for the type of this PDU */
394         hf_register_info value_hf; /* wireshark field info for this value */
395 };
396
397
398 /* bits in the flags collection */
399 #define PDU_OPTIONAL     1
400 #define PDU_IMPLICIT     2
401 #define PDU_NAMEDNUM     4
402 #define PDU_REFERENCE    8
403 #define PDU_TYPEDEF   0x10
404 #define PDU_ANONYMOUS 0x20
405 #define PDU_TYPETREE  0x40
406
407 #define PDU_CHOICE    0x08000000   /* manipulated by the PDUname routine */
408
409 static guint PDUinfo_initflags = 0;     /* default flags for newly allocated PDUinfo structs */
410
411 /* description of PDU properties as passed from the matching routine
412  * to the decoder and GUI.
413  */
414 typedef struct _PDUprops PDUprops;
415 struct _PDUprops {
416         guint type;     /* value from enum TBLTypeId */
417         const char *name;
418         const char *typename;
419         const char *fullname;
420         guint flags;
421         gpointer data;
422         gint value_id;
423         gint type_id;
424 };
425 /* flags defined in PDUprops.flags */
426 #define OUT_FLAG_type           1
427 #define OUT_FLAG_data           2
428 #define OUT_FLAG_typename       4
429 #define OUT_FLAG_dontshow       8
430 #define OUT_FLAG_noname      0x10
431 #define OUT_FLAG_constructed 0x20
432
433 static PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
434 static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
435
436 static const char empty[] = "";         /* address of the empt string, avoids many tests for NULL */
437 #define MAX_OTSLEN 256          /* max printed size for an octet string */
438
439
440 #undef NEST                     /* show nesting of asn.1 enties */
441
442 #ifdef NEST                     /* only for debugging */
443 /* show nesting, only for debugging... */
444 #define MAXTAGS MAX_NEST
445 static struct {
446         guchar cls;
447         guchar tag;
448 } taglist[MAXTAGS];
449
450 static char *showtaglist(guint level)
451 {
452         static char tagtxt[BUFLM];
453         char *p = tagtxt;
454         guint i;
455
456 #ifdef ALLTAGS
457         for(i=0; i<= level; i++) {
458                 switch(taglist[i].cls) {
459                 case BER_CLASS_UNI: *p++ = 'U'; break;
460                 case BER_CLASS_APP: *p++ = 'A'; break;
461                 case BER_CLASS_CON: *p++ = 'C'; break;
462                 case BER_CLASS_PRI: *p++ = 'P'; break;
463                 default:       *p++ = 'x'; break;
464                 }
465                 p += g_sprintf(p, "%d.", taglist[i].tag);
466         }
467 #else /* only context tags */
468         *p++ = 'C';
469         for(i=0; i<= level; i++) {
470                 if (taglist[i].cls == BER_CLASS_CON) {
471                         p += g_sprintf(p, "%d.", taglist[i].tag);
472                 }
473         }
474 #endif
475         *--p = 0;               /* remove trailing '.' */
476         return tagtxt;
477 }
478
479 static guint
480 get_context(guint level)
481 {
482         guint ctx = 0;
483         guint i;
484
485         for(i=0; i<=level; i++) {
486                 if (taglist[i].cls == BER_CLASS_CON)
487                         ctx = (ctx << 8) | taglist[i].tag;
488         }
489         return ctx;
490 }
491 #endif /* NEST, only for debugging */
492
493
494 /* Convert a bit string to an ascii representation for printing
495  * -- not thread safe ...
496  */
497 static const char *showbits(guchar *val, guint count)
498 {
499         static char str[BUFLM];
500         guint i;
501         char *p = str;
502
503         if (count > 32)
504                 return "*too many bits*";
505
506         if (val != 0) {
507                 for(i=0; i<count; i++) {
508                         if (i && ((i & 7) == 0)) *p++ = ' ';
509                         *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
510                 }
511         }
512         *p = 0;
513         return str;
514 }
515
516 /* get bitnames string for bits set */
517 static const char *
518 showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
519 {
520         static char str[BUFLL];
521         guint i;
522         char *p = str;
523
524         if (props->flags & OUT_FLAG_noname)
525                 return empty;
526
527         if (count > 32)
528                 return "*too many bits, no names...*";
529
530         if (val != NULL) {
531                 for(i=0; i<count; i++) {
532                         if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
533                                 p += g_sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
534                         }
535                 }
536                 if (p > str)
537                         --p;    /* remove terminating , */
538         }
539         *p = 0;
540         return str;
541
542
543
544 }
545 /* Convert an oid to its conventional text representation
546  * -- not thread safe...
547  */
548 static char *showoid(subid_t *oid, guint len)
549 {
550         static char str[BUFLM];
551         guint i;
552         char *p = str;
553
554         if (oid != NULL) {
555                 for(i=0; i<len; i++) {
556                         if (i) *p++ = '.';
557                         p += g_sprintf(p, "%lu", (unsigned long)oid[i]);
558                 }
559         }
560         *p = 0;
561         return str;
562 }
563
564 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
565 static char *
566 showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
567 {
568         guint dohex = 0;
569         guint i;
570         char *str, *p;
571         const char *endstr = empty;
572
573         if (len == 0) {
574                 str = g_malloc(1);
575                 str[0] = 0;
576         } else {
577                 for (i=0; i<len; i++) {
578                         if (!isprint(octets[i])) /* maybe isblank() as well ... */
579                                 dohex++;
580                 }
581                 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
582                         len = MAX_OTSLEN;
583                         endstr = "...."; /* this is 5 bytes !! */
584                 }
585                 if (dohex) {
586                         str = p = g_malloc(len*2 + 5);
587                         for (i=0; i<len; i++) {
588                                 p += g_sprintf(p, "%2.2X", octets[i]);
589                         }
590                         strncpy(p, endstr, 5);
591                 } else {
592                         if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
593                                 str = p = g_malloc(len*3+2);
594                                 for (i=0; i<len; i++) {
595                                         p += g_sprintf(p, "%2.2X", octets[i]);
596                                 }
597                                 *p++ = ' '; /* insert space */
598                                 strncpy(p, octets, len);
599                                 p[len] = 0;
600                         } else {
601                                 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
602                                 str = g_malloc(len+5);
603                                 strncpy(str, octets, len);
604                                 strncpy(&str[len], endstr, 5);
605                         }
606                 }
607         }
608         return str;
609 }
610
611 /* allow NULL pointers in strcmp, handle them as empty strings */
612 static int
613 g_strcmp(gconstpointer a, gconstpointer b)
614 {
615         if (a == 0) a = empty;
616         if (b == 0) b = empty;
617         return strcmp(a, b);
618 }
619
620 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
621 /* WARNING   WARNING   WARNING   WARNING   WARNING   WARNING */
622 /*                                                           */
623 /* Most of the following routine is guesswork in order to    */
624 /* speed up resynchronisation if the dissector lost the      */
625 /* encoding due to incomplete captures, or a capture that    */
626 /* starts in the middle of a fragmented ip packet            */
627 /* If this poses to many problems, these settings can be     */
628 /* made part of the protocol settings in the user interface  */
629 /*************************************************************/
630
631 /* check length for a reasonable value, return a corrected value */
632 static int
633 checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
634 {
635         int newlen = len;
636
637         if ( ! def) {
638                 g_snprintf(lenstr, strmax, "indefinite");
639                 return len;
640         }
641
642         if (len < 0)            /* negative ..... */
643                 newlen = 4;
644
645         if (cls != BER_CLASS_UNI) {     /* don't know about the tags */
646                 if (len > 131071)
647                         newlen = 64;
648         } else {
649                 switch (tag) {
650                 case BER_UNI_TAG_EOC:   /* End Of Contents    */
651                 case BER_UNI_TAG_NULL:  /* Null               */
652                         newlen = 0;
653                         break;
654                 case BER_UNI_TAG_BOOLEAN:       /* Boolean            */
655                         newlen = 1;
656                         break;
657                 case BER_UNI_TAG_INTEGER:       /* Integer            */
658                 case BER_UNI_TAG_ENUMERATED:    /* Enumerated         */
659                         if (len > 8)
660                                 newlen = 4;
661                         break;
662                 case BER_UNI_TAG_BITSTRING:     /* Bit String         */
663                         if (len > 8)
664                                 newlen = 4;
665                         break;
666                 case BER_UNI_TAG_OCTETSTRING:   /* Octet String       */
667                 case BER_UNI_TAG_NumericString: /* Numerical String   */
668                 case BER_UNI_TAG_PrintableString: /* Printable String   */
669                 case BER_UNI_TAG_TeletexString: /* Teletext String    */
670                 case BER_UNI_TAG_VideotexString: /* Video String       */
671                 case BER_UNI_TAG_IA5String: /* IA5 String         */
672                 case BER_UNI_TAG_GraphicString: /* Graphical String   */
673                 case BER_UNI_TAG_VisibleString: /* Visible String     */
674                 case BER_UNI_TAG_GeneralString: /* General String     */
675                 if (len > 65535)
676                         newlen = 32;
677                 break;
678                 case BER_UNI_TAG_OID:           /* Object Identifier  */
679                 case BER_UNI_TAG_ObjectDescriptor:              /* Description        */
680                 case ASN1_EXT:          /* External           */
681                         if (len > 64)
682                                 newlen = 16;
683                         break;
684                 case BER_UNI_TAG_REAL:          /* Real               */
685                         if (len >16)
686                                 newlen = 8;
687                         break;
688                 case BER_UNI_TAG_SEQUENCE:              /* Sequence           */
689                 case BER_UNI_TAG_SET:           /* Set                */
690                         if (len > 65535)
691                                 newlen = 64;
692                         break;
693                 case BER_UNI_TAG_UTCTime:       /* Universal Time     */
694                 case BER_UNI_TAG_GeneralizedTime:       /* General Time       */
695                         if (len > 32)
696                                 newlen = 15;
697                         break;
698
699                 default:
700                         if (len > 131071)
701                                 newlen = 64;
702                         break;
703                 }
704         }
705
706         if (newlen != len) {
707                 /* a change was needed.... */
708                 g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
709         } else {
710                 g_snprintf(lenstr, strmax, "%d", len);
711         }
712         return newlen;
713 }
714
715 static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
716 static void PDUreset(int count, int counr2);
717
718 static void
719 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
720
721   ASN1_SCK asn1;
722   guint cls, con, tag, len, offset, reassembled;
723   gboolean def;
724   char lenstr[BUFLS];
725   char tagstr[BUFLS];
726   char headstr[BUFLL];
727   char offstr[BUFLS];
728   const char *name, *tname;
729   volatile guint boffset;
730   volatile int i = 0;           /* PDU counter */
731   proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
732   proto_item *hidden_item;
733   PDUprops props;
734   static guint lastseq;
735   struct tcpinfo *info;
736   gint delta;
737
738   pcount++;
739   boffset = 0;
740
741   reassembled = 1;              /* UDP is not a stream, and thus always reassembled .... */
742   if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
743           info = (struct tcpinfo *)pinfo->private_data;
744           delta = info->seq - lastseq;
745           reassembled = info->is_reassembled;
746           lastseq = info->seq;
747
748           if (asn1_verbose)
749                   g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
750                             info->seq, delta, reassembled);
751   } else {
752           if (asn1_verbose)
753                   g_message("dissect_asn1: udp");
754   }
755
756   /* Set the protocol column */
757   col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
758
759   col_clear(pinfo->cinfo, COL_INFO);
760
761
762   offstr[0] = 0;
763   if ((first_pdu_offset > 0) && !reassembled) {
764           boffset = first_pdu_offset;
765           g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
766   }
767
768   /* open BER decoding */
769   asn1_open(&asn1, tvb, boffset);
770
771   asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
772
773   asn1_close(&asn1, &offset);
774
775   PDUreset(pcount, 0);          /* arguments are just for debugging */
776   getPDUprops(&props, boffset, cls, tag, con);
777   name = props.name;
778   tname = props.typename;
779
780   len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
781
782   if (asn1_debug) {
783
784           g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
785
786           g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
787                    offstr,
788                    tname,
789                    name,
790                    pcount,
791                    asn1_cls[cls],
792                    asn1_con[con],
793                    ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
794                    lenstr,
795                    boffset,
796                    tvb_length(tvb)
797                   );
798   } else {
799           if (props.flags & OUT_FLAG_noname) {
800                   g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
801                   name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
802           }
803           g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
804   }
805
806   /* Set the info column */
807   col_add_str(pinfo->cinfo, COL_INFO, headstr );
808
809   /*
810    * If we have a non-null tree (ie we are building the proto_tree
811    * instead of just filling out the columns ), then add a BER
812    * tree node
813    */
814
815   /* ignore the tree here, must decode BER to know how to reassemble!! */
816 /* if(tree) { */
817
818     TRY {                       /* catch incomplete PDU's */
819
820         ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
821                                             def? (int) (offset - boffset + len) :  -1,
822                                             "ASN.1 %s", current_pduname);
823
824         tree2 = proto_item_add_subtree(ti, ett_asn1);
825
826         hidden_item = proto_tree_add_item(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
827                                    def? (int) (offset - boffset + len) :  -1, TRUE);
828         PROTO_ITEM_SET_HIDDEN(hidden_item);
829
830         offset = boffset; /* the first packet */
831         while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
832             ti2 = 0;
833             boffset = offset;
834             /* open BER decoding */
835             asn1_open(&asn1, tvb, offset);
836             asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
837             asn1_close(&asn1, &offset);
838
839             PDUreset(pcount, i+1);
840             getPDUprops(&props, boffset, cls, tag, con);
841             name = props.name;
842             tname = props.typename;
843
844             if (!def)
845                     len = tvb_length_remaining(tvb, offset);
846
847             len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
848
849             if (asn1_debug) {
850
851                     g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
852
853                     g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
854                              asn1_cls[cls],
855                              asn1_con[con],
856                              ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
857                              lenstr,
858                              boffset,
859                              tvb_length_remaining(tvb, offset) );
860
861                     if (props.value_id == -1)
862                             ti2 = proto_tree_add_text(tree2, tvb, boffset,
863                                                       def? (int) (offset - boffset + len) :  -1,
864                                                       "%s: (%s)%s %d-%d %s", current_pduname,
865                                                       tname, name, pcount, i+1, headstr);
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 %d-%d %s ~", current_pduname,
870                                                       tname, name, pcount, i+1, headstr);
871
872                                 if (props.type_id != -1){
873                                  hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
874                                                       def? (int) (offset - boffset + len) :  -1, TRUE);
875                                          PROTO_ITEM_SET_HIDDEN(hidden_item);
876                                 }
877
878                     }
879             } else {
880                     if (props.flags & OUT_FLAG_noname) {
881                             g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
882                             name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
883                     }
884                     if (props.value_id == -1)
885                             ti2 = proto_tree_add_text(tree2, tvb, boffset,
886                                                       def? (int) (offset - boffset + len) :  -1,
887                                                       "%s: (%s)%s", current_pduname, tname, name);
888                     else {
889                             ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
890                                                       def? (int) (offset - boffset + len) :  -1,
891                                                       "%s: (%s)%s ~", current_pduname, tname, name);
892                                 if (props.type_id != -1){
893                                 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
894                                                       def? (int) (offset - boffset + len) :  -1, TRUE);
895                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
896                                 }
897                     }
898             }
899             asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
900
901 #ifdef NEST
902             taglist[0].cls = cls;
903             taglist[0].tag = tag;
904 #endif /* NEST */
905
906             if (!def) len++; /* make sure we get an exception if we run off the end! */
907
908             offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
909
910             proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
911
912             i++; /* one more full message handled */
913
914             if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
915                     proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
916         }
917         col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
918         if (ti)
919                 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
920     }
921     CATCH(BoundsError) {
922             RETHROW;
923     }
924     CATCH(ReportedBoundsError) {
925             col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
926             if (ti)
927                     proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
928             if (ti2)
929                     proto_item_append_text(ti2, " (incomplete)");
930             if (asn1_desegment) {
931                     pinfo->desegment_offset = boffset;
932                     pinfo->desegment_len = 1;
933                     if (asn1_verbose)
934                             g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
935                                       boffset, 1, pinfo->can_desegment);
936             } else {
937                     RETHROW;
938             }
939     }
940     ENDTRY;
941 /* } */
942   if (asn1_verbose)
943         g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
944                    pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
945 }
946
947 /* decode an ASN.1 sequence, until we have consumed the specified length */
948 static guint
949 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
950 {
951   ASN1_SCK asn1;
952   guint ret, cls, con, tag, len, boffset, soffset, eos;
953   gboolean def;
954   guint value;
955   const char *clsstr, *constr, *tagstr;
956   char tagbuf[BUFLM];
957   char lenbuf[BUFLM];
958   char nnbuf[BUFLS];
959   proto_tree *ti, *pt2;
960   proto_item *hidden_item;
961   guchar *octets, *bits, unused;
962   subid_t *oid;
963   /* the debugging formats */
964   static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s";          /* decimal */
965   static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s";       /* enum */
966   static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s";        /* octet string */
967   static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s";       /* bit field */
968   static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s";            /* constructed */
969   static char matchind[] = " ~"; /* indication of possible match */
970   const char *name, *ename, *tname;
971   char *oname;
972   PDUprops props;
973
974   ti = 0;                       /* suppress gcc warning */
975
976   soffset = offset; /* where this sequence starts */
977   eos = offset + tlen;
978   while (offset < eos) {        /* while this entity has not ended... */
979           boffset = offset;
980           asn1_open(&asn1, tvb, offset);
981           ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
982           asn1_close(&asn1, &offset); /* mark current position */
983           if (ret != ASN1_ERR_NOERROR) {
984                 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
985                 break;
986           }
987
988           getPDUprops(&props, boffset, cls, tag, con);
989           name = props.name;
990           tname = props.typename;
991           if (asn1_full)
992                   name = &props.fullname[pabbrev_pdu_len];      /* no abbrev.pduname */
993           if (asn1_debug) {     /* show both names */
994                   g_sprintf(fieldname, "%s[%s]", props.name, props.fullname);
995                   name = fieldname;
996           }
997
998           clsstr = asn1_cls[cls];
999           constr = asn1_con[con];
1000           if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
1001                   tagstr = asn1_tag[tag];
1002           } else {
1003                   g_snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
1004                   tagstr = tagbuf;
1005           }
1006
1007           len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
1008
1009           if (def) {
1010                   g_snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
1011           } else {
1012                   strncpy(nnbuf, "NN-", sizeof(nnbuf));
1013                                 /* make sure we get an exception if we run off the end! */
1014                   len = tvb_length_remaining(tvb, offset) + 1;
1015           }
1016           if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
1017                   /* just give type name if we don't know any better */
1018                   tname = tagstr;
1019                   name = nnbuf; /* this is better than just empty.... */
1020           }
1021
1022 #ifdef NEST
1023           taglist[level].cls = cls;
1024           taglist[level].tag = tag;
1025 #endif /* NEST */
1026
1027           oname  = 0;
1028           if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
1029                 cls = BER_CLASS_UNI;
1030                 tag = BER_UNI_TAG_GeneralString;
1031                 oname = g_malloc(strlen(name) + 32);
1032                 g_sprintf(oname, "%s ** nesting cut off **", name);
1033                 name = oname;
1034           }
1035           switch(cls) {
1036             case BER_CLASS_UNI: /* fprintf(stderr, "Universal\n"); */
1037               switch(tag) {
1038                 case BER_UNI_TAG_INTEGER:
1039                       ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1040                       asn1_close(&asn1, &offset); /* mark where we are now */
1041                       if (asn1_debug) {
1042                               if ( (props.value_id == -1) ||
1043                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1044                                         /* unknown or unexpected: just text */
1045                                         proto_tree_add_text(pt, tvb, boffset,
1046                                                         offset - boffset, textfmt_d, boffset,
1047                                                         clsstr, constr, tagstr, tname, name, value,
1048                                                         empty);
1049                               else {
1050                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1051                                                         offset - boffset, value, textfmt_d, boffset,
1052                                                         clsstr, constr, tagstr, tname, name, value,
1053                                                         matchind);
1054                                         if (props.type_id != -1) {
1055                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1056                                                                 boffset, offset - boffset, value);
1057                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1058                                         }
1059                               }
1060                       } else {
1061                               if ( (props.value_id == -1) ||
1062                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1063                                         /* unknown or unexpected, just text */
1064                                         proto_tree_add_text(pt, tvb, boffset,
1065                                                         offset - boffset,
1066                                                         "(%s)%s: %d", tname, name, value);
1067                               else {
1068                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1069                                                         offset - boffset, value,
1070                                                         "(%s)%s: %d ~", tname, name, value);
1071                                         if (props.type_id != -1){
1072                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1073                                                                 boffset, offset - boffset, value);
1074                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1075                                         }
1076                               }
1077                       }
1078                       break;
1079
1080                 case BER_UNI_TAG_ENUMERATED:
1081                       ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1082                       asn1_close(&asn1, &offset); /* mark where we are now */
1083                       ename = getPDUenum(&props, boffset, cls, tag, value);
1084                       if (asn1_debug) {
1085                               if ( (props.value_id == -1) ||
1086                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1087                                         /* unknown or unexpected, just text */
1088                                         proto_tree_add_text(pt, tvb, boffset,
1089                                                         offset - boffset,
1090                                                         textfmt_e, boffset, clsstr, constr, tagstr,
1091                                                         tname, name, value, ename, empty);
1092                               else {
1093                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1094                                                         offset - boffset, value,
1095                                                         textfmt_e, boffset, clsstr, constr, tagstr,
1096                                                         tname, name, value, ename, matchind);
1097                                         if (props.type_id != -1){
1098                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1099                                                                 boffset, offset - boffset, value);
1100                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1101                                         }
1102                               }
1103                       } else {
1104                               if ( (props.value_id == -1) ||
1105                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1106                                         /* unknown or unexpected, just text */
1107                                         proto_tree_add_text(pt, tvb, boffset,
1108                                                         offset - boffset,
1109                                                         "(%s)%s: %d:%s", tname, name, value, ename);
1110                               else {
1111                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1112                                                         offset - boffset, value,
1113                                                         "(%s)%s: %d:%s ~", tname, name, value, ename);
1114                                         if (props.type_id != -1){
1115                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1116                                                                 boffset, offset - boffset, value);
1117                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1118                                         }
1119                               }
1120                       }
1121                       break;
1122
1123                 case BER_UNI_TAG_BOOLEAN:
1124                       ret = asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1125                       asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1126                       if (asn1_debug) {
1127                               if ( (props.value_id == -1) ||
1128                                    (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1129                                         /* unknown or unexpected, just text */
1130                                         proto_tree_add_text(pt, tvb, boffset,
1131                                                         offset - boffset,
1132                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1133                                                         tname, name, value? "true" : "false", empty);
1134                               else {
1135                                         proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1136                                                         offset - boffset, value != 0,
1137                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1138                                                         tname, name, value? "true" : "false", matchind);
1139                                         if (props.type_id != -1){
1140                                                 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1141                                                                 boffset, offset - boffset, value != 0);
1142                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1143                                         }
1144                               }
1145                       } else {
1146                               if ( (props.value_id == -1) ||
1147                                    (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1148                                         /* unknown or unexpected, just text */
1149                                         proto_tree_add_text(pt, tvb, boffset,
1150                                                         offset - boffset,
1151                                                         "(%s)%s: %s", tname, name,
1152                                                         value? "true" : "false");
1153                               else {
1154                                         proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1155                                                         offset - boffset, value != 0,
1156                                                         "(%s)%s: %s ~", tname, name,
1157                                                         value? "true" : "false");
1158                                         if (props.type_id != -1){
1159                                                 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1160                                                                 boffset, offset - boffset, value != 0);
1161                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1162                                         }
1163                               }
1164                       }
1165                       break;
1166
1167                 case BER_UNI_TAG_OCTETSTRING:
1168                 case BER_UNI_TAG_NumericString:
1169                 case BER_UNI_TAG_PrintableString:
1170                 case BER_UNI_TAG_TeletexString:
1171                 case BER_UNI_TAG_IA5String:
1172                 case BER_UNI_TAG_GeneralString:
1173                 case BER_UNI_TAG_UTCTime:
1174                 case BER_UNI_TAG_GeneralizedTime:
1175                         /* read value, \0 terminated */
1176                       ret = asn1_string_value_decode(&asn1, len, &octets);
1177                       asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1178                       ename = showoctets(octets, len, (tag == BER_UNI_TAG_OCTETSTRING) ? 4 : 0 );
1179                       if (asn1_debug) {
1180                               if ( (props.value_id == -1) ||
1181                                    (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1182                                         /* unknown or unexpected, just text */
1183                                         proto_tree_add_text(pt, tvb, boffset,
1184                                                         offset - boffset,
1185                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1186                                                         tname, name, ename, empty);
1187                               else {
1188                                         proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1189                                                         offset - boffset, octets, /* \0 termnated */
1190                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1191                                                         tname, name, ename, matchind);
1192                                         if (props.type_id != -1){
1193                                                 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1194                                                                 boffset, offset - boffset, octets);
1195                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1196                                         }
1197                               }
1198                       } else {
1199                               if ( (props.value_id == -1) ||
1200                                    (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1201                                         /* unknown or unexpected, just text */
1202                                         proto_tree_add_text(pt, tvb, boffset,
1203                                                         offset - boffset,
1204                                                         "(%s)%s: %s", tname, name, ename);
1205                               else {
1206                                         proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1207                                                         offset - boffset, octets, /* \0 terminated */
1208                                                         "(%s)%s: %s ~", tname, name, ename);
1209                                         if (props.type_id != -1){
1210                                                 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1211                                                                 boffset, offset - boffset, octets);
1212                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1213                                         }
1214                               }
1215                       }
1216                       g_free(octets);
1217                       g_free( (gpointer) ename);
1218                       break;
1219
1220                 case BER_UNI_TAG_BITSTRING:
1221                       ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1222                       asn1_close(&asn1, &offset); /* mark where we are now */
1223                       ename = showbitnames(bits, (con*8)-unused, &props, offset);
1224                       if (asn1_debug) {
1225                               if ( (props.value_id == -1) ||
1226                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1227                                         /* unknown or unexpected, just text */
1228                                         proto_tree_add_text(pt, tvb, boffset,
1229                                                         offset - boffset,
1230                                                         textfmt_b, boffset, clsstr, constr, tagstr,
1231                                                         tname, name,
1232                                                         showbits(bits, (con*8)-unused), ename, empty);
1233                               else {
1234                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1235                                                         offset - boffset, *bits, /* XXX length ? XXX */
1236                                                         textfmt_b, boffset, clsstr, constr, tagstr,
1237                                                         tname, name,
1238                                                         showbits(bits, (con*8)-unused),ename, matchind);
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                       } else {
1247                               if ( (props.value_id == -1) ||
1248                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1249                                         /* unknown or unexpected, just text */
1250                                         proto_tree_add_text(pt, tvb, boffset,
1251                                                         offset - boffset,
1252                                                         "(%s)%s: %s:%s", tname, name,
1253                                                         showbits(bits, (con*8)-unused), ename);
1254                               else {
1255                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1256                                                         offset - boffset, *bits, /* XXX length ? XXX */
1257                                                         "(%s)%s: %s:%s ~", tname, name,
1258                                                         showbits(bits, (con*8)-unused), ename);
1259                                         if (props.type_id != -1){
1260                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1261                                                                 boffset, offset - boffset, *bits);
1262                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1263                                         }
1264                               }
1265                       }
1266                       g_free(bits);
1267                       break;
1268
1269                 case BER_UNI_TAG_SET:
1270                 case BER_UNI_TAG_SEQUENCE:
1271                                 /* show full sequence length */
1272                       if (asn1_debug) {
1273                               ename = empty;
1274                               if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1275                                       ename = ", noshow";
1276                               if ( (props.flags & OUT_FLAG_constructed))
1277                                       ename = ", unexpected constructed";
1278
1279                               if (props.value_id == -1)
1280                                       ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1281                                                              textfmt_c, boffset, clsstr, constr, tagstr,
1282                                                              tname, name, ename, empty);
1283                               else {
1284                                       ti = proto_tree_add_item(pt, props.value_id, tvb,
1285                                                               boffset, 1, TRUE);
1286                                       /* change te text to to what I really want */
1287                                       proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1288                                                              tagstr, tname, name, ename, matchind);
1289                                           if (props.type_id != -1){
1290                                               hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1291                                                               boffset, 1, TRUE);
1292                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1293                                           }
1294                               }
1295                       } else {
1296                               if (props.value_id == -1) {
1297                                       if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1298                                               ti = proto_tree_add_text(pt, tvb, boffset,
1299                                                                        offset - boffset + len,
1300                                                                        "(%s)%s", tname, name);
1301                               } else {
1302                                       if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1303                                               ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1304                                                                        boffset, offset - boffset + len,
1305                                                                        "(%s)%s ~", tname, name);
1306                                       else {
1307                                               /* don't care about the text */
1308                                               ti = hidden_item = proto_tree_add_item(pt, props.value_id, tvb,
1309                                                           boffset, 1, TRUE);
1310                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1311                                       }
1312                                           if (props.type_id != -1){
1313                                               hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1314                                                           boffset, 1, TRUE);
1315                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1316                                           }
1317                               }
1318                       }
1319                       if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1320
1321                       if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1322                               pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1323                       else
1324                               pt2 = pt;
1325
1326                       offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1327
1328                       if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1329                               proto_item_set_len(ti, offset - boffset);
1330
1331                       break;
1332
1333                 case BER_UNI_TAG_EOC:
1334                       if (asn1_debug) { /* don't show if not debugging */
1335                               proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1336                                                   boffset, clsstr, constr, tagstr, tname, name,
1337                                                   offset - soffset, empty);
1338                       }
1339                       getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1340                       return offset;
1341
1342                 case BER_UNI_TAG_OID:
1343                       ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1344                       asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1345                       ename = showoid(oid, con);
1346                       if (asn1_debug) {
1347                               if ( (props.value_id == -1) ||
1348                                    (tbl_types_wireshark[props.type] != FT_BYTES) )
1349                                       /* unknown or unexpected, just text */
1350                                       proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1351                                                           boffset, clsstr, constr, tagstr, tname, name,
1352                                                           ename, empty);
1353                               else {
1354                                       proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1355                                                                  offset - boffset, ename,/* XXX length?*/
1356                                                                  "(%s)%s: %s ~", tname, name, ename);
1357                                           if (props.type_id != -1){
1358                                                   hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1359                                                                 boffset, offset - boffset, ename);
1360                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1361                                           }
1362                               }
1363                       } else {
1364                               if ( (props.value_id == -1) ||
1365                                    (tbl_types_wireshark[props.type] != FT_BYTES) )
1366                                         /* unknown or unexpected, just text */
1367                                         proto_tree_add_text(pt, tvb, boffset,
1368                                                         offset - boffset,
1369                                                         "(%s)%s: %s", tname, name, ename);
1370                               else {
1371                                         proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1372                                                         offset - boffset, ename, /* XXX length ? */
1373                                                         "(%s)%s: %s ~", tname, name, ename);
1374                                         if (props.type_id != -1){
1375                                                 hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1376                                                                 boffset, offset - boffset, ename);
1377                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1378                                         }
1379                               }
1380                       }
1381                       g_free(oid);
1382                       break;
1383
1384                 case BER_UNI_TAG_NULL:
1385                       if (asn1_debug) {
1386                               proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1387                                                   boffset, clsstr, constr, tagstr, tname, name,
1388                                                   "[NULL]", empty);
1389                       } else {
1390                               proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1391                                                   "(%s)%s: [NULL]", tname, name);
1392                       }
1393                       offset += len; /* skip value ... */
1394                       break;
1395
1396                 case BER_UNI_TAG_ObjectDescriptor:
1397                 case ASN1_EXT:
1398                 case BER_UNI_TAG_REAL:
1399                 case BER_UNI_TAG_VideotexString:
1400                 case BER_UNI_TAG_GraphicString:
1401                 case BER_UNI_TAG_VisibleString:
1402
1403                 default:
1404                       if (asn1_debug) {
1405                               ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1406                                                        textfmt_s, boffset, clsstr, constr, tagstr,
1407                                                        tname, name, lenbuf, empty);
1408                       } else {
1409                               ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1410                                                        "(%s)%s: %s bytes", tname, name, lenbuf);
1411                       }
1412                       proto_item_append_text(ti, " *"); /* indicate default is used */
1413                       offset += len; /* skip value ... */
1414                       break;
1415               };
1416               break;
1417
1418             case BER_CLASS_CON:         /* fprintf(stderr, "Context\n"); */
1419             case BER_CLASS_APP:         /* fprintf(stderr, "Application\n"); */
1420             case BER_CLASS_PRI:         /* fprintf(stderr, "Private\n"); */
1421
1422                   if (def && !con) {
1423                         if (props.value_id == -1) /* type unknown, handle as string */
1424                                 goto dostring;
1425                         switch(props.type) {
1426                                 /* this is via the asn1 description, don't trust the length */
1427                         case TBL_INTEGER:
1428                                 if (len > 4)
1429                                         goto dostring;
1430                                 ret = asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
1431                                 asn1_close(&asn1, &offset); /* mark where we are now */
1432                                 if (asn1_debug) {
1433                                         if ( (props.value_id == -1) ||
1434                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1435                                                 /* unknown or unexpected, just text */
1436                                                 proto_tree_add_text(pt, tvb,
1437                                                             boffset, offset - boffset,
1438                                                             textfmt_d, boffset, clsstr, constr,
1439                                                             tagstr, tname, name, value, empty);
1440                                         else {
1441                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1442                                                             boffset, offset - boffset, value,
1443                                                             textfmt_d, boffset, clsstr, constr,
1444                                                             tagstr, tname, name, value, matchind);
1445                                                 if (props.type_id != -1){
1446                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1447                                                                 tvb, boffset, offset - boffset, value);
1448                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1449                                                 }
1450                                         }
1451                                 } else {
1452                                         if ( (props.value_id == -1) ||
1453                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1454                                                 /* unknown or unexpected, just text */
1455                                                 proto_tree_add_text(pt, tvb,
1456                                                             boffset, offset - boffset,
1457                                                             "(%s)%s: %d", tname, name, value);
1458                                         else {
1459                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1460                                                             boffset, offset - boffset, value,
1461                                                             "(%s)%s: %d ~", tname, name, value);
1462                                                 if (props.type_id != -1){
1463                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1464                                                                 tvb, boffset, offset - boffset, value);
1465                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1466                                                 }
1467                                         }
1468                                 }
1469                                 break;
1470
1471                         case TBL_ENUMERATED:
1472                                 if (len > 4)
1473                                         goto dostring;
1474                                 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1475                                 asn1_close(&asn1, &offset); /* mark where we are now */
1476                                 ename = getPDUenum(&props, boffset, cls, tag, value);
1477                                 if (asn1_debug) {
1478                                         if ( (props.value_id == -1) ||
1479                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1480                                                 /* unknown or unexpected, just text */
1481                                                 proto_tree_add_text(pt, tvb,
1482                                                            boffset, offset - boffset,
1483                                                            textfmt_e, boffset, clsstr, constr,
1484                                                            tagstr, tname, name, value, ename, empty);
1485                                         else {
1486                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1487                                                            boffset, offset - boffset, value,
1488                                                            textfmt_e, boffset, clsstr, constr,
1489                                                            tagstr, tname, name, value, ename, matchind);
1490                                                 if (props.type_id != -1){
1491                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1492                                                                 tvb, boffset, offset - boffset, value);
1493                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1494                                                 }
1495                                         }
1496                                 } else {
1497                                         if ( (props.value_id == -1) ||
1498                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1499                                                 /* unknown or unexpected, just text */
1500                                                 proto_tree_add_text(pt, tvb,
1501                                                            boffset, offset - boffset,
1502                                                            "(%s)%s: %d:%s", tname, name, value, ename);
1503                                         else {
1504                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1505                                                           boffset, offset - boffset, value,
1506                                                           "(%s)%s: %d:%s ~", tname, name, value, ename);
1507                                                 if (props.type_id != -1){
1508                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1509                                                                 tvb, boffset, offset - boffset, value);
1510                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1511                                                 }
1512                                         }
1513                                 }
1514                                 break;
1515                         case TBL_BITSTRING:
1516                                 if (len > (1+4)) /* max 32 bits ...?.. */
1517                                         goto dostring;
1518                                                                 /* read value */
1519                                 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1520                                 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1521                                 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1522                                 if (asn1_debug) {
1523                                         if ( (props.value_id == -1) ||
1524                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1525                                                 /* unknown or unexpected, just text */
1526                                                 proto_tree_add_text(pt, tvb,
1527                                                             boffset, offset - boffset,
1528                                                             textfmt_b, boffset, clsstr, constr,
1529                                                             tagstr, tname, name,
1530                                                             showbits(bits, (con*8)-unused), ename,
1531                                                             empty);
1532                                         else {
1533                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1534                                                             boffset, offset - boffset, *bits,
1535                                                             textfmt_b, boffset, clsstr, constr,
1536                                                             tagstr, tname, name,
1537                                                             showbits(bits, (con*8)-unused), ename,
1538                                                             matchind);
1539                                                 if (props.type_id != -1){
1540                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1541                                                                  tvb, boffset, offset - boffset, *bits);
1542                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1543                                                 }
1544                                         }
1545                                 } else {
1546                                         if ( (props.value_id == -1) ||
1547                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1548                                                 /* unknown or unexpected, just text */
1549                                                 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1550                                                             "(%s)%s: %s:%s", tname, name,
1551                                                             showbits(bits, (con*8)-unused), ename);
1552                                         else {
1553                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1554                                                             boffset, offset - boffset, *bits,
1555                                                             "(%s)%s: %s:%s ~", tname, name,
1556                                                             showbits(bits, (con*8)-unused), ename);
1557                                                 if (props.type_id != -1){
1558                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1559                                                                 tvb, boffset, offset - boffset, *bits);
1560                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1561                                                 }
1562                                         }
1563                                 }
1564                                 g_free(bits);
1565                                 break;
1566                         case TBL_BOOLEAN:
1567                                 if (len > 1)
1568                                         goto dostring;
1569                                 ret = asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1570                                 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1571                                 if (asn1_debug) {
1572                                         if ( (props.value_id == -1) ||
1573                                              (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1574                                                 /* unknown or unexpected, just text */
1575                                                 proto_tree_add_text(pt, tvb,
1576                                                             boffset, offset - boffset,
1577                                                             textfmt_s, boffset, clsstr, constr,
1578                                                             tagstr, tname, name,
1579                                                             value? "true" : "false", empty);
1580                                         else {
1581                                                 proto_tree_add_boolean_format(pt, props.value_id,  tvb,
1582                                                             boffset, offset - boffset, value != 0,
1583                                                             textfmt_s, boffset, clsstr, constr,
1584                                                             tagstr, tname, name,
1585                                                             value? "true" : "false", matchind);
1586                                                 if (props.type_id != -1){
1587                                                         hidden_item = proto_tree_add_boolean(pt, props.type_id,
1588                                                           tvb, boffset, offset - boffset, value != 0);
1589                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1590                                                 }
1591                                         }
1592                                 } else {
1593                                         if ( (props.value_id == -1) ||
1594                                              (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1595                                                 /* unknown or unexpected, just text */
1596                                                 proto_tree_add_text(pt, tvb,
1597                                                             boffset, offset - boffset,
1598                                                             "(%s)%s: %s", tname, name,
1599                                                             value? "true" : "false");
1600                                         else {
1601                                                 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1602                                                             boffset, offset - boffset, value != 0,
1603                                                             "(%s)%s: %s ~", tname, name,
1604                                                             value? "true" : "false");
1605                                                 if (props.type_id != -1){
1606                                                         hidden_item = proto_tree_add_boolean(pt, props.type_id,
1607                                                           tvb, boffset, offset - boffset, value != 0);
1608                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1609                                                 }
1610                                         }
1611                                 }
1612                                 break;
1613                         case TBL_NULL:
1614                                 if (len > 0)
1615                                         goto dostring;
1616                                 if (asn1_debug) {
1617                                         proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1618                                                             textfmt_s, boffset, clsstr, constr,
1619                                                             tagstr, tname, name, "[NULL]", empty);
1620                                 } else {
1621                                         proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1622                                                             "(%s)%s: [NULL]", tname, name);
1623                                 }
1624                                 offset += len; /* skip value ... */
1625                                 break;
1626                         default:
1627                         dostring:
1628                                 props.value_id = -1; /* unlikely this is correct, dont use it */
1629                                 /* fallthrough */
1630                         case TBL_OCTETSTRING:
1631                                 /* defined length, not constructed, must be a string.... */
1632                                 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1633                                 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1634                                 ename = showoctets(octets, len, 2); /* convert octets to printable */
1635                                 if (asn1_debug) {
1636                                         if ( (props.value_id == -1) ||
1637                                              (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1638                                                 /* unknown or unexpected, just text */
1639                                                 proto_tree_add_text(pt, tvb,
1640                                                             boffset, offset - boffset,
1641                                                             textfmt_s, boffset, clsstr, constr,
1642                                                             tagstr, tname, name, ename, empty);
1643                                         else {
1644                                                 proto_tree_add_string_format(pt, props.value_id, tvb,
1645                                                             boffset, offset - boffset, (gchar *)octets, /* XXX */
1646                                                             textfmt_s, boffset, clsstr, constr,
1647                                                             tagstr, tname, name, ename, matchind);
1648                                                 if (props.type_id != -1){
1649                                                         hidden_item = proto_tree_add_string(pt, props.type_id,
1650                                                                 tvb, boffset, offset - boffset, (gchar *)octets);
1651                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1652                                                 }
1653                                         }
1654                                 } else {
1655                                         if ( (props.value_id == -1) ||
1656                                              (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1657                                                 /* unknown or unexpected, just text */
1658                                                 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1659                                                             "(%s)%s: %s", tname, name, ename);
1660                                         else {
1661                                                 proto_tree_add_string_format(pt, props.value_id, tvb,
1662                                                             boffset, offset - boffset, (gchar *)octets, /* XXX */
1663                                                             "(%s)%s: %s ~", tname, name, ename);
1664                                                 if (props.type_id != -1){
1665                                                         hidden_item = proto_tree_add_string(pt, props.type_id,
1666                                                                 tvb, boffset, offset - boffset, (gchar *)octets);
1667                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1668                                                 }
1669                                         }
1670                                 }
1671                                 g_free(octets);
1672                                 g_free( (gpointer) ename);
1673                                 break;
1674                         }
1675                   } else {
1676                         /* indefinite length or constructed.... must be a sequence .... */
1677                         /* show full sequence length */
1678                         if (asn1_debug) {
1679                                 ename = empty;
1680                                 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1681                                         ename = ", noshow";
1682                                 if ( (props.flags & OUT_FLAG_constructed))
1683                                         ename = ", unexpected constructed";
1684
1685                                 if (props.value_id == -1)
1686                                       ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1687                                                                  textfmt_c, boffset, clsstr, constr,
1688                                                                  tagstr, tname, name, ename, empty);
1689                                 else {
1690                                       ti = proto_tree_add_item(pt, props.value_id, tvb,
1691                                                               boffset, 1, TRUE);
1692                                       /* change te text to to what I really want */
1693                                       if (ti) {
1694                                         proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1695                                                              tagstr, tname, name, ename, matchind);
1696                                         if (props.type_id != -1){
1697                                               hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1698                                                               boffset, 1, TRUE);
1699                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1700                                         }
1701                                       } else {
1702                                         ti = proto_tree_add_text(pt, tvb, boffset,
1703                                                                  offset - boffset + len,
1704                                                                  textfmt_c, boffset, clsstr, constr,
1705                                                                  tagstr, tname, name, ename, empty);
1706                                       }
1707                                 }
1708                         } else {
1709                                 if (props.value_id == -1) {
1710                                         if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1711                                                 ti = proto_tree_add_text(pt, tvb, boffset,
1712                                                          offset - boffset + len, "(%s)%s", tname, name);
1713                                 } else {
1714                                         if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1715                                                 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1716                                                                 boffset, 1,
1717                                                                 "(%s)%s ~", tname, name);
1718                                         else {
1719                                                 /* don't care about the text */
1720                                                 ti = proto_tree_add_item(pt, props.value_id,
1721                                                              tvb,  boffset, 1, TRUE);
1722                                                 PROTO_ITEM_SET_HIDDEN(ti);
1723                                         }
1724                                         if (props.type_id != -1){
1725                                                 hidden_item = proto_tree_add_item(pt, props.type_id,
1726                                                              tvb,  boffset, 1, TRUE);
1727                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1728                                         }
1729                                 }
1730                         }
1731
1732                         if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1733
1734                         if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1735                                 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1736                         else
1737                                 pt2 = pt;
1738
1739                         offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1740
1741                         if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1742                                 proto_item_set_len(ti, offset - boffset);
1743                   }
1744               break;
1745
1746             default:            /* fprintf(stderr, "Other\n"); */
1747                   if (asn1_debug) {
1748                           ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1749                                                    textfmt_s, boffset, clsstr, constr, tagstr,
1750                                                    tname, name, lenbuf, empty);
1751                   } else {
1752                           ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1753                                                    "(%s)%s: %s bytes %s data", tname, name,
1754                                                    lenbuf, clsstr);
1755                   }
1756                   proto_item_append_text(ti, " *"); /* indicate default is used */
1757                   offset += len; /* skip value ... */
1758                   break;
1759           }
1760           g_free(oname); /* XXX, memory management ? */
1761   }
1762   /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1763
1764   getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1765
1766   return offset;
1767 }
1768 #define READSYNTAX
1769 #ifdef READSYNTAX
1770
1771 /************************************************************************************************/
1772 /*  search throug the ASN.1 description for appropriate names                                   */
1773 /************************************************************************************************/
1774
1775 guint lev_limit = G_MAXINT;
1776
1777 int icount = 0;                 /* item counter */
1778
1779 static guint
1780 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1781 {
1782         ASN1_SCK asn1;
1783         guint eos, cls, con, tag, len, value;
1784         gboolean def;
1785         guchar *octets, *bits, unused;
1786         subid_t *oid;
1787         GNode *cur_node = 0;
1788
1789         eos = offset + size;
1790
1791         if (level > lev_limit)
1792                 return eos;
1793
1794         while(offset < eos) {
1795                 if (ptr)        /* build pointer tree to all asn1 entities */
1796                         cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
1797
1798                 asn1_open(&asn1, tvb, offset);
1799                 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1800                 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
1801                 icount++;
1802                 if (!def) {
1803                         len = tvb_length_remaining(tvb, offset);
1804                 }
1805
1806                 switch(cls) {
1807                 case BER_CLASS_UNI:     /* fprintf(stderr, "Universal\n"); */
1808                         switch(tag) {
1809                         case BER_UNI_TAG_INTEGER:
1810                         case BER_UNI_TAG_ENUMERATED:
1811                                 asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
1812                                 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
1813                                 break;
1814
1815                         case BER_UNI_TAG_BOOLEAN:
1816                                 asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1817                                 asn1_close(&asn1, &offset); /* mark where we are */
1818                                 break;
1819
1820                         case BER_UNI_TAG_OCTETSTRING:
1821                         case BER_UNI_TAG_NumericString:
1822                         case BER_UNI_TAG_PrintableString:
1823                         case BER_UNI_TAG_TeletexString:
1824                         case BER_UNI_TAG_IA5String:
1825                         case BER_UNI_TAG_GeneralString:
1826                         case BER_UNI_TAG_UTCTime:
1827                         case BER_UNI_TAG_GeneralizedTime:
1828                                 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1829                                 asn1_close(&asn1, &offset); /* mark where we are */
1830                                 g_free(octets);
1831                                 break;
1832
1833                         case BER_UNI_TAG_BITSTRING:
1834                                 asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1835                                 asn1_close(&asn1, &offset); /* mark where we are */
1836                                 g_free(bits);
1837                                 break;
1838
1839                         case BER_UNI_TAG_SET:
1840                         case BER_UNI_TAG_SEQUENCE:
1841                                 if (len == 0) /* don't recurse if offset isn't going to change */
1842                                         return offset;
1843
1844                                 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1845                                 break;
1846
1847                         case BER_UNI_TAG_EOC:
1848                                 return offset;
1849
1850                         case BER_UNI_TAG_OID:
1851                                 asn1_oid_value_decode(&asn1, len, &oid, &con);
1852                                 asn1_close(&asn1, &offset); /* mark where we are */
1853                                 g_free(oid);
1854                                 break;
1855
1856                         case BER_UNI_TAG_NULL:
1857                                 offset += len;
1858                                 break;
1859
1860                         case BER_UNI_TAG_ObjectDescriptor:
1861                         case ASN1_EXT:
1862                         case BER_UNI_TAG_REAL:
1863                         case BER_UNI_TAG_VideotexString:
1864                         case BER_UNI_TAG_GraphicString:
1865                         case BER_UNI_TAG_VisibleString:
1866
1867                         default:
1868                                 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1869                                 offset += len; /* skip value ... */
1870                                 break;
1871                         };
1872                         break;
1873
1874                 case BER_CLASS_CON:             /* fprintf(stderr, "Context\n"); */
1875                         if (def && !con) {
1876                                 /* defined length, not constructed, must be a string.... */
1877                                 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1878                                 asn1_close(&asn1, &offset); /* mark where we are */
1879                                 g_free(octets);
1880                         } else {
1881                                 /* indefinite length or constructed.... must be a sequence .... */
1882                                 if (len == 0) /* don't recurse if offset isn't going to change */
1883                                         return offset;
1884
1885                                 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1886                         }
1887                         break;
1888
1889                 default:                /* fprintf(stderr, "Other\n"); */
1890                         if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1891                         offset += len; /* skip value ... */
1892                         break;
1893                 }
1894         }
1895         return offset;
1896 }
1897
1898 static void showGNodes(GNode *p, int n);
1899
1900 #if 0
1901 static gboolean
1902 myLeaf(GNode *node, gpointer data)
1903 {
1904         ASN1_SCK asn1;
1905         guint ret, cls, con, tag, def, len;
1906         char *clsstr, *constr, *tagstr;
1907         char tagbuf[BUFLM];
1908         char lenbuf[BUFLM];
1909
1910         (void) data;                    /* make a reference */
1911         asn1_open(&asn1, asn1_desc, (int)node->data);
1912
1913         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1914
1915         clsstr = asn1_cls[cls];
1916         constr = asn1_con[con];
1917         if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
1918                 tagstr = asn1_tag[tag];
1919         } else {
1920                 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1921                 tagstr = tagbuf;
1922         }
1923         if (def) {
1924                 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1925         } else {
1926                 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1927         }
1928
1929         if (asn1_verbose)
1930                 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1931
1932         return FALSE;
1933 }
1934
1935 static void
1936 list_modules(void)
1937 {
1938         if (asn1_verbose) g_message("build GNode tree:");
1939         showGNodes(g_node_first_child(asn1_nodes), 0);
1940         if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1941                   g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1942                   g_node_max_height (asn1_nodes),
1943                   g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1944                   g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1945
1946         g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1947
1948 }
1949 #endif
1950
1951 static void
1952 tt_build_tree(void)             /* build a GNode tree with all offset's to ASN.1 entities */
1953 {
1954         if (asn1_nodes)
1955                 g_node_destroy(asn1_nodes);
1956         asn1_nodes = g_node_new(0);
1957         icount = 0;
1958         parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1959 }
1960
1961
1962 /*****************************************************************************************************/
1963
1964 static guint anonCount;  /* for naming anonymous types */
1965
1966 typedef struct _TBLModule       TBLModule;
1967 typedef struct _TBLTypeDef      TBLTypeDef;
1968 typedef struct _TBLTag          TBLTag;
1969 typedef struct _TBLType         TBLType;
1970 typedef struct _TBLTypeRef      TBLTypeRef;
1971 typedef struct _TBLNamedNumber  TBLNamedNumber;
1972 typedef struct _TBLRange        TBLRange;
1973
1974 enum _tbl_t {
1975         TBLTYPE_Module,
1976         TBLTYPE_TypeDef,
1977         TBLTYPE_Tag,
1978         TBLTYPE_Type,
1979         TBLTYPE_TypeRef,
1980         TBLTYPE_NamedNumber,
1981         TBLTYPE_Range
1982 };
1983 typedef enum _tbl_t tbl_t;
1984 /* text for 'tbl_t' type for debugging */
1985 static const char *data_types[] = {
1986                         "Module",
1987                         "TypeDef",
1988                         "Tag",
1989                         "Type",
1990                         "TypeRef",
1991                         "NamedNumber",
1992                         "Range",
1993 };
1994
1995 enum _TBLTypeContent_t {
1996         TBLTYPETYPE_None,
1997         TBLTYPETYPE_Primitive,
1998         TBLTYPETYPE_Elements,
1999         TBLTYPETYPE_TypeRef
2000 };
2001 typedef enum _TBLTypeContent_t TBLTypeContent_t;
2002
2003 struct _TBLNamedNumber {
2004         tbl_t   type;
2005         guchar  *name;
2006         guint   value;
2007 };
2008
2009 struct _TBLRange {
2010         tbl_t   type;
2011         guint   from;
2012         guint   to;
2013 };
2014
2015 struct _TBLTypeRef {
2016         tbl_t   type;
2017         guint   typeDefId;
2018         gboolean implicit;
2019 };
2020
2021 struct _TBLTag {
2022         tbl_t   type;
2023         guint   tclass;
2024         guint   code;
2025 };
2026
2027 struct _TBLType {
2028         tbl_t   type;
2029         guint   typeId;
2030         gboolean        optional;
2031         TBLTypeContent_t content;
2032         guchar  *fieldName;
2033         gboolean anonymous;
2034         gboolean constraint;
2035 };
2036
2037 struct _TBLTypeDef {
2038         tbl_t   type;
2039         guint   typeDefId;
2040         guchar  *typeName;
2041         guchar  isPdu;
2042 };
2043
2044 struct _TBLModule {
2045         tbl_t   type;
2046         guchar  *name;
2047         subid_t *id;
2048         guint   isUseful;
2049 };
2050
2051 struct _TT {
2052         guint   totalNumModules;
2053         guint   totalNumTypeDefs;
2054         guint   totalNumTypes;
2055         guint   totalNumTags;
2056         guint   totalNumStrings;
2057         guint   totalLenStrings;
2058 } TT;
2059
2060 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2061
2062 static guint
2063 get_asn1_int(guint want_tag, guint offset)
2064 {
2065         ASN1_SCK asn1;
2066         guint ret, cls, con, tag, len;
2067         gboolean def;
2068         guint value;
2069
2070         /* g_message("%d get_asn1_int", offset); */
2071
2072         asn1_open(&asn1, asn1_desc, offset);
2073
2074         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2075         if (ret == ASN1_ERR_NOERROR) {
2076                          /* do not check class, both Unversal and Context are OK */
2077                 if (con == ASN1_PRI && tag == want_tag) {
2078                         if (def) {
2079                                 asn1_uint32_value_decode(&asn1, len, &value);
2080                                 return value;
2081                         } else
2082                                 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2083                 } else
2084                         ret = ASN1_ERR_WRONG_TYPE;
2085         }
2086         g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2087
2088         return 0;
2089 }
2090
2091 static subid_t *                        /* with prepended length ..... */
2092 get_asn1_oid(guint want_tag, guint offset)
2093 {
2094         ASN1_SCK asn1;
2095         guint ret, cls, con, tag, len;
2096         gboolean def;
2097         subid_t *oid;
2098
2099         /* g_message("%d get_asn1_oid", offset); */
2100
2101         asn1_open(&asn1, asn1_desc, offset);
2102
2103         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2104         if (ret == ASN1_ERR_NOERROR) {
2105                         /* do not check class, both Unversal and Context are OK */
2106                 if ((con == ASN1_PRI) && (tag == want_tag))     {
2107                         if (def) {
2108                                 asn1_oid_value_decode(&asn1, len, &oid, &con);
2109                                 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2110                                 memmove(&oid[1], oid, con*sizeof(guint));
2111                                 oid[0] = con;
2112                                 return oid;
2113                         } else
2114                                 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2115                 } else
2116                         ret = ASN1_ERR_WRONG_TYPE;
2117         }
2118         g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2119
2120         return 0;
2121 }
2122
2123 static guchar *                 /* 0 terminated string */
2124 get_asn1_string(guint want_tag, guint offset)
2125 {
2126         ASN1_SCK asn1;
2127         guint ret, cls, con, tag, len;
2128         gboolean def;
2129         guchar *octets;
2130
2131         /* g_message("%d get_asn1_string", offset); */
2132
2133         asn1_open(&asn1, asn1_desc, offset);
2134
2135         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2136         if (ret == ASN1_ERR_NOERROR) {
2137                         /* do not check class, both Unversal and Context are OK */
2138                 if ((con == ASN1_PRI) && (tag == want_tag))     {
2139                         if (def) {
2140                                 asn1_string_value_decode(&asn1, len, &octets);
2141                                 octets = g_realloc(octets, len+1); /* need space for sentinel */
2142                                 octets[len] = 0;
2143                                 return octets;
2144                         } else
2145                                 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2146                 } else
2147                         ret = ASN1_ERR_WRONG_TYPE;
2148         }
2149         g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2150
2151         return 0;
2152 }
2153
2154 static guint
2155 get_asn1_uint(guint offset)
2156 {
2157         ASN1_SCK asn1;
2158         guint ret, len, value;
2159
2160         /* g_message( "%d get_asn1_uint", offset); */
2161
2162         asn1_open(&asn1, asn1_desc, offset);
2163
2164         ret = asn1_uint32_decode(&asn1, &value, &len);
2165
2166         if (ret != ASN1_ERR_NOERROR) {
2167                 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2168                 value = 0;
2169         }
2170         return value;
2171 }
2172
2173 static gboolean
2174 check_tag(guint want_tag, guint offset)
2175 {
2176         ASN1_SCK asn1;
2177         guint ret, cls, con, tag, len;
2178         gboolean def;
2179
2180         asn1_open(&asn1, asn1_desc, offset);
2181
2182         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2183         if (ret == ASN1_ERR_NOERROR) {
2184                 ret = (tag == want_tag) ? TRUE : FALSE;
2185                 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2186                 return ret;
2187         }
2188         g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2189
2190         return FALSE;
2191 }
2192
2193 #if 0
2194 static gboolean
2195 constructed(guint offset)
2196 {
2197         ASN1_SCK asn1;
2198         guint ret, cls, con, tag, def, len;
2199
2200         /* g_message("%d constructed?", offset); */
2201
2202         asn1_open(&asn1, asn1_desc, offset);
2203
2204         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2205         if (ret == ASN1_ERR_NOERROR) {
2206                 if (con) {
2207                         return TRUE;
2208                 }
2209                 return FALSE;
2210         }
2211         /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2212
2213         return FALSE;
2214 }
2215 #endif
2216
2217 static void
2218 define_constraint(GNode *p, GNode *q)
2219 {
2220         TBLRange *range = g_malloc(sizeof(TBLRange));
2221         g_node_append_data(q, range);
2222
2223         range->type = TBLTYPE_Range;
2224
2225         /* g_message("define_constraint %p, %p", p, q); */
2226
2227         p = g_node_first_child(p);
2228
2229         if (!p) {
2230                 return;
2231         }
2232
2233         range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2234         p = g_node_next_sibling(p);
2235
2236         if (!p) {
2237                 return;
2238         }
2239
2240         range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2241
2242 }
2243
2244 static void
2245 define_namednumber(GNode *p, GNode *q)
2246 {
2247         TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2248         g_node_append_data(q, num);
2249
2250         num->type = TBLTYPE_NamedNumber;
2251
2252         /* g_message("define_namednumber %p, %p", p, q); */
2253
2254         p = g_node_first_child(p);
2255
2256         if (!p) {
2257                 return;
2258         }
2259
2260         num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2261         p = g_node_next_sibling(p);
2262
2263         if (!p) {
2264                 return;
2265         }
2266
2267         num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2268 }
2269
2270 static void
2271 define_typeref(GNode *p, GNode *q)
2272 {
2273         TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2274         g_node_append_data(q, ref);
2275
2276         ref->type = TBLTYPE_TypeRef;
2277
2278         /* g_message("define_typeref %p, %p", p, q); */
2279
2280         p = g_node_first_child(p);
2281
2282         if (!p) {
2283                 return;
2284         }
2285
2286         ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2287         p = g_node_next_sibling(p);
2288
2289         if (!p) {
2290                 return;
2291         }
2292
2293         ref->implicit = get_asn1_int(BER_UNI_TAG_BOOLEAN, GPOINTER_TO_UINT(p->data));
2294 }
2295
2296 static void
2297 define_tag(GNode *p, GNode *q)
2298 {
2299         TBLTag *type = g_malloc(sizeof(TBLTag));
2300         g_node_append_data(q, type);
2301
2302         type->type = TBLTYPE_Tag;
2303
2304         /* g_message("define_tag %p, %p", p, q); */
2305
2306         p = g_node_first_child(p);
2307
2308         if (!p) {
2309                 return;
2310         }
2311
2312         type->tclass = get_asn1_int(BER_UNI_TAG_ENUMERATED, GPOINTER_TO_UINT(p->data));
2313         p = g_node_next_sibling(p);
2314
2315         if (!p) {
2316                 return;
2317         }
2318
2319         type->code = get_asn1_int(BER_UNI_TAG_INTEGER, GPOINTER_TO_UINT(p->data));
2320
2321 }
2322
2323 static void
2324 define_type(GNode *p, GNode *q)
2325 {
2326         GNode *r;
2327         TBLType *type = g_malloc(sizeof(TBLType));
2328
2329         GNode *t = g_node_append_data(q, type);
2330
2331         type->type = TBLTYPE_Type;
2332
2333         /* g_message("define_type %p, %p", p, q); */
2334
2335         type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2336         p = g_node_next_sibling(p);
2337
2338         type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2339         p = g_node_next_sibling(p);
2340
2341         if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
2342                 r = g_node_first_child(p);
2343                 while (r) {
2344                         define_tag(r, t);
2345                         r = g_node_next_sibling(r);
2346                 }
2347                 p = g_node_next_sibling(p);
2348         }
2349
2350         if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
2351                 g_warning("expect tag 3, ERROR");
2352         }
2353         r = g_node_first_child(p);
2354                 /* a choice ... */
2355         type->content = TBLTYPETYPE_None;
2356         if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
2357         if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
2358         if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
2359         switch(type->content) {
2360                 case TBLTYPETYPE_Primitive:
2361                         break;
2362                 case TBLTYPETYPE_Elements:
2363                         r = g_node_first_child(r);
2364                         while (r) {
2365                                 define_type(g_node_first_child(r), t);
2366                                 r = g_node_next_sibling(r);
2367                         }
2368                         break;
2369                 case TBLTYPETYPE_TypeRef:
2370                         define_typeref(r, t);
2371                         break;
2372                 case TBLTYPETYPE_None:
2373                         g_warning("expected a contents choice, error");
2374                         break;
2375         }
2376         p = g_node_next_sibling(p);
2377
2378         type->fieldName = 0;
2379         type->anonymous = FALSE;
2380         if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
2381                 type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
2382                 p = g_node_next_sibling(p);
2383         } else {
2384                 type->anonymous = TRUE;
2385         }
2386
2387         type->constraint = FALSE;
2388         if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
2389                 type->constraint = TRUE;
2390                 define_constraint(p, t);
2391                 p = g_node_next_sibling(p);
2392         }
2393
2394         if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
2395                 r =  g_node_first_child(p);
2396                 while(r) {
2397                         define_namednumber(r, t);
2398                         r = g_node_next_sibling(r);
2399                 }
2400         }
2401 }
2402
2403 static void
2404 define_typedef(GNode *p, GNode *q)
2405 {
2406         TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2407
2408         GNode *t = g_node_append_data(q, type_def);
2409
2410         /* g_message("define_typedef %p, %p", p, q); */
2411
2412         type_def->type = TBLTYPE_TypeDef;
2413
2414         p = g_node_first_child(p);
2415
2416         if (!p) {
2417                 return;
2418         }
2419
2420         type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2421         p = g_node_next_sibling(p);
2422
2423         if (!p) {
2424                 return;
2425         }
2426
2427         type_def->typeName = get_asn1_string(BER_UNI_TAG_PrintableString, GPOINTER_TO_UINT(p->data));
2428         p = g_node_next_sibling(p);
2429
2430         if (!p) {
2431                 return;
2432         }
2433
2434         define_type(g_node_first_child(p), t);
2435         p = g_node_next_sibling(p);
2436
2437         type_def->isPdu = (p != 0);  /* true if it exists, value ignored */
2438 }
2439
2440 static void
2441 define_module(GNode *p, GNode *q)
2442 {
2443         TBLModule *module = g_malloc(sizeof(TBLModule));
2444
2445         GNode *m = g_node_append_data(q, module);
2446
2447         /* g_message("define_module %p %p", p, q); */
2448
2449         module->type = TBLTYPE_Module;
2450
2451         p = g_node_first_child(p);
2452         
2453         if (!p) {
2454                 return;
2455         }
2456
2457         module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2458         p = g_node_next_sibling(p);
2459
2460         module->id = 0;
2461         if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */
2462                 module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
2463                 p = g_node_next_sibling(p);
2464         }
2465
2466         module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
2467         p = g_node_next_sibling(p);
2468
2469         p = g_node_first_child(p);
2470         while (p) {
2471                 define_typedef(p, m);
2472                 p = g_node_next_sibling(p);
2473         }
2474 }
2475
2476 typedef struct _SearchDef SearchDef;
2477 struct _SearchDef {
2478         const char *key;
2479         GNode *here;
2480 };
2481
2482 static gboolean
2483 is_typedef(GNode *node, gpointer data)
2484 {
2485         TBLTypeDef *d = (TBLTypeDef *)node->data;
2486         SearchDef *s = (SearchDef *)data;
2487
2488         if (d == 0) return FALSE;
2489         if (d->type != TBLTYPE_TypeDef) return FALSE;
2490         if (strcmp(s->key, d->typeName) == 0) {
2491                 s->here = node;
2492                 return TRUE;
2493         }
2494         return FALSE;
2495 }
2496
2497 typedef struct _TypeRef TypeRef;
2498 struct _TypeRef {
2499         GNode *type;
2500         char *name;
2501         guchar defclass;
2502         guint deftag;
2503         GNode *pdu;             /* location in PDU descriptor tree */
2504         guint level;            /* recursion counter */
2505         GNode *typetree;
2506         GPtrArray *refs;        /* pointers to PDUinfo structures teferencing this entry */
2507 };
2508
2509 typedef struct _NameDefs NameDefs;
2510 struct _NameDefs {
2511         guint max;
2512         guint used;
2513         TypeRef *info;
2514 };
2515 #define ALLOC_INCR 4
2516 #define CLASSREF (BER_CLASS_PRI+1)
2517
2518 static gboolean
2519 is_named(GNode *node, gpointer data)
2520 {
2521         TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2522         NameDefs *n = (NameDefs *)data;
2523         guint oldmax;
2524
2525         if (num == 0) return FALSE;
2526         if (num->type != TBLTYPE_NamedNumber) return FALSE;
2527
2528         if (num->value >= n->max) { /* need larger array */
2529                 oldmax = n->max;
2530                 n->max = num->value + ALLOC_INCR;
2531                 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2532                 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2533         }
2534         if (num->value > n->used)  /* track max used value, there may be holes... */
2535                 n->used = num->value;
2536
2537         n->info[num->value].name = num->name;
2538
2539         return FALSE;
2540 }
2541
2542 static gboolean
2543 index_typedef(GNode *node, gpointer data)
2544 {
2545         TBLTypeDef *d = (TBLTypeDef *)node->data;
2546         NameDefs *n = (NameDefs *)data;
2547         TypeRef *t;
2548         TBLTag *tag;
2549         guint oldmax;
2550
2551         if (d == 0) return FALSE;
2552         if (d->type != TBLTYPE_TypeDef) return FALSE;
2553
2554         if (d->typeDefId >= n->max) { /* need larger array */
2555                 oldmax = n->max;
2556                 n->max = d->typeDefId + ALLOC_INCR;
2557                 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2558                 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2559         }
2560         if (d->typeDefId > n->used)  /* track max used value, there may be holes... */
2561                 n->used = d->typeDefId;
2562
2563         t = &(n->info[d->typeDefId]);
2564         t->name = d->typeName;
2565         t->type = node;
2566         t->refs = g_ptr_array_new();    /* collect references here */
2567         node = g_node_first_child(node); /* the real type */
2568         tag = (TBLTag *)node->data;
2569         if ((tag->type == TBLTYPE_Type) && (((TBLType *)(void *)tag)->typeId == TBL_CHOICE)) {
2570                 /* no reasonable default... ! */
2571                 t->defclass = 3; /* Private .... */
2572                 t->deftag= 9999; /* a random value */
2573         } else {
2574                 node = g_node_first_child(node); /* the default tag */
2575                 tag = (TBLTag *)node->data;
2576                 switch(tag->type) {
2577                 case TBLTYPE_Tag:
2578                         t->defclass = tag->tclass;
2579                         t->deftag = tag->code;
2580                         break;
2581                 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2582                         t->defclass = CLASSREF; /* invalid class.. */
2583                         t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2584                         break;
2585                 default:
2586                         g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2587                                         data_types[tag->type]);
2588                         t->defclass = 3; /* Private .... */
2589                         t->deftag= 9998; /* another random value */
2590                         break;
2591                 }
2592         }
2593
2594         return FALSE;
2595 }
2596
2597 static TypeRef *typeDef_names = 0;
2598 static guint numTypedefs = 0;
2599
2600 static gboolean
2601 free_node_data(GNode *node, gpointer data _U_)
2602 {
2603         g_free(node->data);
2604         return FALSE;
2605 }
2606
2607 static void
2608 get_values(void)                /* collect values from ASN.1 tree */
2609                                 /* coded according to the tbl.asn1 description of snacc output */
2610 {                               /* This routine does not leave references to the tvbuff or */
2611                                 /* to the asn1_nodes, both can be freed by the caller of this.*/
2612         GNode *p;
2613         SearchDef sd;
2614         NameDefs nd;
2615         guint i;
2616         char X;
2617         const char *t, *s, *E;
2618         static char missing[] = "  **missing**  ";
2619
2620         if (asn1_verbose) g_message("interpreting tree");
2621         typeDef_names = 0;  /* just forget allocated any data .... */
2622
2623         if (data_nodes) {
2624                 g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2625                     free_node_data, NULL);
2626                 g_node_destroy(data_nodes);
2627         }
2628
2629         data_nodes = g_node_new(0);
2630
2631         p = g_node_first_child(asn1_nodes); /* top of the data tree */
2632
2633         p = g_node_first_child(p);
2634         if (!p) return;
2635         TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2636         p = g_node_next_sibling(p);
2637         if (!p) return;
2638         TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2639         p = g_node_next_sibling(p);
2640         if (!p) return;
2641         TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2642         p = g_node_next_sibling(p);
2643         if (!p) return;
2644         TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2645         p = g_node_next_sibling(p);
2646         if (!p) return;
2647         TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2648         p = g_node_next_sibling(p);
2649         if (!p) return;
2650         TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2651         p = g_node_next_sibling(p);
2652
2653         p = g_node_first_child(p);
2654         while (p) {
2655                 define_module(p, data_nodes);
2656                 p = g_node_next_sibling(p);
2657         }
2658
2659         /* g_message("finished with tree"); */
2660
2661         if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2662                 sd.key = "TBLTypeId";
2663                 sd.here = 0;
2664                 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2665                 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", (void *)sd.here);
2666                 if (sd.here) {
2667                         nd.max = 8;
2668                         nd.used = 0;
2669                         nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2670                         g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2671                                                 (gpointer)&nd);
2672                         if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, (void *)nd.info);
2673                         E = empty;
2674                         for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2675                                 X = 'X';
2676                                 t = TBLTYPE(i);
2677                                 s = nd.info[i].name;
2678                                 if (s == 0) s = missing;
2679                                 if (g_strcmp(t, s) == 0) { /* OK ! */
2680                                         X = ' ';
2681                                         t = empty;
2682                                 } else {
2683                                         E = ", X  with errors  X";
2684                                 }
2685                                 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2686                         }
2687                         if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2688                 }
2689                 tbl_types_verified = TRUE;
2690         }
2691         /* build table with typedef names */
2692         nd.max = 8;
2693         nd.used = 0;
2694         nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2695         g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2696         if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, (void *)nd.info);
2697
2698         for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2699