MSWSP: add ids for another unknown Property Set
[wireshark-wip.git] / plugins / asn1 / packet-asn1.c
blobcbd02b3460c425bf752d0e201092cd4d85307653
1 /******************************************************************************************************/
2 /* packet-asn1.c
4 * Copyright (c) 2003 by Matthijs Melchior <matthijs.melchior@xs4all.nl>
6 * $Id$
8 * A plugin for:
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1999 Gerald Combs
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
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.
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
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.
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.
60 /* Include files */
62 #include "config.h"
64 #include <errno.h>
66 #include <ctype.h>
67 #include <string.h>
69 #include <glib.h>
70 #include <glib/gprintf.h>
72 #include <wsutil/report_err.h>
73 #include <wsutil/file_util.h>
75 #include <epan/packet.h>
76 #include <epan/exceptions.h>
77 #include <epan/addr_resolv.h>
78 #include <epan/prefs.h>
79 #include <epan/filesystem.h>
80 #include <epan/dissectors/packet-tcp.h>
81 #include <epan/oids.h>
82 #include <epan/emem.h>
83 #include <plugins/asn1/asn1.h>
85 #ifdef DISSECTOR_WITH_GUI
86 #include <gtk/gtk.h>
87 #endif
89 #include <epan/ipproto.h>
91 /* buffer lengths */
92 #define BUFLS 32
93 #define BUFLM 64
94 #define BUFLL 128
96 /* Define default ports */
98 #define TCP_PORT_ASN1 0
99 #define UDP_PORT_ASN1 0
100 #define SCTP_PORT_ASN1 0
102 void proto_reg_handoff_asn1(void);
104 /* Define the asn1 proto */
106 static int proto_asn1 = -1;
108 /* Define the tree for asn1*/
110 static int ett_asn1 = -1;
112 #define MAXPDU 64 /* max # PDU's in one packet */
113 static int ett_pdu[MAXPDU];
115 #define MAX_NEST 32 /* max nesting level for ASN.1 elements */
116 static int ett_seq[MAX_NEST];
119 * Global variables associated with the preferences for asn1
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 */
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;
151 #define ASN1LOGFILE "wireshark.log"
153 /* PDU counter, for correlation between GUI display and log file in debug mode */
154 static int pcount = 0;
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 */
161 static guint PDUerrcount = 0; /* count of parse errors in one ASN.1 message */
163 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
166 static char pabbrev[] = "asn1"; /* field prefix */
168 static char fieldname[512]; /* for constructing full names */
169 static guint pabbrev_pdu_len; /* length initial part of fieldname with 'abbrev.asn1pdu.' */
172 * Text strings describing the standard, universal, ASN.1 names.
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 */
178 static const char tag_class[] = "UACPX";
180 static const char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
182 static const char *asn1_con[] = { "Primitive", "Constructed" };
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*/
197 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
198 static gboolean tbl_types_verified = FALSE;
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,
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 */
223 TBL_INVALID /* incorrect value for this enum */
224 } TBLTypeId;
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,
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 */
250 /* XXX - Should we use val_to_str here? */
251 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
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",
270 /* 14 */ "tbl-sequenceof-start",
271 /* 15 */ "tbl-typeref-nopop",
272 /* 16 */ "tbl-choice-done",
273 /* 17 */ "tbl-reserved",
274 /* 18 */ "tbl-choice-immediate",
276 /* 19 */ "tbl-invalid",
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",
294 /* 14 */ "start-SEQUENCE OF",
295 /* 15 */ "TYPEREF nopop",
296 /* 16 */ "CHOICE done",
297 /* 17 */ "Reserved",
298 /* 18 */ "CHOICE immediate",
300 /* 19 */ "INVALID entry",
302 /* conversion from snacc type to appropriate wireshark type */
303 static enum ftenum 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 */
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 */
325 /* 19 */ FT_NONE, /* TBL_INVALID */
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 */
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 */
351 /* 19 */ BASE_NONE, /* TBL_INVALID */
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 */
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 */
376 /* 19 */ "FT_NONE", /* TBL_INVALID */
379 typedef struct _PDUinfo PDUinfo;
380 struct _PDUinfo {
381 guint type;
382 const char *name;
383 const char *asn1typename;
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 */
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
407 #define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
409 static guint PDUinfo_initflags = 0; /* default flags for newly allocated PDUinfo structs */
411 /* description of PDU properties as passed from the matching routine
412 * to the decoder and GUI.
414 typedef struct _PDUprops PDUprops;
415 struct _PDUprops {
416 guint type; /* value from enum TBLTypeId */
417 const char *name;
418 const char *asn1typename;
419 const char *fullname;
420 guint flags;
421 gpointer data;
422 gint value_id;
423 gint type_id;
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
433 static PDUprops *getPDUprops(PDUprops *out, guint offset, guint cls, guint tag, guint cons);
434 static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
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 */
440 #undef NEST /* show nesting of asn.1 enties */
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];
450 static char *showtaglist(guint level)
452 static char tagtxt[BUFLM];
453 guint i;
454 int idx;
456 idx = 0;
457 #ifdef ALLTAGS
458 for(i=0; i<= level; i++) {
459 switch(taglist[i].cls) {
460 case BER_CLASS_UNI:
461 idx += g_snprintf(&tagtxt[idx], BUFLM - idx, "U");
462 break;
463 case BER_CLASS_APP:
464 idx += g_snprintf(&tagtxt[idx], BUFLM - idx, "A");
465 break;
466 case BER_CLASS_CON:
467 idx += g_snprintf(&tagtxt[idx], BUFLM - idx, "C");
468 break;
469 case BER_CLASS_PRI:
470 idx += g_snprintf(&tagtxt[idx], BUFLM - idx, "P");
471 break;
472 default:
473 idx += g_snprintf(&tagtxt[idx], BUFLM - idx, "x");
474 break;
476 idx += g_snprintf(&tagtxt[idx], BUFLM - idx, "%d.", taglist[i].tag);
478 #else /* only context tags */
479 idx += g_snprintf(&tagtxt[idx], BUFLM - idx, "C");
480 for(i=0; i<= level; i++) {
481 if (taglist[i].cls == BER_CLASS_CON) {
482 idx += g_snprintf(&tagtxt[idx], BUFLM - idx, "%d.", taglist[i].tag);
485 #endif
486 idx--;
487 tagtxt[idx] = '\0'; /* remove trailing '.' */
488 return tagtxt;
491 static guint
492 get_context(guint level)
494 guint ctx = 0;
495 guint i;
497 for(i=0; i<=level; i++) {
498 if (taglist[i].cls == BER_CLASS_CON)
499 ctx = (ctx << 8) | taglist[i].tag;
501 return ctx;
503 #endif /* NEST, only for debugging */
506 /* Convert a bit string to an ascii representation for printing
507 * -- not thread safe ...
509 static const char *showbits(guchar *val, guint count)
511 static char str[BUFLM];
512 guint i;
513 char *p = str;
515 if (count > 32)
516 return "*too many bits*";
518 if (val != 0) {
519 for(i=0; i<count; i++) {
520 if (i && ((i & 7) == 0)) *p++ = ' ';
521 *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
524 *p = 0;
525 return str;
528 /* get bitnames string for bits set */
529 static const char *
530 showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
532 static char str[BUFLL];
533 guint i;
534 int idx;
536 if (props->flags & OUT_FLAG_noname)
537 return empty;
539 if (count > 32)
540 return "*too many bits, no names...*";
542 idx = 0;
543 if (val != NULL) {
544 for(i=0; i<count; i++) {
545 if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
546 idx += g_snprintf(&str[idx], BUFLL-idx, "%s,", getPDUenum(props, offset, 0, 0, i));
549 if (idx > 0)
550 --idx; /* remove terminating , */
552 str[idx] = '\0';
553 return str;
558 /* Convert an oid to its conventional text representation
559 * -- not thread safe...
561 static char *showoid(subid_t *oid, guint len)
563 static char str[BUFLM];
564 guint i;
565 int idx;
567 idx = 0;
568 if (oid != NULL) {
569 for(i=0; i<len; i++) {
570 if (i)
571 idx += g_snprintf(&str[idx], BUFLM - idx, ".");
572 idx += g_snprintf(&str[idx], BUFLM - idx, "%lu", (unsigned long)oid[i]);
575 str[idx] = '\0';
576 return str;
579 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
580 static char *
581 showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
583 guint dohex = 0;
584 guint i;
585 char *str;
586 int idx;
587 const char *endstr = empty;
589 if (len == 0) {
590 str = (char *)g_malloc(1);
591 str[0] = 0;
592 } else {
593 for (i=0; i<len; i++) {
594 if (!isprint(octets[i])) /* maybe isblank() as well ... */
595 dohex++;
597 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
598 len = MAX_OTSLEN;
599 endstr = "...."; /* this is 5 bytes !! */
601 if (dohex) {
602 str = (char *)g_malloc(len*2 + 5);
603 idx = 0;
604 for (i=0; i<len; i++) {
605 idx += g_snprintf(&str[idx], len*2 - idx, "%2.2X", octets[i]);
607 g_snprintf(&str[idx], len*2 + 5 - idx, "%s", endstr);
608 } else {
609 if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
610 str = (char *)g_malloc(len*3+2);
611 idx = 0;
612 for (i=0; i<len; i++) {
613 idx += g_snprintf(&str[idx], len*3 - idx, "%2.2X", octets[i]);
615 g_snprintf(&str[idx], len*3+2 - idx, " %s", octets);
616 } else {
617 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
618 str = (char *)g_malloc(len+5);
619 g_snprintf(str, len*3+5, " %s%s", octets, endstr);
623 return str;
626 /* allow NULL pointers in strcmp, handle them as empty strings */
627 static int
628 g_strcmp(gconstpointer a, gconstpointer b)
630 if (a == 0) a = empty;
631 if (b == 0) b = empty;
632 return strcmp((const char *)a, (const char *)b);
635 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
636 /* WARNING WARNING WARNING WARNING WARNING WARNING */
637 /* */
638 /* Most of the following routine is guesswork in order to */
639 /* speed up resynchronisation if the dissector lost the */
640 /* encoding due to incomplete captures, or a capture that */
641 /* starts in the middle of a fragmented ip packet */
642 /* If this poses to many problems, these settings can be */
643 /* made part of the protocol settings in the user interface */
644 /*************************************************************/
646 /* check length for a reasonable value, return a corrected value */
647 static int
648 checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
650 int newlen = len;
652 if ( ! def) {
653 g_snprintf(lenstr, strmax, "indefinite");
654 return len;
657 if (len < 0) /* negative ..... */
658 newlen = 4;
660 if (cls != BER_CLASS_UNI) { /* don't know about the tags */
661 if (len > 131071)
662 newlen = 64;
663 } else {
664 switch (tag) {
665 case BER_UNI_TAG_EOC: /* End Of Contents */
666 case BER_UNI_TAG_NULL: /* Null */
667 newlen = 0;
668 break;
669 case BER_UNI_TAG_BOOLEAN: /* Boolean */
670 newlen = 1;
671 break;
672 case BER_UNI_TAG_INTEGER: /* Integer */
673 case BER_UNI_TAG_ENUMERATED: /* Enumerated */
674 if (len > 8)
675 newlen = 4;
676 break;
677 case BER_UNI_TAG_BITSTRING: /* Bit String */
678 if (len > 8)
679 newlen = 4;
680 break;
681 case BER_UNI_TAG_OCTETSTRING: /* Octet String */
682 case BER_UNI_TAG_NumericString: /* Numerical String */
683 case BER_UNI_TAG_PrintableString: /* Printable String */
684 case BER_UNI_TAG_TeletexString: /* Teletext String */
685 case BER_UNI_TAG_VideotexString: /* Video String */
686 case BER_UNI_TAG_IA5String: /* IA5 String */
687 case BER_UNI_TAG_GraphicString: /* Graphical String */
688 case BER_UNI_TAG_VisibleString: /* Visible String */
689 case BER_UNI_TAG_GeneralString: /* General String */
690 if (len > 65535)
691 newlen = 32;
692 break;
693 case BER_UNI_TAG_OID: /* Object Identifier */
694 case BER_UNI_TAG_ObjectDescriptor: /* Description */
695 case ASN1_EXT: /* External */
696 if (len > 64)
697 newlen = 16;
698 break;
699 case BER_UNI_TAG_REAL: /* Real */
700 if (len >16)
701 newlen = 8;
702 break;
703 case BER_UNI_TAG_SEQUENCE: /* Sequence */
704 case BER_UNI_TAG_SET: /* Set */
705 if (len > 65535)
706 newlen = 64;
707 break;
708 case BER_UNI_TAG_UTCTime: /* Universal Time */
709 case BER_UNI_TAG_GeneralizedTime: /* General Time */
710 if (len > 32)
711 newlen = 15;
712 break;
714 default:
715 if (len > 131071)
716 newlen = 64;
717 break;
721 if (newlen != len) {
722 /* a change was needed.... */
723 g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
724 } else {
725 g_snprintf(lenstr, strmax, "%d", len);
727 return newlen;
730 static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
731 static void PDUreset(int count, int counr2);
733 static int
734 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) {
736 ASN1_SCK asn1;
737 guint cls, con, tag, len, offset, reassembled;
738 gboolean def;
739 char lenstr[BUFLS];
740 char tagstr[BUFLS];
741 char headstr[BUFLL];
742 char offstr[BUFLS];
743 const char *name, *tname;
744 volatile guint boffset;
745 volatile int i = 0; /* PDU counter */
746 proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
747 proto_item *hidden_item;
748 PDUprops props;
749 static guint lastseq;
750 struct tcpinfo *info;
751 gint delta;
753 pcount++;
754 boffset = 0;
756 reassembled = 1; /* UDP is not a stream, and thus always reassembled .... */
757 if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
758 info = (struct tcpinfo *)data;
759 delta = info->seq - lastseq;
760 reassembled = info->is_reassembled;
761 lastseq = info->seq;
763 if (asn1_verbose)
764 g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
765 info->seq, delta, reassembled);
766 } else {
767 if (asn1_verbose)
768 g_message("dissect_asn1: udp");
771 /* Set the protocol column */
772 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
774 col_clear(pinfo->cinfo, COL_INFO);
777 offstr[0] = 0;
778 if ((first_pdu_offset > 0) && !reassembled) {
779 boffset = first_pdu_offset;
780 g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
783 /* open BER decoding */
784 asn1_open(&asn1, tvb, boffset);
786 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
788 asn1_close(&asn1, &offset);
790 PDUreset(pcount, 0); /* arguments are just for debugging */
791 getPDUprops(&props, boffset, cls, tag, con);
792 name = props.name;
793 tname = props.asn1typename;
795 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
797 if (asn1_debug) {
799 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
801 g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
802 offstr,
803 tname,
804 name,
805 pcount,
806 asn1_cls[cls],
807 asn1_con[con],
808 ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
809 lenstr,
810 boffset,
811 tvb_length(tvb)
813 } else {
814 if (props.flags & OUT_FLAG_noname) {
815 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
816 name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
818 g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
821 /* Set the info column */
822 col_add_str(pinfo->cinfo, COL_INFO, headstr );
825 * If we have a non-null tree (ie we are building the proto_tree
826 * instead of just filling out the columns ), then add a BER
827 * tree node
830 /* ignore the tree here, must decode BER to know how to reassemble!! */
831 /* if(tree) { */
833 TRY { /* catch incomplete PDU's */
835 ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
836 def? (int) (offset - boffset + len) : -1,
837 "ASN.1 %s", current_pduname);
839 tree2 = proto_item_add_subtree(ti, ett_asn1);
841 switch (((PDUinfo *)PDUtree->data)->type) {
843 case TBL_BOOLEAN:
844 case TBL_INTEGER:
845 case TBL_BITSTRING:
846 case TBL_REAL:
847 case TBL_ENUMERATED:
848 hidden_item = proto_tree_add_item(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
849 def? (int) (offset - boffset + len) : -1, ENC_LITTLE_ENDIAN);
850 break;
852 case TBL_OCTETSTRING:
853 hidden_item = proto_tree_add_item(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
854 def? (int) (offset - boffset + len) : -1, ENC_ASCII|ENC_NA);
855 break;
857 default:
858 hidden_item = proto_tree_add_item(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
859 def? (int) (offset - boffset + len) : -1, ENC_NA);
860 break;
862 PROTO_ITEM_SET_HIDDEN(hidden_item);
864 offset = boffset; /* the first packet */
865 while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
866 ti2 = 0;
867 boffset = offset;
868 /* open BER decoding */
869 asn1_open(&asn1, tvb, offset);
870 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
871 asn1_close(&asn1, &offset);
873 PDUreset(pcount, i+1);
874 getPDUprops(&props, boffset, cls, tag, con);
875 name = props.name;
876 tname = props.asn1typename;
878 if (!def)
879 len = tvb_length_remaining(tvb, offset);
881 len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
883 if (asn1_debug) {
885 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
887 g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
888 asn1_cls[cls],
889 asn1_con[con],
890 ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
891 lenstr,
892 boffset,
893 tvb_length_remaining(tvb, offset) );
895 if (props.value_id == -1)
896 ti2 = proto_tree_add_text(tree2, tvb, boffset,
897 def? (int) (offset - boffset + len) : -1,
898 "%s: (%s)%s %d-%d %s", current_pduname,
899 tname, name, pcount, i+1, headstr);
900 else {
901 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
902 def? (int) (offset - boffset + len) : -1,
903 "%s: (%s)%s %d-%d %s ~", current_pduname,
904 tname, name, pcount, i+1, headstr);
906 if (props.type_id != -1){
907 switch (proto_registrar_get_ftype(props.type_id)) {
909 case FT_INT8:
910 case FT_INT16:
911 case FT_INT24:
912 case FT_INT32:
913 case FT_INT64:
914 case FT_UINT8:
915 case FT_UINT16:
916 case FT_UINT24:
917 case FT_UINT32:
918 case FT_UINT64:
919 case FT_BOOLEAN:
920 case FT_FLOAT:
921 case FT_DOUBLE:
922 case FT_IPv4:
923 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
924 def? (int) (offset - boffset + len) : -1, ENC_LITTLE_ENDIAN);
925 break;
927 case FT_STRING:
928 case FT_STRINGZ:
929 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
930 def? (int) (offset - boffset + len) : -1, ENC_ASCII|ENC_NA);
931 break;
933 default:
934 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
935 def? (int) (offset - boffset + len) : -1, ENC_NA);
936 break;
938 PROTO_ITEM_SET_HIDDEN(hidden_item);
941 } else {
942 if (props.flags & OUT_FLAG_noname) {
943 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
944 name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
946 if (props.value_id == -1)
947 ti2 = proto_tree_add_text(tree2, tvb, boffset,
948 def? (int) (offset - boffset + len) : -1,
949 "%s: (%s)%s", current_pduname, tname, name);
950 else {
951 ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
952 def? (int) (offset - boffset + len) : -1,
953 "%s: (%s)%s ~", current_pduname, tname, name);
954 if (props.type_id != -1){
955 switch (proto_registrar_get_ftype(props.type_id)) {
957 case FT_INT8:
958 case FT_INT16:
959 case FT_INT24:
960 case FT_INT32:
961 case FT_INT64:
962 case FT_UINT8:
963 case FT_UINT16:
964 case FT_UINT24:
965 case FT_UINT32:
966 case FT_UINT64:
967 case FT_BOOLEAN:
968 case FT_FLOAT:
969 case FT_DOUBLE:
970 case FT_IPv4:
971 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
972 def? (int) (offset - boffset + len) : -1, ENC_LITTLE_ENDIAN);
973 break;
975 case FT_STRING:
976 case FT_STRINGZ:
977 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
978 def? (int) (offset - boffset + len) : -1, ENC_ASCII|ENC_NA);
979 break;
981 default:
982 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
983 def? (int) (offset - boffset + len) : -1, ENC_NA);
984 break;
986 PROTO_ITEM_SET_HIDDEN(hidden_item);
990 asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
992 #ifdef NEST
993 taglist[0].cls = cls;
994 taglist[0].tag = tag;
995 #endif /* NEST */
997 if (!def) len++; /* make sure we get an exception if we run off the end! */
999 offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
1001 proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
1003 i++; /* one more full message handled */
1005 if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
1006 proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
1008 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
1009 if (ti)
1010 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
1012 CATCH(ReportedBoundsError) {
1013 col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
1014 if (ti)
1015 proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
1016 if (ti2)
1017 proto_item_append_text(ti2, " (incomplete)");
1018 if (asn1_desegment) {
1019 pinfo->desegment_offset = boffset;
1020 pinfo->desegment_len = 1;
1021 if (asn1_verbose)
1022 g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
1023 boffset, 1, pinfo->can_desegment);
1024 } else {
1025 RETHROW;
1028 ENDTRY;
1029 /* } */
1030 if (asn1_verbose)
1031 g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
1032 pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
1034 return tvb_length(tvb);
1037 /* decode an ASN.1 sequence, until we have consumed the specified length */
1038 static guint
1039 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
1041 ASN1_SCK asn1;
1042 guint ret, cls, con, tag, len, boffset, soffset, eos;
1043 gboolean def;
1044 guint value;
1045 const char *clsstr, *constr, *tagstr;
1046 char tagbuf[BUFLM];
1047 char lenbuf[BUFLM];
1048 char nnbuf[BUFLS];
1049 proto_tree *ti, *pt2;
1050 proto_item *hidden_item;
1051 guchar *octets, *bits, unused;
1052 subid_t *oid;
1053 /* the debugging formats */
1054 static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s"; /* decimal */
1055 static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s"; /* enum */
1056 static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s"; /* octet string */
1057 static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s"; /* bit field */
1058 static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s"; /* constructed */
1059 static char matchind[] = " ~"; /* indication of possible match */
1060 const char *name, *ename, *tname;
1061 char *oname;
1062 PDUprops props;
1064 ti = 0; /* suppress gcc warning */
1066 soffset = offset; /* where this sequence starts */
1067 eos = offset + tlen;
1068 while (offset < eos) { /* while this entity has not ended... */
1069 boffset = offset;
1070 asn1_open(&asn1, tvb, offset);
1071 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1072 asn1_close(&asn1, &offset); /* mark current position */
1073 if (ret != ASN1_ERR_NOERROR) {
1074 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
1075 break;
1078 getPDUprops(&props, boffset, cls, tag, con);
1079 name = props.name;
1080 tname = props.asn1typename;
1081 if (asn1_full)
1082 name = &props.fullname[pabbrev_pdu_len]; /* no abbrev.pduname */
1083 if (asn1_debug) { /* show both names */
1084 g_snprintf(fieldname, sizeof(fieldname), "%s[%s]", props.name, props.fullname);
1085 name = fieldname;
1088 clsstr = asn1_cls[cls];
1089 constr = asn1_con[con];
1090 if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
1091 tagstr = asn1_tag[tag];
1092 } else {
1093 g_snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
1094 tagstr = tagbuf;
1097 len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
1099 if (def) {
1100 g_snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
1101 } else {
1102 g_snprintf(nnbuf, sizeof(nnbuf), "NN-");
1103 /* make sure we get an exception if we run off the end! */
1104 len = tvb_length_remaining(tvb, offset) + 1;
1106 if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
1107 /* just give type name if we don't know any better */
1108 tname = tagstr;
1109 name = nnbuf; /* this is better than just empty.... */
1112 #ifdef NEST
1113 taglist[level].cls = cls;
1114 taglist[level].tag = tag;
1115 #endif /* NEST */
1117 oname = 0;
1118 if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
1119 cls = BER_CLASS_UNI;
1120 tag = BER_UNI_TAG_GeneralString;
1121 oname = (char *)g_malloc(strlen(name) + 32);
1122 g_snprintf(oname, (gulong)(strlen(name) + 32), "%s ** nesting cut off **", name);
1123 name = oname;
1125 switch(cls) {
1126 case BER_CLASS_UNI: /* fprintf(stderr, "Universal\n"); */
1127 switch(tag) {
1128 case BER_UNI_TAG_INTEGER:
1129 asn1_int32_value_decode(&asn1, len, &value); /* read value */
1130 asn1_close(&asn1, &offset); /* mark where we are now */
1131 if (asn1_debug) {
1132 if ( (props.value_id == -1) ||
1133 (tbl_types_wireshark[props.type] != FT_UINT32) )
1134 /* unknown or unexpected: just text */
1135 proto_tree_add_text(pt, tvb, boffset,
1136 offset - boffset, textfmt_d, boffset,
1137 clsstr, constr, tagstr, tname, name, value,
1138 empty);
1139 else {
1140 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1141 offset - boffset, value, textfmt_d, boffset,
1142 clsstr, constr, tagstr, tname, name, value,
1143 matchind);
1144 if (props.type_id != -1) {
1145 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1146 boffset, offset - boffset, value);
1147 PROTO_ITEM_SET_HIDDEN(hidden_item);
1150 } else {
1151 if ( (props.value_id == -1) ||
1152 (tbl_types_wireshark[props.type] != FT_UINT32) )
1153 /* unknown or unexpected, just text */
1154 proto_tree_add_text(pt, tvb, boffset,
1155 offset - boffset,
1156 "(%s)%s: %d", tname, name, value);
1157 else {
1158 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1159 offset - boffset, value,
1160 "(%s)%s: %d ~", tname, name, value);
1161 if (props.type_id != -1){
1162 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1163 boffset, offset - boffset, value);
1164 PROTO_ITEM_SET_HIDDEN(hidden_item);
1168 break;
1170 case BER_UNI_TAG_ENUMERATED:
1171 asn1_int32_value_decode(&asn1, len, &value); /* read value */
1172 asn1_close(&asn1, &offset); /* mark where we are now */
1173 ename = getPDUenum(&props, boffset, cls, tag, value);
1174 if (asn1_debug) {
1175 if ( (props.value_id == -1) ||
1176 (tbl_types_wireshark[props.type] != FT_UINT32) )
1177 /* unknown or unexpected, just text */
1178 proto_tree_add_text(pt, tvb, boffset,
1179 offset - boffset,
1180 textfmt_e, boffset, clsstr, constr, tagstr,
1181 tname, name, value, ename, empty);
1182 else {
1183 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1184 offset - boffset, value,
1185 textfmt_e, boffset, clsstr, constr, tagstr,
1186 tname, name, value, ename, matchind);
1187 if (props.type_id != -1){
1188 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1189 boffset, offset - boffset, value);
1190 PROTO_ITEM_SET_HIDDEN(hidden_item);
1193 } else {
1194 if ( (props.value_id == -1) ||
1195 (tbl_types_wireshark[props.type] != FT_UINT32) )
1196 /* unknown or unexpected, just text */
1197 proto_tree_add_text(pt, tvb, boffset,
1198 offset - boffset,
1199 "(%s)%s: %d:%s", tname, name, value, ename);
1200 else {
1201 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1202 offset - boffset, value,
1203 "(%s)%s: %d:%s ~", tname, name, value, ename);
1204 if (props.type_id != -1){
1205 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1206 boffset, offset - boffset, value);
1207 PROTO_ITEM_SET_HIDDEN(hidden_item);
1211 break;
1213 case BER_UNI_TAG_BOOLEAN:
1214 asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1215 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1216 if (asn1_debug) {
1217 if ( (props.value_id == -1) ||
1218 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1219 /* unknown or unexpected, just text */
1220 proto_tree_add_text(pt, tvb, boffset,
1221 offset - boffset,
1222 textfmt_s, boffset, clsstr, constr, tagstr,
1223 tname, name, value? "true" : "false", empty);
1224 else {
1225 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1226 offset - boffset, value != 0,
1227 textfmt_s, boffset, clsstr, constr, tagstr,
1228 tname, name, value? "true" : "false", matchind);
1229 if (props.type_id != -1){
1230 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1231 boffset, offset - boffset, value != 0);
1232 PROTO_ITEM_SET_HIDDEN(hidden_item);
1235 } else {
1236 if ( (props.value_id == -1) ||
1237 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1238 /* unknown or unexpected, just text */
1239 proto_tree_add_text(pt, tvb, boffset,
1240 offset - boffset,
1241 "(%s)%s: %s", tname, name,
1242 value? "true" : "false");
1243 else {
1244 proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1245 offset - boffset, value != 0,
1246 "(%s)%s: %s ~", tname, name,
1247 value? "true" : "false");
1248 if (props.type_id != -1){
1249 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1250 boffset, offset - boffset, value != 0);
1251 PROTO_ITEM_SET_HIDDEN(hidden_item);
1255 break;
1257 case BER_UNI_TAG_OCTETSTRING:
1258 case BER_UNI_TAG_NumericString:
1259 case BER_UNI_TAG_PrintableString:
1260 case BER_UNI_TAG_TeletexString:
1261 case BER_UNI_TAG_IA5String:
1262 case BER_UNI_TAG_GeneralString:
1263 case BER_UNI_TAG_UTCTime:
1264 case BER_UNI_TAG_GeneralizedTime:
1265 /* read value, \0 terminated */
1266 asn1_string_value_decode(&asn1, len, &octets);
1267 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1268 ename = showoctets(octets, len, (tag == BER_UNI_TAG_OCTETSTRING) ? 4 : 0 );
1269 if (asn1_debug) {
1270 if ( (props.value_id == -1) ||
1271 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1272 /* unknown or unexpected, just text */
1273 proto_tree_add_text(pt, tvb, boffset,
1274 offset - boffset,
1275 textfmt_s, boffset, clsstr, constr, tagstr,
1276 tname, name, ename, empty);
1277 else {
1278 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1279 offset - boffset, octets, /* \0 termnated */
1280 textfmt_s, boffset, clsstr, constr, tagstr,
1281 tname, name, ename, matchind);
1282 if (props.type_id != -1){
1283 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1284 boffset, offset - boffset, octets);
1285 PROTO_ITEM_SET_HIDDEN(hidden_item);
1288 } else {
1289 if ( (props.value_id == -1) ||
1290 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1291 /* unknown or unexpected, just text */
1292 proto_tree_add_text(pt, tvb, boffset,
1293 offset - boffset,
1294 "(%s)%s: %s", tname, name, ename);
1295 else {
1296 proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1297 offset - boffset, octets, /* \0 terminated */
1298 "(%s)%s: %s ~", tname, name, ename);
1299 if (props.type_id != -1){
1300 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1301 boffset, offset - boffset, octets);
1302 PROTO_ITEM_SET_HIDDEN(hidden_item);
1306 g_free(octets);
1307 g_free( (gpointer) ename);
1308 break;
1310 case BER_UNI_TAG_BITSTRING:
1311 asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1312 asn1_close(&asn1, &offset); /* mark where we are now */
1313 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1314 if (asn1_debug) {
1315 if ( (props.value_id == -1) ||
1316 (tbl_types_wireshark[props.type] != FT_UINT32) )
1317 /* unknown or unexpected, just text */
1318 proto_tree_add_text(pt, tvb, boffset,
1319 offset - boffset,
1320 textfmt_b, boffset, clsstr, constr, tagstr,
1321 tname, name,
1322 showbits(bits, (con*8)-unused), ename, empty);
1323 else {
1324 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1325 offset - boffset, *bits, /* XXX length ? XXX */
1326 textfmt_b, boffset, clsstr, constr, tagstr,
1327 tname, name,
1328 showbits(bits, (con*8)-unused),ename, matchind);
1329 if (props.type_id != -1){
1330 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1331 boffset, offset - boffset, *bits);
1332 PROTO_ITEM_SET_HIDDEN(hidden_item);
1336 } else {
1337 if ( (props.value_id == -1) ||
1338 (tbl_types_wireshark[props.type] != FT_UINT32) )
1339 /* unknown or unexpected, just text */
1340 proto_tree_add_text(pt, tvb, boffset,
1341 offset - boffset,
1342 "(%s)%s: %s:%s", tname, name,
1343 showbits(bits, (con*8)-unused), ename);
1344 else {
1345 proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1346 offset - boffset, *bits, /* XXX length ? XXX */
1347 "(%s)%s: %s:%s ~", tname, name,
1348 showbits(bits, (con*8)-unused), ename);
1349 if (props.type_id != -1){
1350 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1351 boffset, offset - boffset, *bits);
1352 PROTO_ITEM_SET_HIDDEN(hidden_item);
1356 g_free(bits);
1357 break;
1359 case BER_UNI_TAG_SET:
1360 case BER_UNI_TAG_SEQUENCE:
1361 /* show full sequence length */
1362 if (asn1_debug) {
1363 ename = empty;
1364 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1365 ename = ", noshow";
1366 if ( (props.flags & OUT_FLAG_constructed))
1367 ename = ", unexpected constructed";
1369 if (props.value_id == -1)
1370 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1371 textfmt_c, boffset, clsstr, constr, tagstr,
1372 tname, name, ename, empty);
1373 else {
1374 switch (props.type) {
1376 case TBL_BOOLEAN:
1377 case TBL_INTEGER:
1378 case TBL_BITSTRING:
1379 case TBL_REAL:
1380 case TBL_ENUMERATED:
1381 ti = proto_tree_add_item(pt, props.value_id, tvb,
1382 boffset, 1, ENC_LITTLE_ENDIAN);
1383 break;
1385 case TBL_OCTETSTRING:
1386 ti = proto_tree_add_item(pt, props.value_id, tvb,
1387 boffset, 1, ENC_ASCII|ENC_NA);
1388 break;
1390 default:
1391 ti = proto_tree_add_item(pt, props.value_id, tvb,
1392 boffset, 1, ENC_NA);
1393 break;
1395 /* change te text to to what I really want */
1396 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1397 tagstr, tname, name, ename, matchind);
1398 if (props.type_id != -1){
1399 switch (proto_registrar_get_ftype(props.type_id)) {
1401 case FT_INT8:
1402 case FT_INT16:
1403 case FT_INT24:
1404 case FT_INT32:
1405 case FT_INT64:
1406 case FT_UINT8:
1407 case FT_UINT16:
1408 case FT_UINT24:
1409 case FT_UINT32:
1410 case FT_UINT64:
1411 case FT_BOOLEAN:
1412 case FT_FLOAT:
1413 case FT_DOUBLE:
1414 case FT_IPv4:
1415 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1416 boffset, 1, ENC_LITTLE_ENDIAN);
1417 break;
1419 case FT_STRING:
1420 case FT_STRINGZ:
1421 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1422 boffset, 1, ENC_ASCII|ENC_NA);
1423 break;
1425 default:
1426 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1427 boffset, 1, ENC_NA);
1428 break;
1430 PROTO_ITEM_SET_HIDDEN(hidden_item);
1433 } else {
1434 if (props.value_id == -1) {
1435 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1436 ti = proto_tree_add_text(pt, tvb, boffset,
1437 offset - boffset + len,
1438 "(%s)%s", tname, name);
1439 } else {
1440 if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1441 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1442 boffset, offset - boffset + len,
1443 "(%s)%s ~", tname, name);
1444 else {
1445 /* don't care about the text */
1446 switch (props.type) {
1448 case TBL_BOOLEAN:
1449 case TBL_INTEGER:
1450 case TBL_BITSTRING:
1451 case TBL_REAL:
1452 case TBL_ENUMERATED:
1453 ti = hidden_item = proto_tree_add_item(pt, props.value_id, tvb,
1454 boffset, 1, ENC_LITTLE_ENDIAN);
1455 break;
1457 case TBL_OCTETSTRING:
1458 ti = hidden_item = proto_tree_add_item(pt, props.value_id, tvb,
1459 boffset, 1, ENC_ASCII|ENC_NA);
1460 break;
1462 default:
1463 ti = hidden_item = proto_tree_add_item(pt, props.value_id, tvb,
1464 boffset, 1, ENC_NA);
1465 break;
1467 PROTO_ITEM_SET_HIDDEN(hidden_item);
1469 if (props.type_id != -1){
1470 switch (proto_registrar_get_ftype(props.type_id)) {
1472 case FT_INT8:
1473 case FT_INT16:
1474 case FT_INT24:
1475 case FT_INT32:
1476 case FT_INT64:
1477 case FT_UINT8:
1478 case FT_UINT16:
1479 case FT_UINT24:
1480 case FT_UINT32:
1481 case FT_UINT64:
1482 case FT_BOOLEAN:
1483 case FT_FLOAT:
1484 case FT_DOUBLE:
1485 case FT_IPv4:
1486 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1487 boffset, 1, ENC_LITTLE_ENDIAN);
1488 break;
1490 case FT_STRING:
1491 case FT_STRINGZ:
1492 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1493 boffset, 1, ENC_ASCII|ENC_NA);
1494 break;
1496 default:
1497 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1498 boffset, 1, ENC_NA);
1499 break;
1501 PROTO_ITEM_SET_HIDDEN(hidden_item);
1505 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1507 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1508 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1509 else
1510 pt2 = pt;
1512 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1514 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1515 proto_item_set_len(ti, offset - boffset);
1517 break;
1519 case BER_UNI_TAG_EOC:
1520 if (asn1_debug) { /* don't show if not debugging */
1521 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1522 boffset, clsstr, constr, tagstr, tname, name,
1523 offset - soffset, empty);
1525 getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1526 return offset;
1528 case BER_UNI_TAG_OID:
1529 asn1_oid_value_decode(&asn1, len, &oid, &con);
1530 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1531 ename = showoid(oid, con);
1532 if (asn1_debug) {
1533 if ( (props.value_id == -1) ||
1534 (tbl_types_wireshark[props.type] != FT_BYTES) )
1535 /* unknown or unexpected, just text */
1536 proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1537 boffset, clsstr, constr, tagstr, tname, name,
1538 ename, empty);
1539 else {
1540 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1541 offset - boffset, ename,/* XXX length?*/
1542 "(%s)%s: %s ~", tname, name, ename);
1543 if (props.type_id != -1){
1544 hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1545 boffset, offset - boffset, ename);
1546 PROTO_ITEM_SET_HIDDEN(hidden_item);
1549 } else {
1550 if ( (props.value_id == -1) ||
1551 (tbl_types_wireshark[props.type] != FT_BYTES) )
1552 /* unknown or unexpected, just text */
1553 proto_tree_add_text(pt, tvb, boffset,
1554 offset - boffset,
1555 "(%s)%s: %s", tname, name, ename);
1556 else {
1557 proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1558 offset - boffset, ename, /* XXX length ? */
1559 "(%s)%s: %s ~", tname, name, ename);
1560 if (props.type_id != -1){
1561 hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1562 boffset, offset - boffset, ename);
1563 PROTO_ITEM_SET_HIDDEN(hidden_item);
1567 g_free(oid);
1568 break;
1570 case BER_UNI_TAG_NULL:
1571 if (asn1_debug) {
1572 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1573 boffset, clsstr, constr, tagstr, tname, name,
1574 "[NULL]", empty);
1575 } else {
1576 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1577 "(%s)%s: [NULL]", tname, name);
1579 offset += len; /* skip value ... */
1580 break;
1582 case BER_UNI_TAG_ObjectDescriptor:
1583 case ASN1_EXT:
1584 case BER_UNI_TAG_REAL:
1585 case BER_UNI_TAG_VideotexString:
1586 case BER_UNI_TAG_GraphicString:
1587 case BER_UNI_TAG_VisibleString:
1589 default:
1590 if (asn1_debug) {
1591 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1592 textfmt_s, boffset, clsstr, constr, tagstr,
1593 tname, name, lenbuf, empty);
1594 } else {
1595 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1596 "(%s)%s: %s bytes", tname, name, lenbuf);
1598 proto_item_append_text(ti, " *"); /* indicate default is used */
1599 offset += len; /* skip value ... */
1600 break;
1602 break;
1604 case BER_CLASS_CON: /* fprintf(stderr, "Context\n"); */
1605 case BER_CLASS_APP: /* fprintf(stderr, "Application\n"); */
1606 case BER_CLASS_PRI: /* fprintf(stderr, "Private\n"); */
1608 if (def && !con) {
1609 if (props.value_id == -1) /* type unknown, handle as string */
1610 goto dostring;
1611 switch(props.type) {
1612 /* this is via the asn1 description, don't trust the length */
1613 case TBL_INTEGER:
1614 if (len > 4)
1615 goto dostring;
1616 asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
1617 asn1_close(&asn1, &offset); /* mark where we are now */
1618 if (asn1_debug) {
1619 if ( (props.value_id == -1) ||
1620 (tbl_types_wireshark[props.type] != FT_UINT32) )
1621 /* unknown or unexpected, just text */
1622 proto_tree_add_text(pt, tvb,
1623 boffset, offset - boffset,
1624 textfmt_d, boffset, clsstr, constr,
1625 tagstr, tname, name, value, empty);
1626 else {
1627 proto_tree_add_uint_format(pt, props.value_id, tvb,
1628 boffset, offset - boffset, value,
1629 textfmt_d, boffset, clsstr, constr,
1630 tagstr, tname, name, value, matchind);
1631 if (props.type_id != -1){
1632 hidden_item = proto_tree_add_uint(pt, props.type_id,
1633 tvb, boffset, offset - boffset, value);
1634 PROTO_ITEM_SET_HIDDEN(hidden_item);
1637 } else {
1638 if ( (props.value_id == -1) ||
1639 (tbl_types_wireshark[props.type] != FT_UINT32) )
1640 /* unknown or unexpected, just text */
1641 proto_tree_add_text(pt, tvb,
1642 boffset, offset - boffset,
1643 "(%s)%s: %d", tname, name, value);
1644 else {
1645 proto_tree_add_uint_format(pt, props.value_id, tvb,
1646 boffset, offset - boffset, value,
1647 "(%s)%s: %d ~", tname, name, value);
1648 if (props.type_id != -1){
1649 hidden_item = proto_tree_add_uint(pt, props.type_id,
1650 tvb, boffset, offset - boffset, value);
1651 PROTO_ITEM_SET_HIDDEN(hidden_item);
1655 break;
1657 case TBL_ENUMERATED:
1658 if (len > 4)
1659 goto dostring;
1660 asn1_int32_value_decode(&asn1, len, &value); /* read value */
1661 asn1_close(&asn1, &offset); /* mark where we are now */
1662 ename = getPDUenum(&props, boffset, cls, tag, value);
1663 if (asn1_debug) {
1664 if ( (props.value_id == -1) ||
1665 (tbl_types_wireshark[props.type] != FT_UINT32) )
1666 /* unknown or unexpected, just text */
1667 proto_tree_add_text(pt, tvb,
1668 boffset, offset - boffset,
1669 textfmt_e, boffset, clsstr, constr,
1670 tagstr, tname, name, value, ename, empty);
1671 else {
1672 proto_tree_add_uint_format(pt, props.value_id, tvb,
1673 boffset, offset - boffset, value,
1674 textfmt_e, boffset, clsstr, constr,
1675 tagstr, tname, name, value, ename, matchind);
1676 if (props.type_id != -1){
1677 hidden_item = proto_tree_add_uint(pt, props.type_id,
1678 tvb, boffset, offset - boffset, value);
1679 PROTO_ITEM_SET_HIDDEN(hidden_item);
1682 } else {
1683 if ( (props.value_id == -1) ||
1684 (tbl_types_wireshark[props.type] != FT_UINT32) )
1685 /* unknown or unexpected, just text */
1686 proto_tree_add_text(pt, tvb,
1687 boffset, offset - boffset,
1688 "(%s)%s: %d:%s", tname, name, value, ename);
1689 else {
1690 proto_tree_add_uint_format(pt, props.value_id, tvb,
1691 boffset, offset - boffset, value,
1692 "(%s)%s: %d:%s ~", tname, name, value, ename);
1693 if (props.type_id != -1){
1694 hidden_item = proto_tree_add_uint(pt, props.type_id,
1695 tvb, boffset, offset - boffset, value);
1696 PROTO_ITEM_SET_HIDDEN(hidden_item);
1700 break;
1701 case TBL_BITSTRING:
1702 if (len > (1+4)) /* max 32 bits ...?.. */
1703 goto dostring;
1704 /* read value */
1705 asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1706 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1707 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1708 if (asn1_debug) {
1709 if ( (props.value_id == -1) ||
1710 (tbl_types_wireshark[props.type] != FT_UINT32) )
1711 /* unknown or unexpected, just text */
1712 proto_tree_add_text(pt, tvb,
1713 boffset, offset - boffset,
1714 textfmt_b, boffset, clsstr, constr,
1715 tagstr, tname, name,
1716 showbits(bits, (con*8)-unused), ename,
1717 empty);
1718 else {
1719 proto_tree_add_uint_format(pt, props.value_id, tvb,
1720 boffset, offset - boffset, *bits,
1721 textfmt_b, boffset, clsstr, constr,
1722 tagstr, tname, name,
1723 showbits(bits, (con*8)-unused), ename,
1724 matchind);
1725 if (props.type_id != -1){
1726 hidden_item = proto_tree_add_uint(pt, props.type_id,
1727 tvb, boffset, offset - boffset, *bits);
1728 PROTO_ITEM_SET_HIDDEN(hidden_item);
1731 } else {
1732 if ( (props.value_id == -1) ||
1733 (tbl_types_wireshark[props.type] != FT_UINT32) )
1734 /* unknown or unexpected, just text */
1735 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1736 "(%s)%s: %s:%s", tname, name,
1737 showbits(bits, (con*8)-unused), ename);
1738 else {
1739 proto_tree_add_uint_format(pt, props.value_id, tvb,
1740 boffset, offset - boffset, *bits,
1741 "(%s)%s: %s:%s ~", tname, name,
1742 showbits(bits, (con*8)-unused), ename);
1743 if (props.type_id != -1){
1744 hidden_item = proto_tree_add_uint(pt, props.type_id,
1745 tvb, boffset, offset - boffset, *bits);
1746 PROTO_ITEM_SET_HIDDEN(hidden_item);
1750 g_free(bits);
1751 break;
1752 case TBL_BOOLEAN:
1753 if (len > 1)
1754 goto dostring;
1755 asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1756 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1757 if (asn1_debug) {
1758 if ( (props.value_id == -1) ||
1759 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1760 /* unknown or unexpected, just text */
1761 proto_tree_add_text(pt, tvb,
1762 boffset, offset - boffset,
1763 textfmt_s, boffset, clsstr, constr,
1764 tagstr, tname, name,
1765 value? "true" : "false", empty);
1766 else {
1767 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1768 boffset, offset - boffset, value != 0,
1769 textfmt_s, boffset, clsstr, constr,
1770 tagstr, tname, name,
1771 value? "true" : "false", matchind);
1772 if (props.type_id != -1){
1773 hidden_item = proto_tree_add_boolean(pt, props.type_id,
1774 tvb, boffset, offset - boffset, value != 0);
1775 PROTO_ITEM_SET_HIDDEN(hidden_item);
1778 } else {
1779 if ( (props.value_id == -1) ||
1780 (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1781 /* unknown or unexpected, just text */
1782 proto_tree_add_text(pt, tvb,
1783 boffset, offset - boffset,
1784 "(%s)%s: %s", tname, name,
1785 value? "true" : "false");
1786 else {
1787 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1788 boffset, offset - boffset, value != 0,
1789 "(%s)%s: %s ~", tname, name,
1790 value? "true" : "false");
1791 if (props.type_id != -1){
1792 hidden_item = proto_tree_add_boolean(pt, props.type_id,
1793 tvb, boffset, offset - boffset, value != 0);
1794 PROTO_ITEM_SET_HIDDEN(hidden_item);
1798 break;
1799 case TBL_NULL:
1800 if (len > 0)
1801 goto dostring;
1802 if (asn1_debug) {
1803 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1804 textfmt_s, boffset, clsstr, constr,
1805 tagstr, tname, name, "[NULL]", empty);
1806 } else {
1807 proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1808 "(%s)%s: [NULL]", tname, name);
1810 offset += len; /* skip value ... */
1811 break;
1812 default:
1813 dostring:
1814 props.value_id = -1; /* unlikely this is correct, dont use it */
1815 /* fallthrough */
1816 case TBL_OCTETSTRING:
1817 /* defined length, not constructed, must be a string.... */
1818 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1819 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1820 ename = showoctets(octets, len, 2); /* convert octets to printable */
1821 if (asn1_debug) {
1822 if ( (props.value_id == -1) ||
1823 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1824 /* unknown or unexpected, just text */
1825 proto_tree_add_text(pt, tvb,
1826 boffset, offset - boffset,
1827 textfmt_s, boffset, clsstr, constr,
1828 tagstr, tname, name, ename, empty);
1829 else {
1830 proto_tree_add_string_format(pt, props.value_id, tvb,
1831 boffset, offset - boffset, (gchar *)octets, /* XXX */
1832 textfmt_s, boffset, clsstr, constr,
1833 tagstr, tname, name, ename, matchind);
1834 if (props.type_id != -1){
1835 hidden_item = proto_tree_add_string(pt, props.type_id,
1836 tvb, boffset, offset - boffset, (gchar *)octets);
1837 PROTO_ITEM_SET_HIDDEN(hidden_item);
1840 } else {
1841 if ( (props.value_id == -1) ||
1842 (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1843 /* unknown or unexpected, just text */
1844 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1845 "(%s)%s: %s", tname, name, ename);
1846 else {
1847 proto_tree_add_string_format(pt, props.value_id, tvb,
1848 boffset, offset - boffset, (gchar *)octets, /* XXX */
1849 "(%s)%s: %s ~", tname, name, ename);
1850 if (props.type_id != -1){
1851 hidden_item = proto_tree_add_string(pt, props.type_id,
1852 tvb, boffset, offset - boffset, (gchar *)octets);
1853 PROTO_ITEM_SET_HIDDEN(hidden_item);
1857 g_free(octets);
1858 g_free( (gpointer) ename);
1859 break;
1861 } else {
1862 /* indefinite length or constructed.... must be a sequence .... */
1863 /* show full sequence length */
1864 if (asn1_debug) {
1865 ename = empty;
1866 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1867 ename = ", noshow";
1868 if ( (props.flags & OUT_FLAG_constructed))
1869 ename = ", unexpected constructed";
1871 if (props.value_id == -1)
1872 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1873 textfmt_c, boffset, clsstr, constr,
1874 tagstr, tname, name, ename, empty);
1875 else {
1876 switch (props.type) {
1878 case TBL_BOOLEAN:
1879 case TBL_INTEGER:
1880 case TBL_BITSTRING:
1881 case TBL_REAL:
1882 case TBL_ENUMERATED:
1883 ti = proto_tree_add_item(pt, props.value_id, tvb,
1884 boffset, 1, ENC_LITTLE_ENDIAN);
1885 break;
1887 case TBL_OCTETSTRING:
1888 ti = proto_tree_add_item(pt, props.value_id, tvb,
1889 boffset, 1, ENC_ASCII|ENC_NA);
1890 break;
1892 default:
1893 ti = proto_tree_add_item(pt, props.value_id, tvb,
1894 boffset, 1, ENC_NA);
1895 break;
1897 /* change te text to to what I really want */
1898 if (ti) {
1899 proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1900 tagstr, tname, name, ename, matchind);
1901 if (props.type_id != -1){
1902 switch (proto_registrar_get_ftype(props.type_id)) {
1904 case FT_INT8:
1905 case FT_INT16:
1906 case FT_INT24:
1907 case FT_INT32:
1908 case FT_INT64:
1909 case FT_UINT8:
1910 case FT_UINT16:
1911 case FT_UINT24:
1912 case FT_UINT32:
1913 case FT_UINT64:
1914 case FT_BOOLEAN:
1915 case FT_FLOAT:
1916 case FT_DOUBLE:
1917 case FT_IPv4:
1918 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1919 boffset, 1, ENC_LITTLE_ENDIAN);
1920 break;
1922 case FT_STRING:
1923 case FT_STRINGZ:
1924 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1925 boffset, 1, ENC_ASCII|ENC_NA);
1926 break;
1928 default:
1929 hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1930 boffset, 1, ENC_NA);
1931 break;
1933 PROTO_ITEM_SET_HIDDEN(hidden_item);
1935 } else {
1936 ti = proto_tree_add_text(pt, tvb, boffset,
1937 offset - boffset + len,
1938 textfmt_c, boffset, clsstr, constr,
1939 tagstr, tname, name, ename, empty);
1942 } else {
1943 if (props.value_id == -1) {
1944 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1945 ti = proto_tree_add_text(pt, tvb, boffset,
1946 offset - boffset + len, "(%s)%s", tname, name);
1947 } else {
1948 if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1949 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1950 boffset, 1,
1951 "(%s)%s ~", tname, name);
1952 else {
1953 /* don't care about the text */
1954 switch (props.type) {
1956 case TBL_BOOLEAN:
1957 case TBL_INTEGER:
1958 case TBL_BITSTRING:
1959 case TBL_REAL:
1960 case TBL_ENUMERATED:
1961 ti = proto_tree_add_item(pt, props.value_id,
1962 tvb, boffset, 1, ENC_LITTLE_ENDIAN);
1963 break;
1965 case TBL_OCTETSTRING:
1966 ti = proto_tree_add_item(pt, props.value_id,
1967 tvb, boffset, 1, ENC_ASCII|ENC_NA);
1968 break;
1970 default:
1971 ti = proto_tree_add_item(pt, props.value_id,
1972 tvb, boffset, 1, ENC_NA);
1973 break;
1975 PROTO_ITEM_SET_HIDDEN(ti);
1977 if (props.type_id != -1){
1978 switch (proto_registrar_get_ftype(props.type_id)) {
1980 case FT_INT8:
1981 case FT_INT16:
1982 case FT_INT24:
1983 case FT_INT32:
1984 case FT_INT64:
1985 case FT_UINT8:
1986 case FT_UINT16:
1987 case FT_UINT24:
1988 case FT_UINT32:
1989 case FT_UINT64:
1990 case FT_BOOLEAN:
1991 case FT_FLOAT:
1992 case FT_DOUBLE:
1993 case FT_IPv4:
1994 hidden_item = proto_tree_add_item(pt, props.type_id,
1995 tvb, boffset, 1, ENC_LITTLE_ENDIAN);
1996 break;
1998 case FT_STRING:
1999 case FT_STRINGZ:
2000 hidden_item = proto_tree_add_item(pt, props.type_id,
2001 tvb, boffset, 1, ENC_ASCII|ENC_NA);
2002 break;
2004 default:
2005 hidden_item = proto_tree_add_item(pt, props.type_id,
2006 tvb, boffset, 1, ENC_NA);
2007 break;
2009 PROTO_ITEM_SET_HIDDEN(hidden_item);
2014 if (len == 0) return offset; /* don't recurse if offset isn't going to change */
2016 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
2017 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
2018 else
2019 pt2 = pt;
2021 offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
2023 if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
2024 proto_item_set_len(ti, offset - boffset);
2026 break;
2028 default: /* fprintf(stderr, "Other\n"); */
2029 if (asn1_debug) {
2030 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
2031 textfmt_s, boffset, clsstr, constr, tagstr,
2032 tname, name, lenbuf, empty);
2033 } else {
2034 ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
2035 "(%s)%s: %s bytes %s data", tname, name,
2036 lenbuf, clsstr);
2038 proto_item_append_text(ti, " *"); /* indicate default is used */
2039 offset += len; /* skip value ... */
2040 break;
2042 g_free(oname); /* XXX, memory management ? */
2044 /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
2046 getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
2048 return offset;
2050 #define READSYNTAX
2051 #ifdef READSYNTAX
2053 /************************************************************************************************/
2054 /* search throug the ASN.1 description for appropriate names */
2055 /************************************************************************************************/
2057 guint lev_limit = G_MAXINT;
2059 int icount = 0; /* item counter */
2061 static guint
2062 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
2064 ASN1_SCK asn1;
2065 guint eos, cls, con, tag, len, value;
2066 gboolean def;
2067 guchar *octets, *bits, unused;
2068 subid_t *oid;
2069 GNode *cur_node = 0;
2071 eos = offset + size;
2073 if (level > lev_limit)
2074 return eos;
2076 while(offset < eos) {
2077 if (ptr) /* build pointer tree to all asn1 entities */
2078 cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
2080 asn1_open(&asn1, tvb, offset);
2081 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2082 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
2083 icount++;
2084 if (!def) {
2085 len = tvb_length_remaining(tvb, offset);
2088 switch(cls) {
2089 case BER_CLASS_UNI: /* fprintf(stderr, "Universal\n"); */
2090 switch(tag) {
2091 case BER_UNI_TAG_INTEGER:
2092 case BER_UNI_TAG_ENUMERATED:
2093 asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
2094 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
2095 break;
2097 case BER_UNI_TAG_BOOLEAN:
2098 asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
2099 asn1_close(&asn1, &offset); /* mark where we are */
2100 break;
2102 case BER_UNI_TAG_OCTETSTRING:
2103 case BER_UNI_TAG_NumericString:
2104 case BER_UNI_TAG_PrintableString:
2105 case BER_UNI_TAG_TeletexString:
2106 case BER_UNI_TAG_IA5String:
2107 case BER_UNI_TAG_GeneralString:
2108 case BER_UNI_TAG_UTCTime:
2109 case BER_UNI_TAG_GeneralizedTime:
2110 asn1_string_value_decode(&asn1, len, &octets); /* read value */
2111 asn1_close(&asn1, &offset); /* mark where we are */
2112 g_free(octets);
2113 break;
2115 case BER_UNI_TAG_BITSTRING:
2116 asn1_bits_decode(&asn1, len, &bits, &con, &unused);
2117 asn1_close(&asn1, &offset); /* mark where we are */
2118 g_free(bits);
2119 break;
2121 case BER_UNI_TAG_SET:
2122 case BER_UNI_TAG_SEQUENCE:
2123 if (len == 0) /* don't recurse if offset isn't going to change */
2124 return offset;
2126 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
2127 break;
2129 case BER_UNI_TAG_EOC:
2130 return offset;
2132 case BER_UNI_TAG_OID:
2133 asn1_oid_value_decode(&asn1, len, &oid, &con);
2134 asn1_close(&asn1, &offset); /* mark where we are */
2135 g_free(oid);
2136 break;
2138 case BER_UNI_TAG_NULL:
2139 offset += len;
2140 break;
2142 case BER_UNI_TAG_ObjectDescriptor:
2143 case ASN1_EXT:
2144 case BER_UNI_TAG_REAL:
2145 case BER_UNI_TAG_VideotexString:
2146 case BER_UNI_TAG_GraphicString:
2147 case BER_UNI_TAG_VisibleString:
2149 default:
2150 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
2151 offset += len; /* skip value ... */
2152 break;
2154 break;
2156 case BER_CLASS_CON: /* fprintf(stderr, "Context\n"); */
2157 if (def && !con) {
2158 /* defined length, not constructed, must be a string.... */
2159 asn1_string_value_decode(&asn1, len, &octets); /* read value */
2160 asn1_close(&asn1, &offset); /* mark where we are */
2161 g_free(octets);
2162 } else {
2163 /* indefinite length or constructed.... must be a sequence .... */
2164 if (len == 0) /* don't recurse if offset isn't going to change */
2165 return offset;
2167 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
2169 break;
2171 default: /* fprintf(stderr, "Other\n"); */
2172 if (asn1_verbose) g_message("%d skip2 %d", offset, len);
2173 offset += len; /* skip value ... */
2174 break;
2177 return offset;
2180 static void showGNodes(GNode *p, int n);
2182 #if 0
2183 static gboolean
2184 myLeaf(GNode *node, gpointer data)
2186 ASN1_SCK asn1;
2187 guint ret, cls, con, tag, def, len;
2188 char *clsstr, *constr, *tagstr;
2189 char tagbuf[BUFLM];
2190 char lenbuf[BUFLM];
2192 (void) data; /* make a reference */
2193 asn1_open(&asn1, asn1_desc, (int)node->data);
2195 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2197 clsstr = asn1_cls[cls];
2198 constr = asn1_con[con];
2199 if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
2200 tagstr = asn1_tag[tag];
2201 } else {
2202 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
2203 tagstr = tagbuf;
2205 if (def) {
2206 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
2207 } else {
2208 g_snprintf(lenbuf, sizeof(lenbuf), "indefinite");
2211 if (asn1_verbose)
2212 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
2214 return FALSE;
2217 static void
2218 list_modules(void)
2220 if (asn1_verbose) g_message("build GNode tree:");
2221 showGNodes(g_node_first_child(asn1_nodes), 0);
2222 if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
2223 g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
2224 g_node_max_height (asn1_nodes),
2225 g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
2226 g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
2228 g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
2231 #endif
2233 static void
2234 tt_build_tree(void) /* build a GNode tree with all offset's to ASN.1 entities */
2236 if (asn1_nodes)
2237 g_node_destroy(asn1_nodes);
2238 asn1_nodes = g_node_new(0);
2239 icount = 0;
2240 parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
2244 /*****************************************************************************************************/
2246 static guint anonCount; /* for naming anonymous types */
2248 typedef struct _TBLModule TBLModule;
2249 typedef struct _TBLTypeDef TBLTypeDef;
2250 typedef struct _TBLTag TBLTag;
2251 typedef struct _TBLType TBLType;
2252 typedef struct _TBLTypeRef TBLTypeRef;
2253 typedef struct _TBLNamedNumber TBLNamedNumber;
2254 typedef struct _TBLRange TBLRange;
2256 enum _tbl_t {
2257 TBLTYPE_Module,
2258 TBLTYPE_TypeDef,
2259 TBLTYPE_Tag,
2260 TBLTYPE_Type,
2261 TBLTYPE_TypeRef,
2262 TBLTYPE_NamedNumber,
2263 TBLTYPE_Range
2265 typedef enum _tbl_t tbl_t;
2266 /* text for 'tbl_t' type for debugging */
2267 static const char *data_types[] = {
2268 "Module",
2269 "TypeDef",
2270 "Tag",
2271 "Type",
2272 "TypeRef",
2273 "NamedNumber",
2274 "Range",
2277 enum _TBLTypeContent_t {
2278 TBLTYPETYPE_None,
2279 TBLTYPETYPE_Primitive,
2280 TBLTYPETYPE_Elements,
2281 TBLTYPETYPE_TypeRef
2283 typedef enum _TBLTypeContent_t TBLTypeContent_t;
2285 struct _TBLNamedNumber {
2286 tbl_t type;
2287 guchar *name;
2288 guint value;
2291 struct _TBLRange {
2292 tbl_t type;
2293 guint from;
2294 guint to;
2297 struct _TBLTypeRef {
2298 tbl_t type;
2299 guint typeDefId;
2300 gboolean implicit;
2303 struct _TBLTag {
2304 tbl_t type;
2305 guint tclass;
2306 guint code;
2309 struct _TBLType {
2310 tbl_t type;
2311 guint typeId;
2312 gboolean optional;
2313 TBLTypeContent_t content;
2314 guchar *fieldName;
2315 gboolean anonymous;
2316 gboolean constraint;
2319 struct _TBLTypeDef {
2320 tbl_t type;
2321 guint typeDefId;
2322 guchar *typeName;
2323 guchar isPdu;
2326 struct _TBLModule {
2327 tbl_t type;
2328 guchar *name;
2329 subid_t *id;
2330 guint isUseful;
2333 struct _TT {
2334 guint totalNumModules;
2335 guint totalNumTypeDefs;
2336 guint totalNumTypes;
2337 guint totalNumTags;
2338 guint totalNumStrings;
2339 guint totalLenStrings;
2340 } TT;
2342 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2344 static guint
2345 get_asn1_int(guint want_tag, guint offset)
2347 ASN1_SCK asn1;
2348 guint ret, cls, con, tag, len;
2349 gboolean def;
2350 guint value;
2352 /* g_message("%d get_asn1_int", offset); */
2354 asn1_open(&asn1, asn1_desc, offset);
2356 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2357 if (ret == ASN1_ERR_NOERROR) {
2358 /* do not check class, both Unversal and Context are OK */
2359 if (con == ASN1_PRI && tag == want_tag) {
2360 if (def) {
2361 asn1_uint32_value_decode(&asn1, len, &value);
2362 return value;
2363 } else
2364 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2365 } else
2366 ret = ASN1_ERR_WRONG_TYPE;
2368 g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2370 return 0;
2373 static subid_t * /* with prepended length ..... */
2374 get_asn1_oid(guint want_tag, guint offset)
2376 ASN1_SCK asn1;
2377 guint ret, cls, con, tag, len;
2378 gboolean def;
2379 subid_t *oid;
2381 /* g_message("%d get_asn1_oid", offset); */
2383 asn1_open(&asn1, asn1_desc, offset);
2385 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2386 if (ret == ASN1_ERR_NOERROR) {
2387 /* do not check class, both Unversal and Context are OK */
2388 if ((con == ASN1_PRI) && (tag == want_tag)) {
2389 if (def) {
2390 asn1_oid_value_decode(&asn1, len, &oid, &con);
2391 oid = (subid_t *)g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2392 memmove(&oid[1], oid, con*sizeof(guint));
2393 oid[0] = con;
2394 return oid;
2395 } else
2396 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2397 } else
2398 ret = ASN1_ERR_WRONG_TYPE;
2400 g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2402 return 0;
2405 static guchar * /* 0 terminated string */
2406 get_asn1_string(guint want_tag, guint offset)
2408 ASN1_SCK asn1;
2409 guint ret, cls, con, tag, len;
2410 gboolean def;
2411 guchar *octets;
2413 /* g_message("%d get_asn1_string", offset); */
2415 asn1_open(&asn1, asn1_desc, offset);
2417 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2418 if (ret == ASN1_ERR_NOERROR) {
2419 /* do not check class, both Unversal and Context are OK */
2420 if ((con == ASN1_PRI) && (tag == want_tag)) {
2421 if (def) {
2422 asn1_string_value_decode(&asn1, len, &octets);
2423 octets = (guchar *)g_realloc(octets, len+1); /* need space for sentinel */
2424 octets[len] = 0;
2425 return octets;
2426 } else
2427 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2428 } else
2429 ret = ASN1_ERR_WRONG_TYPE;
2431 g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2433 return 0;
2436 static guint
2437 get_asn1_uint(guint offset)
2439 ASN1_SCK asn1;
2440 guint ret, len, value;
2442 /* g_message( "%d get_asn1_uint", offset); */
2444 asn1_open(&asn1, asn1_desc, offset);
2446 ret = asn1_uint32_decode(&asn1, &value, &len);
2448 if (ret != ASN1_ERR_NOERROR) {
2449 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2450 value = 0;
2452 return value;
2455 static gboolean
2456 check_tag(guint want_tag, guint offset)
2458 ASN1_SCK asn1;
2459 guint ret, cls, con, tag, len;
2460 gboolean def;
2462 asn1_open(&asn1, asn1_desc, offset);
2464 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2465 if (ret == ASN1_ERR_NOERROR) {
2466 ret = (tag == want_tag) ? TRUE : FALSE;
2467 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2468 return ret;
2470 g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2472 return FALSE;
2475 #if 0
2476 static gboolean
2477 constructed(guint offset)
2479 ASN1_SCK asn1;
2480 guint ret, cls, con, tag, def, len;
2482 /* g_message("%d constructed?", offset); */
2484 asn1_open(&asn1, asn1_desc, offset);
2486 ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2487 if (ret == ASN1_ERR_NOERROR) {
2488 if (con) {
2489 return TRUE;
2491 return FALSE;
2493 /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2495 return FALSE;
2497 #endif
2499 static void
2500 define_constraint(GNode *p, GNode *q)
2502 TBLRange *range = (TBLRange *)g_malloc(sizeof(TBLRange));
2503 g_node_append_data(q, range);
2505 range->type = TBLTYPE_Range;
2507 /* g_message("define_constraint %p, %p", p, q); */
2509 p = g_node_first_child(p);
2511 if (!p) {
2512 return;
2515 range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2516 p = g_node_next_sibling(p);
2518 if (!p) {
2519 return;
2522 range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2526 static void
2527 define_namednumber(GNode *p, GNode *q)
2529 TBLNamedNumber *num = (TBLNamedNumber *)g_malloc(sizeof(TBLNamedNumber));
2530 g_node_append_data(q, num);
2532 num->type = TBLTYPE_NamedNumber;
2534 /* g_message("define_namednumber %p, %p", p, q); */
2536 p = g_node_first_child(p);
2538 if (!p) {
2539 return;
2542 num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2543 p = g_node_next_sibling(p);
2545 if (!p) {
2546 return;
2549 num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2552 static void
2553 define_typeref(GNode *p, GNode *q)
2555 TBLTypeRef *ref = (TBLTypeRef *)g_malloc(sizeof(TBLTypeRef));
2556 g_node_append_data(q, ref);
2558 ref->type = TBLTYPE_TypeRef;
2560 /* g_message("define_typeref %p, %p", p, q); */
2562 p = g_node_first_child(p);
2564 if (!p) {
2565 return;
2568 ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2569 p = g_node_next_sibling(p);
2571 if (!p) {
2572 return;
2575 ref->implicit = get_asn1_int(BER_UNI_TAG_BOOLEAN, GPOINTER_TO_UINT(p->data));
2578 static void
2579 define_tag(GNode *p, GNode *q)
2581 TBLTag *type = (TBLTag *)g_malloc(sizeof(TBLTag));
2582 g_node_append_data(q, type);
2584 type->type = TBLTYPE_Tag;
2586 /* g_message("define_tag %p, %p", p, q); */
2588 p = g_node_first_child(p);
2590 if (!p) {
2591 return;
2594 type->tclass = get_asn1_int(BER_UNI_TAG_ENUMERATED, GPOINTER_TO_UINT(p->data));
2595 p = g_node_next_sibling(p);
2597 if (!p) {
2598 return;
2601 type->code = get_asn1_int(BER_UNI_TAG_INTEGER, GPOINTER_TO_UINT(p->data));
2605 static void
2606 define_type(GNode *p, GNode *q)
2608 GNode *r;
2609 TBLType *type = (TBLType *)g_malloc(sizeof(TBLType));
2611 GNode *t = g_node_append_data(q, type);
2613 type->type = TBLTYPE_Type;
2615 /* g_message("define_type %p, %p", p, q); */
2617 type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2618 p = g_node_next_sibling(p);
2620 type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2621 p = g_node_next_sibling(p);
2623 if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
2624 r = g_node_first_child(p);
2625 while (r) {
2626 define_tag(r, t);
2627 r = g_node_next_sibling(r);
2629 p = g_node_next_sibling(p);
2632 if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
2633 g_warning("expect tag 3, ERROR");
2635 r = g_node_first_child(p);
2636 /* a choice ... */
2637 type->content = TBLTYPETYPE_None;
2638 if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
2639 if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
2640 if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
2641 switch(type->content) {
2642 case TBLTYPETYPE_Primitive:
2643 break;
2644 case TBLTYPETYPE_Elements:
2645 r = g_node_first_child(r);
2646 while (r) {
2647 define_type(g_node_first_child(r), t);
2648 r = g_node_next_sibling(r);
2650 break;
2651 case TBLTYPETYPE_TypeRef:
2652 define_typeref(r, t);
2653 break;
2654 case TBLTYPETYPE_None:
2655 g_warning("expected a contents choice, error");
2656 break;
2658 p = g_node_next_sibling(p);
2660 type->fieldName = 0;
2661 type->anonymous = FALSE;
2662 if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
2663 type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
2664 p = g_node_next_sibling(p);
2665 } else {
2666 type->anonymous = TRUE;
2669 type->constraint = FALSE;
2670 if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
2671 type->constraint = TRUE;
2672 define_constraint(p, t);
2673 p = g_node_next_sibling(p);
2676 if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
2677 r = g_node_first_child(p);
2678 while(r) {
2679 define_namednumber(r, t);
2680 r = g_node_next_sibling(r);
2685 static void
2686 define_typedef(GNode *p, GNode *q)
2688 TBLTypeDef *type_def = (TBLTypeDef *)g_malloc(sizeof(TBLTypeDef));
2690 GNode *t = g_node_append_data(q, type_def);
2692 /* g_message("define_typedef %p, %p", p, q); */
2694 type_def->type = TBLTYPE_TypeDef;
2696 p = g_node_first_child(p);
2698 if (!p) {
2699 return;
2702 type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2703 p = g_node_next_sibling(p);
2705 if (!p) {
2706 return;
2709 type_def->typeName = get_asn1_string(BER_UNI_TAG_PrintableString, GPOINTER_TO_UINT(p->data));
2710 p = g_node_next_sibling(p);
2712 if (!p) {
2713 return;
2716 define_type(g_node_first_child(p), t);
2717 p = g_node_next_sibling(p);
2719 type_def->isPdu = (p != 0); /* true if it exists, value ignored */
2722 static void
2723 define_module(GNode *p, GNode *q)
2725 TBLModule *module = (TBLModule *)g_malloc(sizeof(TBLModule));
2727 GNode *m = g_node_append_data(q, module);
2729 /* g_message("define_module %p %p", p, q); */
2731 module->type = TBLTYPE_Module;
2733 p = g_node_first_child(p);
2735 if (!p) {
2736 return;
2739 module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2740 p = g_node_next_sibling(p);
2742 module->id = 0;
2743 if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */
2744 module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
2745 p = g_node_next_sibling(p);
2748 module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
2749 p = g_node_next_sibling(p);
2751 p = g_node_first_child(p);
2752 while (p) {
2753 define_typedef(p, m);
2754 p = g_node_next_sibling(p);
2758 typedef struct _SearchDef SearchDef;
2759 struct _SearchDef {
2760 const char *key;
2761 GNode *here;
2764 static gboolean
2765 is_typedef(GNode *node, gpointer data)
2767 TBLTypeDef *d = (TBLTypeDef *)node->data;
2768 SearchDef *s = (SearchDef *)data;
2770 if (d == 0) return FALSE;
2771 if (d->type != TBLTYPE_TypeDef) return FALSE;
2772 if (strcmp(s->key, d->typeName) == 0) {
2773 s->here = node;
2774 return TRUE;
2776 return FALSE;
2779 typedef struct _TypeRef TypeRef;
2780 struct _TypeRef {
2781 GNode *type;
2782 char *name;
2783 guchar defclass;
2784 guint deftag;
2785 GNode *pdu; /* location in PDU descriptor tree */
2786 guint level; /* recursion counter */
2787 GNode *typetree;
2788 GPtrArray *refs; /* pointers to PDUinfo structures teferencing this entry */
2791 typedef struct _NameDefs NameDefs;
2792 struct _NameDefs {
2793 guint max;
2794 guint used;
2795 TypeRef *info;
2797 #define ALLOC_INCR 4
2798 #define CLASSREF (BER_CLASS_PRI+1)
2800 static gboolean
2801 is_named(GNode *node, gpointer data)
2803 TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2804 NameDefs *n = (NameDefs *)data;
2805 guint oldmax;
2807 if (num == 0) return FALSE;
2808 if (num->type != TBLTYPE_NamedNumber) return FALSE;
2810 if (num->value >= n->max) { /* need larger array */
2811 oldmax = n->max;
2812 n->max = num->value + ALLOC_INCR;
2813 n->info = (TypeRef *)g_realloc(n->info, n->max * sizeof(TypeRef));
2814 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2816 if (num->value > n->used) /* track max used value, there may be holes... */
2817 n->used = num->value;
2819 n->info[num->value].name = num->name;
2821 return FALSE;
2824 static gboolean
2825 index_typedef(GNode *node, gpointer data)
2827 TBLTypeDef *d = (TBLTypeDef *)node->data;
2828 NameDefs *n = (NameDefs *)data;
2829 TypeRef *t;
2830 TBLTag *tag;
2831 guint oldmax;
2833 if (d == 0) return FALSE;
2834 if (d->type != TBLTYPE_TypeDef) return FALSE;
2836 if (d->typeDefId >= n->max) { /* need larger array */
2837 oldmax = n->max;
2838 n->max = d->typeDefId + ALLOC_INCR;
2839 n->info = (TypeRef *)g_realloc(n->info, n->max * sizeof(TypeRef));
2840 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2842 if (d->typeDefId > n->used) /* track max used value, there may be holes... */
2843 n->used = d->typeDefId;
2845 t = &(n->info[d->typeDefId]);
2846 t->name = d->typeName;
2847 t->type = node;
2848 t->refs = g_ptr_array_new(); /* collect references here */
2849 node = g_node_first_child(node); /* the real type */
2850 tag = (TBLTag *)node->data;
2851 if ((tag->type == TBLTYPE_Type) && (((TBLType *)(void *)tag)->typeId == TBL_CHOICE)) {
2852 /* no reasonable default... ! */
2853 t->defclass = 3; /* Private .... */
2854 t->deftag= 9999; /* a random value */
2855 } else {
2856 node = g_node_first_child(node); /* the default tag */
2857 tag = (TBLTag *)node->data;
2858 switch(tag->type) {
2859 case TBLTYPE_Tag:
2860 t->defclass = tag->tclass;
2861 t->deftag = tag->code;
2862 break;
2863 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2864 t->defclass = CLASSREF; /* invalid class.. */
2865 t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2866 break;
2867 default:
2868 g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2869 data_types[tag->type]);
2870 t->defclass = 3; /* Private .... */
2871 t->deftag= 9998; /* another random value */
2872 break;
2876 return FALSE;
2879 static TypeRef *typeDef_names = 0;
2880 static guint numTypedefs = 0;
2882 static gboolean
2883 free_node_data(GNode *node, gpointer data _U_)
2885 g_free(node->data);
2886 return FALSE;
2889 static void
2890 get_values(void) /* collect values from ASN.1 tree */
2891 /* coded according to the tbl.asn1 description of snacc output */
2892 { /* This routine does not leave references to the tvbuff or */
2893 /* to the asn1_nodes, both can be freed by the caller of this.*/
2894 GNode *p;
2895 SearchDef sd;
2896 NameDefs nd;
2897 guint i;
2898 char X;
2899 const char *t, *s, *E;
2900 static char missing[] = " **missing** ";
2902 if (asn1_verbose) g_message("interpreting tree");
2903 typeDef_names = 0; /* just forget allocated any data .... */
2905 if (data_nodes) {
2906 g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2907 free_node_data, NULL);
2908 g_node_destroy(data_nodes);
2911 data_nodes = g_node_new(0);
2913 p = g_node_first_child(asn1_nodes); /* top of the data tree */
2915 p = g_node_first_child(p);
2916 if (!p) return;
2917 TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2918 p = g_node_next_sibling(p);
2919 if (!p) return;
2920 TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2921 p = g_node_next_sibling(p);
2922 if (!p) return;
2923 TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2924 p = g_node_next_sibling(p);
2925 if (!p) return;
2926 TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2927 p = g_node_next_sibling(p);
2928 if (!p) return;
2929 TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2930 p = g_node_next_sibling(p);
2931 if (!p) return;
2932 TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2933 p = g_node_next_sibling(p);
2935 p = g_node_first_child(p);
2936 while (p) {
2937 define_module(p, data_nodes);
2938 p = g_node_next_sibling(p);
2941 /* g_message("finished with tree"); */
2943 if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2944 sd.key = "TBLTypeId";
2945 sd.here = 0;
2946 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2947 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", (void *)sd.here);
2948 if (sd.here) {
2949 nd.max = 8;
2950 nd.used = 0;
2951 nd.info = (TypeRef *)g_malloc0(nd.max * sizeof(TypeRef));
2952 g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2953 (gpointer)&nd);
2954 if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, (void *)nd.info);
2955 E = empty;
2956 for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2957 X = 'X';
2958 t = TBLTYPE(i);
2959 s = nd.info[i].name;
2960 if (s == 0) s = missing;
2961 if (g_strcmp(t, s) == 0) { /* OK ! */
2962 X = ' ';
2963 t = empty;
2964 } else {
2965 E = ", X with errors X";
2967 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2969 if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2971 tbl_types_verified = TRUE;
2973 /* build table with typedef names */
2974 nd.max = 8;
2975 nd.used = 0;
2976 nd.info = (TypeRef *)g_malloc0(nd.max * sizeof(TypeRef));
2977 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2978 if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, (void *)nd.info);
2980 for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2981 TypeRef *ref = &(nd.info[i]);
2982 t = ref->name;
2983 if (t == 0) {
2984 t = ref->name = missing;
2985 if (asn1_verbose) g_message(" %3d %s", i, t);
2986 } else {
2987 if (asn1_verbose) g_message(" %3d %s, %c%d", i, t,
2988 tag_class[ref->defclass], ref->deftag);
2990 if (ref->pdu) { /* should be 0 */
2991 if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, (void *)ref->pdu);
2994 typeDef_names = nd.info;
2995 numTypedefs = i;
2996 if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
3000 static void
3001 showGNode(GNode *p, int n)
3004 const char *fn, *s = empty;
3005 if (p == 0) return;
3006 n *=2; /* 2 spaces per level */
3007 if (p->data) { /* show value ... */
3008 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
3009 switch (((TBLTag *)p->data)->type) {
3010 case TBLTYPE_Module: {
3011 TBLModule *m = (TBLModule *)p->data;
3012 if (asn1_verbose)
3013 g_message("%*smodule %s%s", n, empty, m->name,
3014 m->isUseful ? ", useful" : empty);
3016 break;
3017 case TBLTYPE_TypeDef: {
3018 TBLTypeDef *t = (TBLTypeDef *)p->data;
3019 if (asn1_verbose)
3020 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
3021 t->isPdu ? ", isPDU" : empty);
3023 break;
3024 case TBLTYPE_Type: {
3025 TBLType *t = (TBLType *)p->data;
3026 if (t->fieldName)
3027 s = t->fieldName;
3028 /* typeId is a value from enum TBLTypeId */
3029 fn = TBLTYPE(t->typeId);
3030 if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
3031 t->optional ? " opt" : empty, s );
3033 break;
3034 case TBLTYPE_Tag: {
3035 TBLTag *t = (TBLTag *)p->data;
3036 if ((t->tclass == BER_CLASS_UNI) && (t->code < 32))
3037 s = asn1_tag[t->code];
3038 if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
3039 tag_class[t->tclass], t->code, s);
3041 break;
3042 case TBLTYPE_NamedNumber: {
3043 TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
3044 if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
3045 nn->value, nn->name);
3047 break;
3048 case TBLTYPE_Range: {
3049 TBLRange *r = (TBLRange *)p->data;
3050 if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
3051 r->from, r->to );
3053 break;
3054 case TBLTYPE_TypeRef: {
3055 TBLTypeRef *r = (TBLTypeRef *)p->data;
3056 if (typeDef_names)
3057 s = typeDef_names[r->typeDefId].name;
3058 if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
3059 r->typeDefId, s, r->implicit ? ", implicit" : empty );
3061 break;
3062 default: {
3063 TBLTag *x = (TBLTag *)p->data;
3064 if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
3066 break;
3068 } else { /* just show tree */
3069 if (asn1_verbose)
3070 g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
3071 n, empty, (void *)p, (void *)p->data, (void *)p->next, (void *)p->prev, (void *)p->parent, (void *)p->children);
3075 static void
3076 showGNodes(GNode *p, int n)
3078 if (p == 0) return;
3079 showGNode(p, n);
3080 showGNodes(p->children, n+1);
3081 showGNodes(p->next, n);
3084 #if 0
3085 static void showGenv(GNode *p, int n, int m)
3087 int i;
3089 if (p == 0) return;
3090 if (n > m) {
3091 if (asn1_verbose) g_message("%*s.....", n*2, empty);
3092 return;
3095 for(i=0; p && (i < 3); p = p->next, i++) {
3096 showGNode(p, n);
3097 showGenv(p->children, n+1, m);
3099 if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
3102 #endif
3104 static void
3105 debug_dump_TT(void) /* dump contents of TT struct, for debugging */
3107 if (asn1_verbose)
3108 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
3109 TT.totalNumModules,
3110 TT.totalNumTypeDefs,
3111 TT.totalNumTypes,
3112 TT.totalNumTags,
3113 TT.totalNumStrings,
3114 TT.totalLenStrings);
3117 static void
3118 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
3119 const gchar *message, gpointer user_data)
3121 static FILE* logf = 0;
3122 static char eol[] = "\r\n";
3124 (void) log_domain; (void) log_level; (void) user_data; /* make references */
3126 if (logf == NULL && asn1_logfile) {
3127 logf = ws_fopen(asn1_logfile, "w");
3129 if (logf) {
3130 fputs(message, logf);
3131 fputs(eol, logf);
3132 fflush(logf); /* debugging ... */
3136 static void
3137 read_asn1_type_table(const char *filename)
3139 FILE *f;
3140 int ret;
3141 guint size = 0;
3142 guchar *data;
3143 struct stat file_stat;
3144 static guint mylogh = 0;
3146 if ((filename == 0) || (strlen(filename) == 0))
3147 return; /* no filename provided */
3149 f = ws_fopen(filename, "rb");
3150 if (f == 0) {
3152 * Ignore "file not found" errors if it's the old default
3153 * ASN.1 file name, as we never shipped such a file.
3154 * Also, on Win32, ignore the earlier default, which
3155 * had a "/" rather than a "\" as the last pathname
3156 * separator.
3158 #ifdef _WIN32
3159 if (strcmp(filename, bad_separator_old_default_asn1_filename) != 0)
3160 #endif
3161 if ((strcmp(filename, old_default_asn1_filename) != 0) || errno != ENOENT)
3162 report_open_failure(filename, errno, FALSE);
3163 return;
3165 ret = fstat(fileno(f), &file_stat);
3166 if (ret!=-1)
3167 size = (int)file_stat.st_size;
3168 if (size == 0) {
3169 if (asn1_verbose) g_message("file %s is empty or size is unknown, ignored", filename);
3170 fclose(f);
3171 return;
3173 if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
3175 data = (guchar *)g_malloc(size);
3176 if (fread(data, size, 1, f) < 1) {
3177 g_warning("error reading %s, %s", filename, g_strerror(errno));
3179 fclose(f);
3181 if (asn1_verbose) {
3182 /* ***** from the time when logging was just in a console... *****
3183 * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
3184 * " Sleep 5 sec...");
3185 * Sleep(5 * 1000);
3189 g_message("logging to file %s", asn1_logfile);
3191 if (mylogh == 0) {
3192 mylogh = g_log_set_handler (NULL, (GLogLevelFlags)(G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
3193 | G_LOG_FLAG_RECURSION), my_log_handler, NULL);
3197 asn1_desc = tvb_new_real_data(data, size, size);
3199 tt_build_tree();
3200 if (asn1_verbose) g_message("read %d items from %s", icount, filename);
3202 #if 0
3203 list_modules();
3204 #endif
3206 get_values();
3208 g_node_destroy(asn1_nodes);
3209 asn1_nodes = NULL;
3211 tvb_free(asn1_desc);
3212 asn1_desc = NULL;
3214 g_free(data);
3215 data = NULL;
3217 showGNodes(data_nodes, 0);
3219 debug_dump_TT();
3223 /* XXX - Shoudn't we make sure we're not dereferencing a NULL pointer here? */
3224 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
3225 g_warning("**** unexpected type %s, want %s, at line %d", \
3226 data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
3229 static void
3230 save_reference(PDUinfo *p)
3232 gint i = p->mytype;
3234 if (i == -1)
3235 i = p->basetype;
3237 g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
3240 static void
3241 tbl_type(gint n, GNode *pdu, GNode *list, guint fullindex);
3245 /* evaluate typeref, pointer to current pdu node and typedef */
3246 static void
3247 tbl_typeref(gint n, GNode *pdu, GNode *tree, guint fullindex)
3249 GNode *q;
3250 PDUinfo *p = (PDUinfo *)pdu->data, *p1;
3251 guint nvals;
3252 value_string *v;
3253 char ss[128];
3254 int i;
3256 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
3257 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
3258 return;
3261 CHECKTYPE(tree, TBLTYPE_TypeDef);
3263 if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
3264 p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
3266 p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
3267 p->flags |= PDU_TYPEDEF;
3269 tree = g_node_first_child(tree); /* move to its underlying type */
3270 CHECKTYPE(tree, TBLTYPE_Type);
3271 p->type = ((TBLType *)tree->data)->typeId;
3273 q = g_node_first_child(tree); /* the tag of this type entry ... is optional... */
3274 if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
3275 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3276 guint xcls, xtag;
3277 xcls = p->tclass;
3278 xtag = p->tag;
3279 /* XXX -- hack -- hack -- hack -- hack -- hack --
3280 * only change tag when class+tag == EOC,
3281 * or class is a reference,
3282 * or new class is not universal.
3284 if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
3285 (((TBLTag *)q->data)->tclass != BER_CLASS_UNI) ) {
3286 p->tclass = ((TBLTag *)q->data)->tclass;
3287 p->tag = ((TBLTag *)q->data)->code;
3288 if (asn1_verbose)
3289 g_message("%*s*change typeref tag from %c%d to %c%d",
3290 n*2, empty,
3291 tag_class[xcls],
3292 xtag,
3293 tag_class[p->tclass],
3294 p->tag);
3295 } else {
3296 if (asn1_verbose)
3297 g_message("%*sNOT changing tag from %c%d to %c%d",
3298 n*2, empty,
3299 tag_class[xcls],
3300 xtag,
3301 tag_class[((TBLTag *)q->data)->tclass],
3302 ((TBLTag *)q->data)->code);
3306 } else {
3308 ss[0] = 0;
3309 if (p->tclass==CLASSREF)
3310 g_snprintf(ss, 128, ", CLASSREF %d", p->tag);
3311 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
3313 if (p->tclass==CLASSREF) {
3314 TypeRef *tr;
3315 i = p->basetype;
3316 /* CLASSREF....., get it defined using type of the reference */
3318 /* p->basetype may be -1 .... ? XXX */
3319 if (i == -1)
3320 i = p->tag;
3321 tr = &typeDef_names[i];
3322 if (asn1_verbose)
3323 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
3324 p->tag, tr->name, (void *)tr->pdu);
3326 tbl_typeref(n+1, pdu, tr->type, fullindex);
3328 return;
3332 if (asn1_verbose)
3333 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
3334 p->name, p->asn1typename, (void *)p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
3336 switch(p->type) {
3337 case TBL_BITSTRING:
3338 case TBL_ENUMERATED:
3339 /* names do not have a fullname */
3340 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
3341 /* read the enumeration [save min-max somewhere ?] */
3342 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type]; /* XXX change field type... */
3343 p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3345 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3347 save_reference(p);
3349 if (asn1_verbose)
3350 g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3351 p->mytype, p->typenum, p->basetype, p->flags, p->asn1typename,
3352 p->name, p->fullname,
3353 tbl_types_wireshark_txt[p->type], p->value_id);
3354 p1 = p;
3355 nvals = 0;
3356 while((q = g_node_next_sibling(q))) {
3357 CHECKTYPE(q, TBLTYPE_NamedNumber);
3358 p = (PDUinfo *)g_malloc0(sizeof(PDUinfo));
3359 nvals++;
3360 p->type = TBL_ENUMERATED;
3361 p->name = (((TBLNamedNumber *)q->data)->name);
3362 p->tag = (((TBLNamedNumber *)q->data)->value);
3363 p->flags = PDU_NAMEDNUM;
3364 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3365 g_node_append_data(pdu, p);
3368 /* list all enum values in the field structure for matching */
3369 p1->value_hf.hfinfo.strings = v = (value_string *)g_malloc0((nvals+1) * sizeof(value_string));
3370 q = g_node_first_child(pdu);
3371 nvals = 0;
3372 while(q) {
3373 p = (PDUinfo *)q->data;
3374 v[nvals].value = p->tag;
3375 v[nvals].strptr = p->name;
3376 /* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
3377 nvals++;
3378 q = g_node_next_sibling(q);
3380 /* last entry is already initialized to { 0, NULL } */
3382 break;
3384 case TBL_CHOICE:
3385 if (p->value_id == -1) { /* not yet registered ..... */
3386 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3387 p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3388 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3390 save_reference(p);
3392 if (asn1_verbose)
3393 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3394 p->mytype, p->typenum, p->basetype, p->flags, p->asn1typename,
3395 p->name, p->fullname,
3396 tbl_types_wireshark_txt[p->type], p->value_id);
3398 tbl_type(n, pdu, q, fullindex);
3399 break;
3401 default:
3402 if (p->value_id == -1) { /* not yet registered ..... */
3403 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3404 p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3405 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3407 save_reference(p);
3409 if (asn1_verbose)
3410 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3411 p->mytype, p->typenum, p->basetype, p->flags, p->asn1typename,
3412 p->name, p->fullname,
3413 tbl_types_wireshark_txt[p->type], p->value_id);
3415 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
3419 static void
3420 tbl_type(gint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
3422 GNode *q, *pdu1;
3423 PDUinfo *p, *p1;
3424 guint ni;
3425 guint nvals;
3426 value_string *v;
3428 if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
3429 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3430 return;
3433 /* showGenv(list, n, n+1); */
3435 ni = fullindex;
3436 pdu1 = pdu; /* save start location for append */
3437 while (list) { /* handle all entries */
3438 if (asn1_verbose)
3439 g_message("%*s+handle a %s, list=%p", n*2, empty,
3440 data_types[((TBLTag *)list->data)->type], (void *)list);
3442 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
3443 list = g_node_next_sibling(list);
3444 if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
3445 if (list == 0)
3446 break;
3449 /******* change to positive comparation, but leave comment for reference
3450 * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3451 * CHECKTYPE(list, TBLTYPE_Type);
3454 if (((TBLTag *)list->data)->type == TBLTYPE_Type) {
3455 CHECKTYPE(list, TBLTYPE_Type);
3457 p = (PDUinfo *)g_malloc0(sizeof(PDUinfo));
3458 pdu = g_node_append_data(pdu1, p);
3460 p->type = ((TBLType *)list->data)->typeId;
3461 p->asn1typename = tbl_types_asn1[p->type]; /* the default type */
3462 p->typenum = -1;
3463 p->mytype = -1;
3464 p->basetype = ((PDUinfo *)pdu1->data)->typenum;
3465 p->flags = PDUinfo_initflags;
3466 p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
3467 p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
3469 if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
3470 /* assign an anonymous name [XXX refer to parent asn1typename...] */
3471 ((TBLType *)list->data)->fieldName =
3472 g_strdup_printf("anon%d", anonCount++);
3474 p->name = ((TBLType *)list->data)->fieldName;
3476 ni = fullindex;
3477 ni += g_snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
3478 p->fullname = g_strdup(fieldname);
3480 /* initialize field info */
3481 p->value_id = -1;
3482 p->type_id = -1;
3483 p->value_hf.p_id = &(p->value_id);
3484 p->value_hf.hfinfo.name = p->fullname;
3485 p->value_hf.hfinfo.abbrev = p->fullname;
3486 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3487 p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3488 p->value_hf.hfinfo.blurb = p->fullname;
3489 /* all the other fields are already 0 ! */
3491 if (p->type < TBL__SIMPLE) {
3492 /* only register fields with a value here, postpone others */
3493 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3495 save_reference(p);
3497 if (asn1_verbose)
3498 g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3499 p->mytype, p->typenum, p->basetype, p->flags,
3500 p->asn1typename, p->name, p->fullname,
3501 tbl_types_wireshark_txt[p->type], p->value_id);
3504 q = g_node_first_child(list);
3505 } else {
3506 p = (PDUinfo *)pdu->data;
3507 q = list;
3511 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
3513 switch (p->type) {
3514 case TBL_BOOLEAN:
3515 case TBL_INTEGER:
3516 case TBL_OCTETSTRING:
3517 case TBL_NULL:
3518 case TBL_OID:
3519 case TBL_REAL:
3520 CHECKTYPE(q, TBLTYPE_Tag);
3521 p->tclass = ((TBLTag *)q->data)->tclass;
3522 p->tag = ((TBLTag *)q->data)->code;
3523 break;
3525 case TBL_BITSTRING:
3526 case TBL_ENUMERATED:
3527 CHECKTYPE(q, TBLTYPE_Tag);
3528 p->tclass = ((TBLTag *)q->data)->tclass;
3529 p->tag = ((TBLTag *)q->data)->code;
3530 if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
3531 /* read the enumeration [save min-max somewhere ?] */
3532 nvals = 0;
3533 p1 = p;
3534 while((q = g_node_next_sibling(q))) {
3535 CHECKTYPE(q, TBLTYPE_NamedNumber);
3536 p = (PDUinfo *)g_malloc0(sizeof(PDUinfo));
3537 nvals++;
3538 p->type = TBL_ENUMERATED;
3539 p->name = (gchar *)(((TBLNamedNumber *)q->data)->name);
3540 p->tag = (((TBLNamedNumber *)q->data)->value);
3541 p->flags = PDU_NAMEDNUM;
3542 if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
3543 g_node_append_data(pdu, p);
3546 /* list all enum values in the field structure for matching */
3547 p1->value_hf.hfinfo.strings = v = (value_string *)g_malloc0((nvals+1) * sizeof(value_string));
3548 q = g_node_first_child(pdu);
3549 nvals = 0;
3550 while(q) {
3551 p = (PDUinfo *)q->data;
3552 v[nvals].value = p->tag;
3553 v[nvals].strptr = p->name;
3554 /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3555 nvals++;
3556 q = g_node_next_sibling(q);
3558 /* last entry is already initialized to { 0, NULL } */
3560 break;
3562 case TBL_SEQUENCE:
3563 case TBL_SET:
3564 case TBL_SEQUENCEOF:
3565 case TBL_SETOF:
3566 case TBL_CHOICE:
3567 CHECKTYPE(q, TBLTYPE_Tag);
3568 q = g_node_first_child(list);
3569 tbl_type(n+1, pdu, q, ni);
3570 break;
3572 case TBL_TYPEREF: { /* may have a tag ... */
3573 TypeRef *tr;
3574 guint i;
3575 if(!q){
3576 break;
3578 if ( ((TBLTag *)q->data)->type == TBLTYPE_Tag) {
3579 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3580 p->tclass = ((TBLTag *)q->data)->tclass;
3581 p->tag = ((TBLTag *)q->data)->code;
3582 if (asn1_verbose)
3583 g_message("%*s*insert type tag %c%d", n*2, empty,
3584 tag_class[p->tclass], p->tag);
3586 q = g_node_next_sibling(q);
3587 } else { /* use default tag for this type */
3588 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3589 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != BER_CLASS_UNI)) ||
3590 ((p->tclass | p->tag) == 0 )) {
3591 /* not implicit, use this tag */
3592 p->tclass = tr->defclass;
3593 p->tag = tr->deftag;
3594 if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3595 tag_class[p->tclass], p->tag);
3598 CHECKTYPE(q, TBLTYPE_TypeRef);
3599 i = ((TBLTypeRef *)q->data)->typeDefId;
3600 p->mytype = i;
3601 tr = &typeDef_names[i];
3602 if (asn1_verbose)
3603 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, (void *)tr->pdu);
3604 p->asn1typename = tr->name;
3606 if (tr->defclass == CLASSREF) {
3607 if (tr->pdu == 0)
3608 tr->pdu = pdu; /* remember this reference */
3609 i = tr->deftag;
3610 tr = &typeDef_names[i];
3611 if (asn1_verbose)
3612 g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3613 i, tr->name, (void *)tr->pdu);
3615 /* evaluate reference if not done before or when below recursion limit */
3616 if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3617 tr->level++;
3618 if (tr->pdu == 0) {
3619 tr->pdu = pdu; /* save for references we leave */
3621 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3622 if (asn1_verbose)
3623 g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3624 p->name,
3625 ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3626 tr->name,
3627 (void *)pdu);
3628 tbl_typeref(n+1, pdu, tr->type, ni);
3629 tr->level--;
3630 } else {
3631 if (asn1_verbose)
3632 g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3633 p->name, tr->name, (void *)tr->pdu);
3634 p->flags |= PDU_REFERENCE;
3635 p->reference = tr->pdu;
3638 break;
3639 default:
3640 g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3641 break;
3644 if (asn1_verbose)
3645 g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3646 n*2, empty, p->name, p->asn1typename, (void *)p, TBLTYPE(p->type),
3647 tag_class[p->tclass], p->tag);
3649 if (p->value_id == -1) { /* not registered before, do it now */
3650 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3652 save_reference(p);
3654 if (asn1_verbose)
3655 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3656 p->mytype, p->typenum, p->basetype, p->flags, p->asn1typename,
3657 p->name, p->fullname,
3658 tbl_types_wireshark_txt[p->type], p->value_id);
3660 list = g_node_next_sibling(list);
3664 static void
3665 PDUtext(char *txt, gulong txt_size, PDUinfo *info) /* say everything we know about this entry */
3667 PDUinfo *rinfo;
3668 const char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3669 int idx;
3671 idx = 0;
3672 if (info) {
3673 tt = TBLTYPE(info->type);
3674 nn = info->name;
3675 tn = info->asn1typename;
3676 fn = info->fullname;
3677 if (info->flags & PDU_NAMEDNUM)
3678 g_snprintf(&txt[idx], txt_size - idx, "name: %2d %s", info->tag, nn);
3679 else {
3680 if (info->flags & PDU_TYPEDEF)
3681 idx += g_snprintf(&txt[idx], txt_size - idx, "def %d: ", info->typenum);
3682 else
3683 idx += g_snprintf(&txt[idx], txt_size - idx, " ");
3684 ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3685 idx += g_snprintf(&txt[idx], txt_size - idx, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3686 tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3687 idx += g_snprintf(&txt[idx], txt_size - idx, ", mt=%d, bt=%d", info->mytype, info->basetype);
3688 oo = (info->flags & PDU_OPTIONAL) ? ", optional" : empty;
3689 ii = (info->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3690 nn = (info->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3691 an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3692 idx += g_snprintf(&txt[idx], txt_size - idx, "%s%s%s%s", oo, ii, nn, an);
3693 if (info->flags & PDU_REFERENCE) {
3694 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3695 tt = TBLTYPE(rinfo->type);
3696 nn = rinfo->name;
3697 tn = rinfo->asn1typename;
3698 fn = rinfo->fullname;
3699 idx += g_snprintf(&txt[idx], txt_size - idx, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3700 if (rinfo->flags & PDU_TYPEDEF)
3701 idx += g_snprintf(&txt[idx], txt_size - idx, " T%d", rinfo->typenum);
3702 idx += g_snprintf(&txt[idx], txt_size - idx, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3703 oo = (rinfo->flags & PDU_OPTIONAL) ? ", optional" : empty;
3704 ii = (rinfo->flags & PDU_IMPLICIT) ? ", implicit" : empty;
3705 nn = (rinfo->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
3706 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3707 tt = (rinfo->flags & PDU_TYPEDEF) ? ", typedef" : empty;
3708 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3709 tr = (rinfo->flags & PDU_TYPETREE) ? ", typetree" : empty;
3710 g_snprintf(&txt[idx], txt_size - idx, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3713 } else {
3714 g_snprintf(&txt[idx], txt_size - idx, "no info available");
3717 return;
3721 static void
3722 showPDUtree(GNode *p, int n)
3724 PDUinfo *info;
3725 char text[400];
3727 while (p != 0) {
3728 info = (PDUinfo *)p->data;
3730 PDUtext(text, sizeof(text), info);
3732 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3734 showPDUtree(g_node_first_child(p), n+1);
3736 p = g_node_next_sibling(p);
3739 return;
3742 static gboolean
3743 build_pdu_tree(const char *pduname)
3745 SearchDef sd;
3746 guint pdudef, i, tcount;
3747 guint sav_len;
3748 PDUinfo *info;
3749 char text[400];
3750 guint j, k;
3751 gint defid;
3752 PDUinfo *p, *q;
3753 TypeRef *tr;
3755 if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3757 if (!data_nodes) {
3758 if (asn1_verbose) g_message("no data nodes");
3759 return FALSE;
3761 sd.key = pduname;
3762 sd.here = 0;
3763 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3764 if (sd.here) {
3765 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3766 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, (void *)sd.here, pdudef);
3767 } else {
3768 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3769 return FALSE;
3772 /* If there's an existing PDU tree, free it */
3773 if (PDUtree) {
3774 g_node_traverse(PDUtree, G_POST_ORDER, G_TRAVERSE_ALL, -1,
3775 free_node_data, NULL);
3776 g_node_destroy(PDUtree);
3779 /* initialize the PDU tree, hand craft the root entry */
3781 info = (PDUinfo *)g_malloc0(sizeof(PDUinfo));
3782 info->name = pduname;
3783 info->asn1typename = pduname;
3784 info->type = TBL_SEQUENCEOF;
3785 info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3786 info->flags = PDUinfo_initflags = 0;
3787 info->value_id = -1;
3788 info->type_id = -1;
3789 info->basetype = -1;
3790 info->mytype = pdudef;
3792 info->value_hf.p_id = &(info->value_id);
3793 info->value_hf.hfinfo.name = info->fullname;
3794 info->value_hf.hfinfo.abbrev = info->fullname;
3795 info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3796 info->value_hf.hfinfo.display = tbl_display_wireshark[info->type];
3797 info->value_hf.hfinfo.blurb = info->fullname;
3799 anonCount = 0; /* anonymous types counter */
3801 PDUtree = g_node_new(info);
3802 pabbrev_pdu_len = g_snprintf(fieldname, sizeof(fieldname), "%s.%s.", pabbrev, pduname);
3803 sav_len = pabbrev_pdu_len;
3805 /* Now build the tree for this top level PDU */
3806 if (asn1_verbose)
3807 g_message("******** Define main type %d, %s", pdudef, pduname);
3808 tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1); /* strip initial . for new names */
3810 if (asn1_verbose)
3811 g_message("%d anonymous types", anonCount);
3813 /* Now make all types used available for matching */
3814 if (asn1_verbose)
3815 g_message("Define the types that are actually referenced through the top level PDU");
3816 for (i=0, tcount=0; i<numTypedefs; i++) {
3817 tr = &(typeDef_names[i]);
3819 if (tr->pdu) { /* ignore if not used in main pdu */
3820 tcount++;
3821 if (i == pdudef)
3822 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3823 if (asn1_verbose)
3824 g_message("******** Define type %d, %s", i, tr->name);
3826 /* .... do definition ..... */
3827 info = (PDUinfo *)g_malloc0(sizeof(PDUinfo));
3828 info->name = tr->name;
3829 info->asn1typename = tr->name;
3830 info->tclass = tr->defclass;
3831 info->tag = tr->deftag;
3832 info->type = TBL_TYPEREF;
3833 info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3834 info->flags = PDUinfo_initflags = PDU_TYPETREE;
3835 info->value_id = -1;
3836 info->type_id = -1;
3837 info->basetype = -1;
3838 info->mytype = i;
3840 info->value_hf.p_id = &(info->value_id);
3841 info->value_hf.hfinfo.name = info->fullname;
3842 info->value_hf.hfinfo.abbrev = info->fullname;
3843 info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3844 info->value_hf.hfinfo.display = tbl_display_wireshark[info->type];
3845 info->value_hf.hfinfo.blurb = info->fullname;
3847 tr->typetree = g_node_new(info);
3848 pabbrev_pdu_len = g_snprintf(fieldname, sizeof(fieldname), "%s.--.%s.", pabbrev, tr->name);
3849 tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3852 if (asn1_verbose)
3853 g_message("%d types used", tcount);
3855 pabbrev_pdu_len = sav_len;
3857 /* and show the result */
3858 if (asn1_verbose)
3859 g_message("Type index:");
3860 for (i=0; i<numTypedefs; i++) {
3861 tr = &(typeDef_names[i]);
3863 if (tr->pdu == 0) /* skip if not used */
3864 continue;
3866 if (asn1_verbose)
3867 g_message(" %3d %s, %c%d, refs: %d",
3868 i, tr->name, tag_class[tr->defclass], tr->deftag,
3869 g_ptr_array_len(tr->refs));
3871 /* get defining node for this type */
3872 defid = -1;
3873 if (tr->typetree) {
3874 p = (PDUinfo *)(tr->typetree->data);
3875 defid = p->value_id;
3876 if (asn1_verbose)
3877 g_message(" -- defining id=%d", defid);
3879 for(j=0; j < g_ptr_array_len(tr->refs); j++) { /* show refs, and set type_id */
3880 p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3881 if (p->mytype == (gint)i)
3882 p->type_id = defid; /* normal reference */
3883 else {
3884 if ((p->flags & PDU_TYPETREE) == 0) {
3885 /* we have a primitive value, find its real type */
3886 for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3887 /* look at all refs */
3888 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3889 if ((q->flags & PDU_TYPETREE) == 0)
3890 continue; /* only type trees are interresting */
3891 if (q->type != p->type)
3892 continue; /* must be same types */
3893 if (strcmp(q->name, p->name) == 0) {
3894 /* OK, take the first we find, not entirely
3895 * correct, it may be from a different
3896 * base-base type...... XXX */
3897 p->type_id = q->value_id;
3898 break;
3904 if (asn1_verbose) {
3905 PDUtext(text, sizeof(text), p);
3906 g_message(" %s", text);
3911 if (asn1_verbose)
3912 g_message("The resulting PDU tree:");
3913 showPDUtree(PDUtree, 0);
3915 return TRUE;
3919 #ifdef DISSECTOR_WITH_GUI
3920 /* This cannot work in tshark.... don't include for now */
3921 #define SHOWPDU
3922 #endif /* DISSECTOR_WITH_GUI */
3923 #ifdef SHOWPDU
3925 static GtkWidget *window = NULL;
3927 /* the columns in the tree view */
3928 enum
3930 TITLE_COLUMN, /* text in this row */
3931 DEF_COLUMN, /* definition in this row, if any */
3932 REF_COLUMN, /* referennce from this column, if any */
3933 VALUE_COLUMN, /* indicate this is a value */
3934 NAME_COLUMN, /* name of this row */
3935 N_COLUMNS
3938 static FILE *namelist = 0;
3940 static void
3941 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3943 GtkTreeIter iter2;
3944 PDUinfo *info, *rinfo;
3945 gint def, ref;
3946 guchar *pb;
3948 char text[400];
3950 while (p != 0) {
3951 info = (PDUinfo *)p->data;
3953 gtk_tree_store_append (store, &iter2, iter); /* Acquire iterator */
3955 PDUtext(text, sizeof(text), info);
3957 def = ref = -1;
3958 if (info->flags & PDU_TYPEDEF)
3959 def = info->typenum;
3961 if (info->flags & PDU_REFERENCE) {
3962 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3963 ref = rinfo->typenum;
3965 pb = GTK_STOCK_CANCEL;
3966 if (G_NODE_IS_LEAF(p)) {
3967 if (info->flags & PDU_NAMEDNUM)
3968 pb = GTK_STOCK_BOLD;
3969 else {
3970 pb = GTK_STOCK_YES;
3971 if (namelist)
3972 fprintf(namelist, "%16s %s\n",
3973 &(TBLTYPE(info->type)[4]), info->fullname);
3975 } else {
3976 switch (info->type) {
3977 case TBL_ENUMERATED:
3978 case TBL_BITSTRING:
3979 pb = GTK_STOCK_ADD;
3980 if (namelist)
3981 fprintf(namelist, "%16s %s\n",
3982 &(TBLTYPE(info->type)[4]), info->fullname);
3983 break;
3984 default:
3985 break;
3989 gtk_tree_store_set (store, &iter2,
3990 TITLE_COLUMN, text,
3991 DEF_COLUMN, def,
3992 REF_COLUMN, ref,
3993 VALUE_COLUMN, pb,
3994 NAME_COLUMN, info->fullname,
3995 -1);
3997 build_tree_view(store, g_node_first_child(p), &iter2);
3999 p = g_node_next_sibling(p);
4002 return;
4006 struct DefFind {
4007 gint def;
4008 GtkTreePath *path;
4011 #define PATHSTACKMAX 10
4012 static GtkTreePath *pathstack[PATHSTACKMAX];
4013 static gint pathstackp = 0;
4015 static void add_path(GtkTreePath *p)
4017 if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
4018 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
4019 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
4020 pathstackp--;
4022 pathstack[pathstackp++] = p;
4025 static GtkTreePath *pop_path(void)
4027 if (pathstackp > 0)
4028 return pathstack[--pathstackp];
4029 return 0;
4032 static gboolean
4033 find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
4035 gint def;
4037 struct DefFind *df = (struct DefFind *)data;
4039 gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
4041 if (def == df->def) {
4042 df->path = gtk_tree_path_copy (path);
4043 return TRUE;
4045 return FALSE;
4049 static void
4050 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
4052 GtkTreeIter iter;
4053 GtkTreePath *path, *path2;
4054 gchar *text, *oldpath, *newpath;
4055 gint def, ref;
4056 struct DefFind df;
4058 (void) arg2;
4060 path = gtk_tree_path_copy (spath);
4062 gtk_tree_model_get_iter (model, &iter, path);
4063 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
4065 oldpath = gtk_tree_path_to_string(path);
4066 path2 = gtk_tree_path_copy (path);
4068 add_path(gtk_tree_path_copy(path));
4070 if (ref != -1) { /* this is a reference, find matching definition */
4071 df.def = ref;
4072 df.path = 0;
4073 gtk_tree_model_foreach (model, find_definition, &df);
4074 if (df.path) {
4075 gtk_tree_path_free(path);
4076 path = df.path;
4078 } else { /* just move to the next entry, if it exists */
4079 gtk_tree_path_next(path2);
4081 if (gtk_tree_model_get_iter (model, &iter, path2)) {
4082 gtk_tree_path_free(path);
4083 path = path2; /* OK */
4084 } else {
4085 if (gtk_tree_path_get_depth (path) > 1)
4086 gtk_tree_path_up (path);
4090 if (path != path2)
4091 gtk_tree_path_free (path2);
4093 gtk_tree_view_expand_to_path (treeview, path);
4094 gtk_tree_view_expand_row (treeview, path, FALSE);
4096 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
4098 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
4100 newpath = gtk_tree_path_to_string(path);
4102 if (asn1_debug)
4103 g_message("my_signal_handler: treeview=%p, moving from %s to %s",
4104 treeview, oldpath, newpath);
4106 g_free(text);
4107 g_free(oldpath);
4108 g_free(newpath);
4109 /* if (df.path) */
4110 /* gtk_tree_path_free(df.path); */
4114 static void
4115 menuitem_cb (gpointer callback_data,
4116 guint callback_action,
4117 GtkWidget *widget)
4119 GtkWidget *dialog;
4120 GtkTreeModel *model;
4121 GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
4122 GtkTreeSelection *selection;
4123 GtkTreeIter iter;
4124 gchar *text, *name;
4125 gint def, ref;
4126 GtkTreePath *path;
4127 gchar *oldpath, *newpath;
4128 GtkTreeViewColumn *focus_column;
4130 selection = gtk_tree_view_get_selection(treeview);
4132 model = gtk_tree_view_get_model(treeview);
4133 gtk_tree_view_get_cursor (treeview, &path, &focus_column);
4135 if (gtk_tree_model_get_iter (model, &iter, path)) {
4137 gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
4138 NAME_COLUMN, &name, -1);
4139 oldpath = gtk_tree_path_to_string(path);
4140 newpath = empty;
4142 switch (callback_action) {
4143 case 0: /* Select */
4144 gtk_tree_selection_select_path (selection, path);
4145 break;
4146 case 1: /* back */
4147 path = pop_path();
4148 if (path) {
4149 gtk_tree_view_expand_to_path (treeview, path);
4150 gtk_tree_view_expand_row (treeview, path, FALSE);
4152 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
4154 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
4156 newpath = gtk_tree_path_to_string(path);
4158 gtk_tree_path_free(path);
4159 } else
4160 newpath = g_strdup("** no path **");
4161 if (asn1_debug)
4162 g_message("menueitem_cb: treeview=%p, moving from %s to %s",
4163 treeview, oldpath, newpath);
4164 break;
4166 case 2: /* Find */
4167 /* get all non anonymous names to the root */
4169 default:
4170 dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
4171 GTK_DIALOG_DESTROY_WITH_PARENT,
4172 GTK_MESSAGE_INFO,
4173 GTK_BUTTONS_CLOSE,
4174 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
4175 gtk_item_factory_path_from_widget (widget),
4176 callback_action, text, oldpath, newpath, name);
4178 /* Close dialog on user response */
4179 g_signal_connect (dialog,
4180 "response",
4181 G_CALLBACK (gtk_widget_destroy),
4182 NULL);
4184 gtk_widget_show (dialog);
4185 break;
4187 g_free(text);
4188 g_free(name);
4189 if (newpath != empty)
4190 g_free(newpath);
4191 g_free(oldpath);
4192 } else
4193 g_message("menuitem_cb: no iterator...");
4196 static GtkItemFactoryEntry menu_items[] = {
4197 { "/Select", NULL, menuitem_cb, 0, NULL, 0 },
4198 { "/Back", "<control>B", menuitem_cb, 1, NULL, 0 },
4199 { "/Find", "<control>F", menuitem_cb, 2, NULL, 0 },
4200 { "/Save", "<control>S", menuitem_cb, 3, NULL, 0 },
4203 static gint button_press_callback( GtkWidget *widget,
4204 GdkEventButton *event,
4205 gpointer data )
4207 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
4209 /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
4210 * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
4211 * event->y_root );
4213 if (event->button == 3) {
4214 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
4215 event->x_root,
4216 event->y_root,
4217 event->button,
4218 event->time);
4219 return TRUE;
4221 return FALSE; /* continue handling this event */
4225 static void
4226 create_message_window(void)
4228 GtkCellRenderer *renderer;
4229 GtkTreeStore *model;
4230 GtkWidget *vbox;
4231 GtkWidget *sw;
4232 GtkWidget *treeview;
4233 gchar *text;
4234 GtkItemFactory *item_factory;
4235 GtkAccelGroup *accel_group;
4236 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
4238 if ( ! window) {
4240 /* create window, etc */
4241 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4242 gtk_window_set_title (GTK_WINDOW (window), current_pduname);
4243 g_signal_connect (window, "destroy",
4244 G_CALLBACK (gtk_widget_destroyed), &window);
4246 vbox = gtk_vbox_new (FALSE, 8);
4247 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
4248 gtk_container_add (GTK_CONTAINER (window), vbox);
4250 text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
4252 gtk_box_pack_start (GTK_BOX (vbox),
4253 gtk_label_new (text),
4254 FALSE, FALSE, 0);
4255 g_free(text);
4257 sw = gtk_scrolled_window_new (NULL, NULL);
4258 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
4259 GTK_SHADOW_ETCHED_IN);
4260 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
4261 GTK_POLICY_AUTOMATIC,
4262 GTK_POLICY_AUTOMATIC);
4263 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
4265 model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
4266 G_TYPE_STRING, G_TYPE_STRING);
4268 namelist = ws_fopen("namelist.txt", "w");
4269 if (!namelist)
4270 fprintf(stderr, "unable to open file: namelist.txt for writing!\n");
4271 build_tree_view(model, PDUtree, NULL);
4272 if (namelist) {
4273 fclose(namelist);
4274 namelist = 0;
4277 /* create tree view */
4278 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
4279 g_object_unref (model);
4280 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
4281 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
4282 GTK_SELECTION_MULTIPLE);
4284 renderer = gtk_cell_renderer_text_new ();
4286 #if 0 /* testing pango attributes */
4288 PangoAttribute* bg;
4289 PangoAttrList* attr;
4291 attr = pango_attr_list_new();
4292 bg = pango_attr_background_new(50000,55000,50000);
4293 bg->start_index = 0;
4294 bg->end_index = 10000;
4295 pango_attr_list_insert(attr, bg);
4297 g_object_set(renderer, "attributes", attr, NULL);
4299 #endif /* testing pango attributes */
4301 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4302 TITLE_COLUMN, "asn1 entities", renderer,
4303 "text", TITLE_COLUMN, NULL );
4305 /* renderer = gtk_cell_renderer_text_new ();
4306 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4307 * DEF_COLUMN, "type definition", renderer,
4308 * "text", DEF_COLUMN, NULL );
4310 * renderer = gtk_cell_renderer_text_new ();
4311 * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4312 * REF_COLUMN, "reference", renderer,
4313 * "text", REF_COLUMN, NULL );
4315 renderer = gtk_cell_renderer_pixbuf_new ();
4316 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4317 VALUE_COLUMN, "value", renderer,
4318 "stock_id", VALUE_COLUMN, NULL );
4320 renderer = gtk_cell_renderer_text_new ();
4321 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4322 NAME_COLUMN, "fieldname", renderer,
4323 "text", NAME_COLUMN, NULL );
4325 gtk_container_add (GTK_CONTAINER (sw), treeview);
4327 /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
4329 /* create menu */
4331 accel_group = gtk_accel_group_new ();
4333 /* This function initializes the item factory.
4334 * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
4335 * or GTK_TYPE_OPTION_MENU.
4336 * Param 2: The path of the menu.
4337 * Param 3: A pointer to a gtk_accel_group. The item factory sets up
4338 * the accelerator table while generating menus.
4341 item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
4343 /* This function generates the menu items. Pass the item factory,
4344 the number of items in the array, the array itself, and any
4345 callback data for the the menu items. */
4346 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
4348 /* Attach the new accelerator group to the window. */
4349 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
4352 /* expand all rows after the treeview widget has been realized */
4353 g_signal_connect (treeview, "realize",
4354 G_CALLBACK (gtk_tree_view_expand_all), NULL);
4355 g_signal_connect (treeview, "row-activated",
4356 G_CALLBACK (my_signal_handler), (gpointer)model);
4358 g_signal_connect (treeview, "button_press_event",
4359 G_CALLBACK (button_press_callback), item_factory);
4361 /* g_signal_connect_swapped (treeview, "event",
4362 * G_CALLBACK (button_press_handler),
4363 * menu);
4365 gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
4368 if (!GTK_WIDGET_VISIBLE (window))
4369 gtk_widget_show_all (window);
4370 else
4372 gtk_widget_destroy (window);
4373 window = NULL;
4376 #endif /* SHOWPDU */
4378 /************************************************************************************************
4379 * routines to find names to go with the decoded data stream *
4380 ************************************************************************************************/
4381 #define PDUSTATE_STACK_SIZE 1024
4382 typedef struct _statestack statestack;
4383 static struct _statestack {
4384 GNode *node;
4385 guint type;
4386 guint offset;
4387 const char *name;
4388 } PDUstate[PDUSTATE_STACK_SIZE];
4389 static gint PDUstatec = 0;
4391 /* XXX - Shouldn't we do bounds checking here? */
4392 #define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
4393 #define POPSTATE PDUstate[--PDUstatec]
4395 static const char *
4396 getname(GNode *node) {
4397 if (node == NULL || node->data == NULL)
4398 THROW(ReportedBoundsError);
4400 return ((PDUinfo *)node->data)->name;
4403 static guint
4404 gettype(GNode *node) {
4405 if (node == NULL || node->data == NULL)
4406 THROW(ReportedBoundsError);
4408 return ((PDUinfo *)node->data)->type & TBL_TYPEmask;
4411 static PDUinfo *
4412 getinfo(GNode *node) {
4413 if (node == NULL)
4414 THROW(ReportedBoundsError);
4416 return (PDUinfo *)node->data;
4419 #define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
4420 #define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
4421 #define MATCH (info && (cls == info->tclass) && (tag == info->tag))
4422 #define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
4423 #define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
4424 #define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
4425 #define ISCHOICE (info && (info->flags & PDU_CHOICE))
4426 #define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
4428 #undef CHECKP
4429 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
4430 pos.node=NULL;PUSHNODE(pos);return ret;}}
4433 static void
4434 showstack(statestack *pos, char *txt, int n)
4436 char buf[1024];
4437 const char /* *name, *type,*/ *stype;
4438 const char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
4439 int i, j;
4440 /* GNode *g;*/
4441 statestack *p;
4442 guint typef;
4444 if ( ! asn1_verbose)
4445 return;
4447 if (n>PDUstatec)
4448 n = PDUstatec;
4449 if (n<0) {
4450 g_message("==underflow");
4451 return;
4453 rep = chs = done = ref = pop = chr = rch = sch = con = empty;
4455 #if 0 /* XXX: not used ??? */
4456 g = pos->node;
4457 if (g) {
4458 name = ((PDUinfo *)g->data)->name;
4459 type = TBLTYPE(((PDUinfo *)g->data)->type);
4460 } else {
4461 name = "node<null>";
4462 type = "?";
4464 #endif
4465 typef = pos->type;
4466 stype = TBLTYPE(typef);
4467 if (typef & TBL_REPEAT) rep = "[repeat]";
4468 if (typef & TBL_CHOICE_made) chs = "[choice]";
4469 if (typef & TBL_SEQUENCE_done) done = "[done]";
4470 if (typef & TBL_REFERENCE) ref = "[ref]";
4471 if (typef & TBL_REFERENCE_pop) pop = "[ref-pop]";
4472 if (typef & TBL_CHOICE_repeat) chr = "[chs-rep]";
4473 if (typef & TBL_REPEAT_choice) rch = "[rep-chs]";
4474 if (typef & TBL_SEQUENCE_choice)sch = "[seq-chs]";
4475 if (typef & TBL_CONSTRUCTED) con = "[constr]";
4477 i = g_snprintf(buf, sizeof(buf), "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
4478 (void *)pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4479 pos->name, pos->offset);
4481 for(j=1, n--; n>0; j++, n--) {
4482 p = &PDUstate[PDUstatec-j];
4483 typef = p->type;
4484 stype = TBLTYPE(typef);
4485 rep = (typef & TBL_REPEAT) ? "[repeat]" : empty;
4486 chs = (typef & TBL_CHOICE_made) ? "[choice]" : empty;
4487 done = (typef & TBL_SEQUENCE_done) ? "[done]" : empty;
4488 ref = (typef & TBL_REFERENCE) ? "[ref]" : empty;
4489 pop = (typef & TBL_REFERENCE_pop) ? "[ref-pop]" : empty;
4490 chr = (typef & TBL_CHOICE_repeat) ? "[chs-rep]" : empty;
4491 rch = (typef & TBL_REPEAT_choice) ? "[rep-chs]" : empty;
4492 sch = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
4493 con = (typef & TBL_CONSTRUCTED) ? "[constr]" : empty;
4495 i += g_snprintf(&buf[i], sizeof(buf) - i, "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
4496 (void *)p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4497 p->name, p->offset);
4499 g_message("%s", buf);
4502 #if 0
4503 static void
4504 showrefNode(GNode *node, int n)
4506 const char *name = empty, *type = empty, *tname = empty;
4507 int cls = 0, tag = 0;
4508 PDUinfo *info;
4509 GNode *ref = 0;
4511 if (n > 10) {
4512 g_message("%*sstop, nesting too deep", 2*n, empty);
4513 return;
4515 if (node->data) {
4516 info = (PDUinfo *)(node->data);
4517 type = TBLTYPE(info->type);
4518 name = info->name;
4519 tname = info->asn1typename;
4520 ref = info->reference;
4521 cls = info->tclass;
4522 tag = info->tag;
4524 g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4525 2*n, empty, tname, type, name, node, node->data,
4526 ref, tag_class[cls], tag);
4528 if (ref)
4529 showrefNode(ref, n+1);
4531 #endif
4533 #if 0
4534 static void
4535 showNode(GNode *node, int n, int m)
4537 const char *name = empty, *type = empty;
4538 GNode *ref = 0;
4540 if (n > m)
4541 return;
4543 if (node->data) {
4544 type = TBLTYPE(((PDUinfo *)(node->data))->type);
4545 name = ((PDUinfo *)(node->data))->name;
4546 ref = ((PDUinfo *)(node->data))->reference;
4548 g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4549 2*n, empty, type, name, node, node->data, node->next, node->prev,
4550 node->parent, node->children);
4552 if (m > 10) {
4553 g_message("%*sstop, nesting too deep", 2*n, empty);
4554 return;
4557 if (ref) showrefNode(ref, n+2);
4559 if (node->children) showNode(node->children, n+1, m);
4560 if (node->next) showNode(node->next, n, m);
4562 #endif
4564 static void
4565 PDUreset(int count, int count2)
4567 statestack pos;
4569 if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
4571 PDUstatec = 0; /* stackpointer */
4572 PDUerrcount = 0; /* error counter per asn.1 message */
4574 pos.node = NULL; /* sentinel */
4575 pos.name = "sentinel";
4576 pos.type = TBL_SEQUENCEOF;
4577 pos.offset = 0;
4578 PUSHNODE(pos);
4580 if (PDUtree) {
4581 pos.node = PDUtree; /* root of the tree */
4582 pos.name = getname(pos.node);
4583 pos.type = gettype(pos.node) | TBL_REPEAT;
4584 pos.offset = 0;
4585 PUSHNODE(pos);
4589 static GNode * /* find GNode for a choice element, 0 if none */
4590 makechoice(GNode *p, guint cls, guint tag)
4592 GNode *q;
4593 PDUinfo *info;
4595 p = g_node_first_child(p); /* the list of choices */
4596 info = 0; /* avoid gcc warning */
4598 while (p) {
4599 info = ((PDUinfo *)p->data);
4601 if (info->type == TBL_CHOICE) {
4602 if (asn1_verbose)
4603 g_message(" using sub choice (%s)%s", info->asn1typename, info->name);
4605 q = makechoice(p, cls, tag);
4606 if (q) { /* found it */
4607 p = q;
4608 info = ((PDUinfo *)p->data);
4609 break;
4610 } /* continue with this level */
4612 } else {
4613 if (asn1_verbose)
4614 g_message(" have %c%d, found %c%d, %s", tag_class[cls], tag,
4615 tag_class[info->tclass], info->tag, info->name);
4617 if ((cls == info->tclass) && (tag == info->tag))
4618 break; /* found it */
4621 p = g_node_next_sibling(p);
4623 if (asn1_verbose) {
4624 if (p) g_message(" OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->asn1typename,
4625 info->name);
4626 else g_message(" ...no matching choice...");
4628 return p;
4631 /* offset is for debugging only, a reference to output on screen */
4632 static PDUprops *
4633 getPDUprops(PDUprops *out, guint offset, guint cls, guint tag, guint cons)
4635 statestack pos, pos2, save_pos;
4636 PDUinfo *info;
4637 const char *ret, *tmp;
4638 int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4639 static char namestr[64]; /* enough ? */
4640 static char posstr[40];
4641 static char noname[] = "*noname*";
4642 static PDUprops constructed_save; /* for unexpectedly constructed entities */
4644 if (PDUstatec > 0) /* don't read from below the stack */
4645 pos = POPSTATE;
4646 /* pos refers to the last asn1 node handled */
4648 /* a very simple, too simple??, way to handle constructed entities */
4649 if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4650 /* unexpectedly constructed, return same info as last time */
4651 g_snprintf(posstr, sizeof(posstr), "==off=%d %c%d%c", offset, tag_class[cls], tag, cons?'c':'p');
4652 showstack(&pos, posstr, 3);
4653 pos.offset = offset;
4654 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4655 PUSHNODE(pos); /* push extra, to match with a EOI operation */
4656 PUSHNODE(pos); /* restore the stack */
4657 *out = constructed_save;
4658 if (asn1_verbose)
4659 g_message(" return for constructed %s (%s)%s",
4660 TBLTYPE(out->type), out->asn1typename, out->name);
4661 return out;
4664 save_pos = pos; /* may need it again */
4666 out->type = 0;
4667 out->name = 0;
4668 out->asn1typename = "*error*";
4669 out->fullname = 0;
4670 out->flags = 0;
4671 out->data = 0;
4672 out->value_id = -1;
4673 out->type_id = -1;
4675 if (PDUstatec <= 0) {
4676 if (PDUstatec > -10) {
4677 if (asn1_verbose)
4678 g_message(">>off=%d stack underflow, return", offset);
4680 if (PDUstatec == -10) {
4681 if (asn1_verbose)
4682 g_message(">>off=%d stack underflow, return, no more messages", offset);
4684 out->name = "*underflow*";
4685 out->flags |= OUT_FLAG_noname;
4686 PDUerrcount++;
4687 return out;
4689 g_snprintf(posstr, sizeof(posstr), "==off=%d %c%d%c", offset, tag_class[cls], tag, cons?'c':'p');
4691 showstack(&pos, posstr, 3);
4693 if (cls == ASN1_EOI) { /* end of this input sequence */
4695 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4696 if (asn1_verbose) g_message(" EOI: reference pop");
4697 pos = POPSTATE;
4698 } else
4699 switch(pos.type & TBL_TYPEmask) {
4700 case TBL_TYPEREF:
4701 if (asn1_verbose) g_message(" EOI: pop typeref");
4702 pos = POPSTATE; /* remove typeref */
4703 break;
4704 case TBL_CHOICE_done:
4705 if (asn1_verbose) g_message(" EOI: mark choice");
4706 pos = POPSTATE;
4707 pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4708 PUSHNODE(pos);
4709 break;
4710 default:
4711 break;
4715 pos = POPSTATE; /* this is pushed back on the stack later */
4716 if (pos.node == NULL) {
4717 if (asn1_verbose) g_message(" EOI, pos.node == NULL");
4718 out->name = "*no-name-EOI*";
4719 out->flags |= OUT_FLAG_noname;
4720 PDUerrcount++;
4721 return out;
4724 info = getinfo(pos.node);
4725 ret = info->name;
4726 tmp = TBLTYPE(info->type);
4727 if (offset != pos.offset) {
4728 if (asn1_verbose)
4729 g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4730 tmp, ret, offset, pos.offset);
4731 while ((offset < pos.offset) && (PDUstatec > 0)) {
4732 pos = POPSTATE;
4733 if (asn1_verbose)
4734 g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
4735 offset, pos.offset);
4737 if (offset != pos.offset)
4738 PDUerrcount++; /* only count if still unequal */
4739 } else {
4740 if (asn1_verbose) g_message(" EOI %s:%s OK, offset=%d", tmp, ret, offset);
4742 } else {
4743 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4744 * indicated by the synthetic EOI call. */
4745 if ((cls == BER_CLASS_UNI) && (tag == BER_UNI_TAG_EOC)) { /* explicit EOC never has a name */
4746 PUSHNODE(pos); /* restore stack */
4747 ret = "explicit-EOC";
4748 if (asn1_verbose) g_message(" return '%s', ignore", ret);
4749 out->name = ret;
4750 out->asn1typename = "ASN1";
4751 return out;
4754 /* find appropriate node for this tag */
4756 if (pos.node == NULL) {
4757 if (asn1_verbose) g_message(" pos.node == NULL");
4758 out->name = "*no-name*";
4759 out->flags |= OUT_FLAG_noname;
4760 PDUerrcount++;
4761 return out;
4764 /* showNode(pos.node, 3, 4); */
4766 switch (pos.type & TBL_TYPEmask) {
4767 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4768 case TBL_SET:
4769 break;
4770 default:
4771 if (pos.type & TBL_CHOICE_made) {
4772 if (asn1_verbose) g_message(" finish choice");
4773 donext = 1;
4775 break;
4778 info = getinfo(pos.node);
4780 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4781 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4782 case TBL_CHOICE:
4783 if (asn1_verbose) g_message(" repeating choice"); /* ignore repeat */
4784 break;
4785 default:
4786 if (asn1_verbose) g_message(" seqof: repeat start");
4787 /* decide how to continue, CHILD for next instance of sequence
4788 * or NEXT for end of repeated sequence.
4789 * use the tag to make a descision */
4790 if (asn1_verbose) g_message(" seqof: first got %c%d, found %c%d",
4791 tag_class[cls], tag,
4792 tag_class[info->tclass], info->tag);
4793 if ( MATCH ) {
4794 /* This is the start of repeating */
4795 PUSHNODE(pos);
4796 ret = getname(pos.node);
4797 if (asn1_verbose) g_message(" return for repeat '%s'", ret);
4798 out->type = (pos.type & TBL_TYPEmask);
4799 out->asn1typename = info->asn1typename;
4800 out->name = ret;
4801 out->value_id = info->value_id;
4802 out->type_id = info->type_id;
4803 if (ISANONYMOUS) {
4804 if (asn1_verbose) g_message(" anonymous: dontshow");
4805 if (asn1_debug)
4806 out->flags |= OUT_FLAG_dontshow;
4807 else
4808 out->name = empty;
4810 return out;
4811 } else {
4812 /* find out where to go .... */
4813 pos2 = pos;
4814 CHILD; /* assume sequence is repeated */
4815 if (pos.node) {
4816 info = getinfo(pos.node); /* needed for MATCH to look ahead */
4817 if (asn1_verbose)
4818 g_message(" seqof: child: got %c%d, found %c%d",
4819 tag_class[cls], tag,
4820 tag_class[info->tclass], info->tag);
4822 if (pos2.type & TBL_CHOICE_repeat) {
4823 pos = POPSTATE;
4824 if (asn1_verbose)
4825 g_message(" repeating a choice, %s",
4826 getname(pos.node));
4827 pos.type = TBL_CHOICE_immediate;
4828 } else {
4829 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4830 donext = 1; /* move on */
4831 if (asn1_verbose)
4832 g_message(" seqof: no repeat, force next");
4834 /* following code will take the child again */
4835 pos = pos2;
4838 break;
4840 } else if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4841 if (asn1_verbose) g_message(" reference pop, donext");
4842 pos = POPSTATE;
4843 donext = 1;
4844 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4845 if (pos.type & TBL_SEQUENCE_choice) {
4846 pos = POPSTATE; /* expect to find a repeat here */
4847 } else {
4848 donext = 1;
4849 if (asn1_verbose) g_message(" sequence done, donext");
4853 if (pos.type & TBL_REFERENCE) {
4854 if (asn1_verbose) g_message(" reference change ref -> pop");
4855 pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4858 pos.offset = offset;
4860 if (donext) {
4861 if (asn1_verbose) g_message(" donext");
4862 NEXT;
4863 } else {
4864 switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4865 case TBL_SETOF: /* ?? */
4866 case TBL_SEQUENCEOF:
4867 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4868 pos.type |= TBL_REPEAT;
4869 PUSHNODE(pos);
4870 CHILD;
4871 pushed++;
4872 /* remember this is the start of a repeat cycle */
4873 typeflags |= TBL_REPEAT;
4874 if (asn1_verbose)
4875 g_message(" seqof: set repeat mark [push,child]");
4876 } else {
4877 if (asn1_verbose)
4878 g_message(" seqof: end of repeat loop [next]");
4879 NEXT;
4881 break;
4882 case TBL_SET: /* ?? */
4883 case TBL_SEQUENCE:
4884 pos.type |= TBL_SEQUENCE_done;
4885 PUSHNODE(pos);
4886 CHILD;
4887 pushed++;
4888 if (asn1_verbose) g_message(" seq [push,child]");
4889 break;
4890 case TBL_CHOICE:
4891 /* no more choice */
4892 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4893 PUSHNODE(pos);
4895 pos.type = 0; /* clear all type flags */
4896 if (asn1_verbose)
4897 g_message(" choice [push], %c%d, %s",
4898 tag_class[info->tclass], info->tag, getname(pos.node));
4899 pos.node = makechoice(pos.node, cls, tag);
4900 if (pos.node == NULL) {
4901 pos = POPSTATE;
4902 out->flags |= OUT_FLAG_noname;
4903 PDUerrcount++;
4905 info = getinfo(pos.node);
4907 ret = getname(pos.node);
4908 if (asn1_verbose)
4909 g_message(" '%s' %c%d will be used",
4910 ret, tag_class[info->tclass], info->tag);
4911 break;
4912 case TBL_CHOICE_done:
4913 NEXT;
4914 break;
4915 case TBL_TYPEREF:
4916 pos = POPSTATE;
4917 NEXT;
4918 if (asn1_verbose) g_message(" typeref [pop,next]");
4919 break;
4920 case TBL_ENUMERATED:
4921 case TBL_BITSTRING:
4922 /* skip named numbers now, call to PDUenum() will retrieve a name */
4923 NEXT;
4924 break;
4925 case TBL_CHOICE_immediate:
4926 if (asn1_verbose) g_message(" immediate choice [no next]");
4927 /* nothing */
4928 break;
4929 default:
4930 NEXT;
4931 break;
4935 if (pos.node == NULL) {
4936 ret = "*no-name-2*";
4937 if (asn1_verbose) g_message(" return '%s'", ret);
4938 out->name = ret;
4939 out->flags |= OUT_FLAG_noname;
4940 PDUerrcount++;
4941 return out;
4943 ret = pos.name = getname(pos.node);
4944 pos.type = gettype(pos.node) | (pos.type & ~TBL_TYPEmask);
4945 info = getinfo(pos.node);
4947 /* pos now points to the prospective current node, go check it ********************/
4948 if (asn1_verbose && info) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4949 (ISOPTIONAL)?", optional":empty,
4950 (ISIMPLICIT)?", implicit":empty,
4951 tag_class[info->tclass], info->tag );
4953 if (ISOPTIONAL) { /* must check the tag */
4954 while(! MATCH) { /* check optional here again...? */
4955 if (asn1_verbose && info)
4956 g_message(" got %c%d, found %c%d", tag_class[cls], tag,
4957 tag_class[info->tclass], info->tag);
4958 NEXT;
4959 if (pos.node == NULL) {
4960 ret = "------";
4961 if (cons) {
4962 pos = save_pos; /* reset for next time */
4963 pos.type |= TBL_SEQUENCE_done;
4964 PUSHNODE(pos);
4965 pos.type &= ~TBL_SEQUENCE_done;
4966 cons_handled = 1;
4967 out->flags |= OUT_FLAG_dontshow;
4968 if (asn1_verbose)
4969 g_message(" end of optional list, constructed, expect value next time");
4970 } else {
4971 PDUerrcount++;
4972 out->flags |= OUT_FLAG_noname;
4973 if (asn1_verbose)
4974 g_message(" *end of optional list...");
4975 info = NULL; /* this is not valid any more... */
4977 break; /* end of list */
4979 info = getinfo(pos.node);
4980 if (asn1_verbose) g_message(" optional, %s", getname(pos.node));
4982 if (pos.node && ! cons_handled) {
4983 ret = pos.name = getname(pos.node);
4984 pos.type = gettype(pos.node);
4986 /* pos now refers to node with name we want, optional nodes skipped */
4989 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4990 pos2 = pos; /* save current state */
4991 if ( ! MATCH) {
4992 if (! pushed) {
4993 if (asn1_verbose)
4994 g_message(" already pushed, skip next push");
4995 PUSHNODE(pos);
4996 typeflags &= ~TBL_CHOICE_made;
4999 if (asn1_verbose && info)
5000 g_message(" immediate choice [push], %c%d, %s",
5001 tag_class[info->tclass], info->tag, getname(pos.node));
5002 if (pos.node) {
5003 pos.node = makechoice(pos.node, cls, tag);
5005 if (pos.node == NULL) {
5006 pos = POPSTATE;
5007 PDUerrcount++;
5009 info = getinfo(pos.node);
5010 pos.type = gettype(pos.node);
5011 out->type = (pos.type & TBL_TYPEmask);
5012 out->flags |= OUT_FLAG_type;
5014 g_snprintf(namestr, sizeof(namestr), "%s!%s", ret, getname(pos.node));
5015 ret = namestr;
5016 if (asn1_verbose)
5017 g_message(" %s:%s will be used", TBLTYPE(pos.type), ret);
5018 if (typeflags & TBL_REPEAT) {
5019 pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
5020 PUSHNODE(pos2);
5021 pos.type |= TBL_SEQUENCE_choice;
5022 PUSHNODE(pos);
5023 if (asn1_verbose)
5024 g_message(" return from immediate choice [%s] '%s'",
5025 TBLTYPE(pos.type), ret);
5027 out->data = pos.node; /* for access to named numbers... */
5029 out->type = (pos.type & TBL_TYPEmask);
5030 out->name = ret;
5031 if (info) {
5032 out->asn1typename = info->asn1typename;
5033 out->fullname = info->fullname;
5034 out->value_id = info->value_id;
5035 out->type_id = info->type_id;
5038 return out;
5039 } else {
5040 typeflags |= TBL_CHOICE_made;
5042 } else {
5043 if (asn1_verbose) g_message(" matching choice '%s'", ret);
5045 if ( ! cons ) { /* ISIMPLICIT was not OK for all */
5046 pos = pos2; /* reset for continuation */
5049 if (asn1_verbose) {
5050 if (info)
5051 g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
5052 (ISOPTIONAL)?", optional":empty,
5053 (ISIMPLICIT)?", implicit":empty,
5054 tag_class[info->tclass], info->tag );
5055 else
5056 g_message(" using: unknown '%s'", ret);
5059 /* must follow references now */
5060 if (pos.type == TBL_TYPEREF && info) {
5061 out->asn1typename = info->asn1typename;
5062 out->type_id = info->typenum;
5063 out->flags |= OUT_FLAG_typename;
5064 PUSHNODE(pos); /* remember where we were */
5065 if (asn1_verbose) g_message(" typeref [push]");
5066 typeflags |= TBL_REFERENCE;
5067 if (info->reference == 0) { /* resolved ref to universal type.... */
5068 /* showNode(pos.node, 3, 4); */
5069 pos.type = gettype(pos.node); /* the resulting type */
5070 info = getinfo(pos.node);
5071 tmp = "unknown tag";
5072 if (info && (info->tclass == BER_CLASS_UNI) && (info->tag < 31)) {
5073 tmp = asn1_tag[info->tag];
5074 pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
5076 if (asn1_verbose && info)
5077 g_message(" indirect typeref to %s:%s, %s [%c%d]",
5078 TBLTYPE(pos.type), info->asn1typename, tmp,
5079 tag_class[info->tclass], info->tag );
5080 } else {
5081 out->fullname = info->fullname;
5082 donext = (ISANONYMOUS); /* refereing entity has no name ? */
5083 pos.node = info->reference;
5084 pos.type = gettype(pos.node);
5085 info = getinfo(pos.node);
5086 if (asn1_verbose)
5087 g_message(" typeref %s %s", TBLTYPE(pos.type), getname(pos.node));
5088 /* keep name from before going through the reference, unless anonymous */
5089 if (donext) /* refering entity has no name */
5090 ret = getname(pos.node); /* a better name */
5092 /* handle choice here ? !!mm!! */
5094 out->type = (pos.type & TBL_TYPEmask);
5095 out->flags |= OUT_FLAG_type;
5096 /* showNode(pos.node, 3, 4); */
5097 /* ret = getname(pos.node);*/
5099 out->data = pos.node;
5100 out->flags |= OUT_FLAG_data;
5101 if (asn1_verbose)
5102 g_message(" typeref set named number list node %p", (void *)pos.node);
5104 if ( ! cons) {
5105 pos = POPSTATE;
5106 pos.type = TBL_TYPEREF_nopop;
5107 if (asn1_verbose) g_message(" typeref pop");
5108 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
5109 /* do not enter the named-number list */
5110 pos = POPSTATE;
5111 pos.type = TBL_TYPEREF_nopop;
5112 if (asn1_verbose) g_message(" typeref [pop]");
5113 } else {
5114 typeflags |= TBL_REFERENCE;
5119 if (cons && ! cons_handled) { /* This entity is constructed, expected ? */
5120 switch(pos.type) {
5121 case TBL_BOOLEAN: /* these are not expected to be constructed */
5122 case TBL_INTEGER:
5123 case TBL_OCTETSTRING:
5124 case TBL_NULL:
5125 case TBL_OID:
5126 case TBL_REAL:
5127 case TBL_ENUMERATED:
5128 case TBL_TYPEREF:
5129 typeflags |= TBL_CONSTRUCTED;
5130 /* this entry has no extra info, next is the same */
5131 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
5132 if (asn1_verbose) g_message(" dontshow and set constructed flag");
5133 break;
5134 default: /* others, such as sequences, are expected to be constructed */
5135 break;
5140 if (ISANONYMOUS) {
5141 if (asn1_verbose) g_message(" anonymous: dontshow");
5142 if (asn1_debug) /* this entry has no extra info, next is the same */
5143 out->flags |= OUT_FLAG_dontshow;
5144 else
5145 out->name = empty; /* show it, but no name */
5148 if (out->name != empty)
5149 out->name = ret;
5151 if ( ! (out->flags & OUT_FLAG_data))
5152 out->data = pos.node; /* for access to named numbers... */
5154 pos.type |= typeflags;
5155 PUSHNODE(pos);
5157 if ( ! (out->flags & OUT_FLAG_type))
5158 out->type = pos.type;
5160 out->type &= TBL_TYPEmask;
5162 if (ret == noname) {
5163 PDUerrcount++;
5164 out->flags |= OUT_FLAG_noname;
5167 if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
5168 out->asn1typename = info->asn1typename;
5169 out->type_id = info->typenum;
5172 if (info && (out->value_id == -1)) {
5173 out->value_id = info->value_id;
5174 out->type_id = info->type_id;
5177 if ((out->fullname == 0) && info)
5178 out->fullname = info->fullname;
5180 if (typeflags & TBL_CONSTRUCTED)
5181 constructed_save = *out;
5183 if (asn1_verbose)
5184 g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
5185 out->value_id, out->type_id);
5187 return out;
5190 static const char *
5191 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
5193 GNode *list;
5194 PDUinfo *info;
5195 const char *ret, *name;
5196 static char unnamed[] = "*unnamed*";
5198 (void) cls; (void) tag; /* make a reference */
5200 if (props->flags & OUT_FLAG_noname)
5201 return empty;
5203 ret = unnamed;
5204 list = (GNode *)props->data;
5206 if (list == 0) {
5207 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
5208 PDUerrcount++;
5209 return "*list-still-0*";
5212 if ((PDUinfo *)list->data)
5213 name = ((PDUinfo *)list->data)->name;
5214 else
5215 name = ret;
5217 for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
5218 info = (PDUinfo *)list->data;
5219 if (value == info->tag) {
5220 ret = info->name;
5221 break;
5224 if (ret == unnamed)
5225 PDUerrcount++;
5227 if (asn1_verbose)
5228 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
5229 return ret;
5232 #endif /* READSYNTAX */
5234 void
5235 proto_register_asn1(void) {
5237 static const enum_val_t type_recursion_opts[] = {
5238 { "0", "0", 0 },
5239 { "1", "1", 1 },
5240 { "2", "2", 2 },
5241 { "3", "3", 3 },
5242 { "4", "4", 4 },
5243 { "4", "5", 5 },
5244 { "6", "6", 6 },
5245 { "7", "7", 7 },
5246 { "8", "8", 8 },
5247 { "9", "9", 9 },
5248 { NULL, NULL, -1},
5251 gint *ett[1+MAX_NEST+MAXPDU];
5253 module_t *asn1_module;
5254 int i, j;
5255 const char *orig_ptr;
5257 asn1_logfile = get_tempfile_path(ASN1LOGFILE);
5259 current_asn1 = g_strdup("");
5260 asn1_filename = g_strdup(current_asn1);
5262 current_pduname = g_strdup("ASN1");
5263 asn1_pduname = g_strdup(current_pduname);
5265 proto_asn1 = proto_register_protocol("ASN.1 decoding",
5266 "ASN1", pabbrev);
5268 ett[0] = &ett_asn1;
5269 for (i=0, j=1; i<MAX_NEST; i++, j++) {
5270 ett[j] = &ett_seq[i];
5271 ett_seq[i] = -1;
5273 for(i=0; i<MAXPDU; i++, j++) {
5274 ett[j] = &ett_pdu[i];
5275 ett_pdu[i] = -1;
5278 proto_register_subtree_array(ett, array_length(ett));
5280 asn1_module = prefs_register_protocol(proto_asn1,
5281 proto_reg_handoff_asn1);
5282 #ifdef JUST_ONE_PORT
5283 prefs_register_uint_preference(asn1_module, "tcp_port",
5284 "ASN.1 TCP Port",
5285 "The TCP port on which "
5286 "ASN.1 messages will be read",
5287 10, &global_tcp_port_asn1);
5288 prefs_register_uint_preference(asn1_module, "udp_port",
5289 "ASN.1 UDP Port",
5290 "The UDP port on which "
5291 "ASN.1 messages will be read",
5292 10, &global_udp_port_asn1);
5293 prefs_register_uint_preference(asn1_module, "sctp_port",
5294 "ASN.1 SCTP Port",
5295 "The SCTP port on which "
5296 "ASN.1 messages will be read",
5297 10, &global_sctp_port_asn1);
5298 #else
5299 range_convert_str(&global_tcp_ports_asn1, ep_strdup_printf("%u", TCP_PORT_ASN1), 65535);
5300 range_convert_str(&global_udp_ports_asn1, ep_strdup_printf("%u", UDP_PORT_ASN1), 65535);
5301 range_convert_str(&global_sctp_ports_asn1, ep_strdup_printf("%u", SCTP_PORT_ASN1), 65535);
5303 prefs_register_range_preference(asn1_module, "tcp_ports",
5304 "ASN.1 TCP Ports",
5305 "The TCP ports on which "
5306 "ASN.1 messages will be read",
5307 &global_tcp_ports_asn1, 65535);
5308 prefs_register_range_preference(asn1_module, "udp_ports",
5309 "ASN.1 UDP Ports",
5310 "The UDP ports on which "
5311 "ASN.1 messages will be read",
5312 &global_udp_ports_asn1, 65535);
5313 prefs_register_range_preference(asn1_module, "sctp_ports",
5314 "ASN.1 SCTP Ports",
5315 "The SCTP ports on which "
5316 "ASN.1 messages will be read",
5317 &global_sctp_ports_asn1, 65535);
5318 #endif /* JUST_ONE_PORT */
5320 prefs_register_bool_preference(asn1_module, "desegment_messages",
5321 "Desegment TCP",
5322 "Desegment ASN.1 messages that span TCP segments",
5323 &asn1_desegment);
5325 old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
5326 #ifdef _WIN32
5327 bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
5328 #endif
5330 orig_ptr = asn1_filename;
5331 prefs_register_filename_preference(asn1_module, "file",
5332 "ASN.1 type table file",
5333 "Compiled ASN.1 description of ASN.1 types",
5334 &asn1_filename);
5335 /* prefs_register_string_preference just overwrite our pointer with a pointer
5336 * to a _copy_ of our string. Free the original string.
5338 g_free((char *)orig_ptr);
5340 orig_ptr = asn1_pduname;
5341 prefs_register_string_preference(asn1_module, "pdu_name",
5342 "ASN.1 PDU name",
5343 "Name of top level PDU",
5344 &asn1_pduname);
5345 g_free((char *)orig_ptr);
5347 prefs_register_uint_preference(asn1_module, "first_pdu_offset",
5348 "Offset to first PDU in first tcp packet",
5349 "Offset for non-reassembled packets, "
5350 "wrong if this happens on other than the first packet!",
5351 10, &first_pdu_offset);
5352 prefs_register_bool_preference(asn1_module, "flat",
5353 "Show full names",
5354 "Show full names for all values",
5355 &asn1_full);
5356 prefs_register_enum_preference(asn1_module, "type_recursion",
5357 "Eliminate references to level",
5358 "Allow this recursion level for eliminated type references",
5359 &type_recursion_level,
5360 type_recursion_opts, FALSE);
5361 prefs_register_bool_preference(asn1_module, "debug",
5362 "ASN.1 debug mode",
5363 "Extra output useful for debugging",
5364 &asn1_debug);
5365 #if 0
5366 prefs_register_bool_preference(asn1_module, "message_win",
5367 "Show ASN.1 tree",
5368 "show full message description",
5369 &asn1_message_win);
5370 #else
5371 prefs_register_obsolete_preference(asn1_module, "message_win");
5372 #endif
5373 prefs_register_bool_preference(asn1_module, "verbose_log",
5374 "Write very verbose log",
5375 "log to file $TMP/" ASN1LOGFILE,
5376 &asn1_verbose);
5379 /* The registration hand-off routing */
5381 static dissector_handle_t asn1_handle;
5383 static void
5384 register_tcp_port(guint32 port)
5386 if (port != 0)
5387 dissector_add_uint("tcp.port", port, asn1_handle);
5390 static void
5391 unregister_tcp_port(guint32 port)
5393 if (port != 0)
5394 dissector_delete_uint("tcp.port", port, asn1_handle);
5397 static void
5398 register_udp_port(guint32 port)
5400 if (port != 0)
5401 dissector_add_uint("udp.port", port, asn1_handle);
5404 static void
5405 unregister_udp_port(guint32 port)
5407 if (port != 0)
5408 dissector_delete_uint("udp.port", port, asn1_handle);
5411 static void
5412 register_sctp_port(guint32 port)
5414 if (port != 0)
5415 dissector_add_uint("sctp.port", port, asn1_handle);
5418 static void
5419 unregister_sctp_port(guint32 port)
5421 if (port != 0)
5422 dissector_delete_uint("sctp.port", port, asn1_handle);
5425 void
5426 proto_reg_handoff_asn1(void) {
5427 static gboolean asn1_initialized = FALSE;
5428 /* XXX: Note that the "saved" ports [or port ranges] will not be initialized the first time */
5429 /* thru pro_reg_handoff_asn1 if no PDUtree is built; So: we init with the definition. */
5430 #ifdef JUST_ONE_PORT
5431 static guint tcp_port_asn1 = 0;
5432 static guint udp_port_asn1 = 0;
5433 static guint sctp_port_asn1 = 0;
5434 #else
5435 static range_t *tcp_ports_asn1 = NULL;
5436 static range_t *udp_ports_asn1 = NULL;
5437 static range_t *sctp_ports_asn1 = NULL;
5438 #endif
5440 pcount = 0;
5442 #ifdef JUST_ONE_PORT
5443 if (asn1_verbose) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegment=%d, "
5444 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5445 global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
5446 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5447 #else
5448 if (asn1_verbose) {
5449 char *tcp_ports_asn1_string, *udp_ports_asn1_string, *sctp_ports_asn1_string;
5450 tcp_ports_asn1_string = range_convert_range(global_tcp_ports_asn1);
5451 udp_ports_asn1_string = range_convert_range(global_udp_ports_asn1);
5452 sctp_ports_asn1_string = range_convert_range(global_sctp_ports_asn1);
5453 g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegment=%d, "
5454 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5455 tcp_ports_asn1_string, udp_ports_asn1_string, sctp_ports_asn1_string, asn1_desegment,
5456 asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5458 #endif /* JUST_ONE_PORT */
5460 if(!asn1_initialized) {
5461 asn1_handle = new_create_dissector_handle(dissect_asn1,proto_asn1);
5462 asn1_initialized = TRUE;
5463 } else { /* clean up ports and their lists */
5464 #ifdef JUST_ONE_PORT
5465 unregister_tcp_port(tcp_port_asn1);
5466 unregister_udp_port(udp_port_asn1);
5467 unregister_sctp_port(sctp_port_asn1);
5468 #else
5469 if (tcp_ports_asn1 != NULL) {
5470 range_foreach(tcp_ports_asn1, unregister_tcp_port);
5471 g_free(tcp_ports_asn1);
5474 if (udp_ports_asn1 != NULL) {
5475 range_foreach(udp_ports_asn1, unregister_udp_port);
5476 g_free(udp_ports_asn1);
5479 if (sctp_ports_asn1 != NULL) {
5480 range_foreach(sctp_ports_asn1, unregister_sctp_port);
5481 g_free(sctp_ports_asn1);
5483 #endif /* JUST_ONE_PORT */
5486 if (strcmp(asn1_filename, current_asn1) != 0) {
5487 /* new definitions, parse the file if we have one */
5488 /* !!! should be postponed until we really need it !!! */
5489 #ifdef READSYNTAX
5490 read_asn1_type_table(asn1_filename);
5491 #endif /* READSYNTAX */
5492 g_free(current_asn1);
5493 current_asn1 = g_strdup(asn1_filename);
5495 if (!PDUtree || /* no tree built yet for PDU type */
5496 strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
5497 if (build_pdu_tree(asn1_pduname)) {
5498 g_free(current_pduname);
5499 current_pduname = g_strdup(asn1_pduname);
5502 #ifdef SHOWPDU
5503 if (asn1_message_win) { /* show what we are prepared to recognize */
5504 if (window) {
5505 gtk_widget_destroy (window);
5506 window = NULL;
5508 create_message_window();
5510 #endif /* SHOWPDU */
5512 /* If we now have a PDU tree, register for the port or ports we have */
5513 if (PDUtree) {
5514 #ifdef JUST_ONE_PORT
5515 tcp_port_asn1 = global_tcp_port_asn1;
5516 udp_port_asn1 = global_udp_port_asn1;
5517 sctp_port_asn1 = global_sctp_port_asn1;
5519 register_tcp_port(tcp_port_asn1);
5520 register_udp_port(udp_port_asn1);
5521 register_sctp_port(sctp_port_asn1);
5522 #else
5523 tcp_ports_asn1 = range_copy(global_tcp_ports_asn1);
5524 udp_ports_asn1 = range_copy(global_udp_ports_asn1);
5525 sctp_ports_asn1 = range_copy(global_sctp_ports_asn1);
5527 range_foreach(tcp_ports_asn1, register_tcp_port);
5528 range_foreach(udp_ports_asn1, register_udp_port);
5529 range_foreach(sctp_ports_asn1, register_sctp_port);
5530 #endif /* JUST_ONE_PORT */