Use <wiretap/file_util.h> to include "file_util.h"; otherwise, the
[obnox/wireshark/wip.git] / plugins / asn1 / packet-asn1.c
index f3b39f99ca08e0fcf20526c6db3e957c0ad79ee1..f38f6bbc662ad6b91fec7487ddf5565c779b5a73 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2003 by Matthijs Melchior <matthijs.melchior@xs4all.nl>
  *
- * $Id: packet-asn1.c,v 1.5 2003/10/29 10:54:17 guy Exp $
+ * $Id$
  *
  * A plugin for:
  *
@@ -67,8 +67,6 @@
 #include <sys/stat.h>
 #include <errno.h>
 
-#include "plugins/plugin_api.h"
-
 #include "moduleinfo.h"
 
 #include <stdio.h>
 #include <time.h>
 #include <string.h>
 #include <epan/packet.h>
-#include <epan/resolv.h>
-#include "prefs.h"
+#include <epan/addr_resolv.h>
+#include <epan/prefs.h>
 #include <epan/strutil.h>
 #include <epan/filesystem.h>
-#include "asn1.h"
-#include "simple_dialog.h"
-
-#include "plugins/plugin_api_defs.h"
+#include <epan/report_err.h>
+#include <epan/dissectors/packet-tcp.h>
+#include <epan/asn1.h>
+#include <wiretap/file_util.h>
 
+#ifdef DISSECTOR_WITH_GUI
 #include <gtk/gtk.h>
+#endif
 
-#include <ipproto.h>
+#include <epan/ipproto.h>
 
 /* Define version if we are not building ethereal statically */
 
-#ifndef __ETHEREAL_STATIC__
+#ifndef ENABLE_STATIC
 G_MODULE_EXPORT const gchar version[] = VERSION;
 #endif
 
@@ -106,6 +106,7 @@ G_MODULE_EXPORT const gchar version[] = VERSION;
 
 #define TCP_PORT_ASN1 801
 #define UDP_PORT_ASN1 801
+#define SCTP_PORT_ASN1 801
 
 void proto_reg_handoff_asn1(void);
 
@@ -127,30 +128,43 @@ static int ett_seq[MAX_NEST];
  * Global variables associated with the preferences for asn1
  */
 
+#ifdef JUST_ONE_PORT
 static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
 static guint global_udp_port_asn1 = UDP_PORT_ASN1;
+static guint global_sctp_port_asn1 = SCTP_PORT_ASN1;
 static guint tcp_port_asn1 = TCP_PORT_ASN1;
 static guint udp_port_asn1 = UDP_PORT_ASN1;
+static guint sctp_port_asn1 = SCTP_PORT_ASN1;
+#else
+static range_t *global_tcp_ports_asn1;
+static range_t *global_udp_ports_asn1;
+static range_t *global_sctp_ports_asn1;
+
+static range_t *tcp_ports_asn1;
+static range_t *udp_ports_asn1;
+static range_t *sctp_ports_asn1;
+#endif /* JUST_ONE_PORT */
 
 static gboolean asn1_desegment = TRUE;
-static char *asn1_filename = 0;
-static char *default_asn1_filename = 0;
-#define ASN1FILE "asn1/default.tt"
-static char *current_asn1 = 0;
-static char *asn1_pduname = 0;
-static char *current_pduname = 0;
+static const char *asn1_filename = NULL;
+static char *old_default_asn1_filename = NULL;
+#define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
+#ifdef _WIN32
+#define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
+static char *bad_separator_old_default_asn1_filename = NULL;
+#endif
+static char *current_asn1 = NULL;
+static const char *asn1_pduname = NULL;
+static char *current_pduname = NULL;
 static gboolean asn1_debug = FALSE;
 static guint first_pdu_offset = 0;
 static gboolean asn1_message_win = FALSE;
 static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
 static gboolean asn1_full = FALSE; /* show full names */
 static guint type_recursion_level = 1; /* eliminate 1 level of references */
-static char *asn1_logfile = 0;
-#ifdef WIN32
-#define ASN1LOGFILE "C:\\temp\\ethereal.log"
-#else
-#define ASN1LOGFILE "/tmp/ethereal.log"
-#endif
+static char *asn1_logfile = NULL;
+
+#define ASN1LOGFILE "ethereal.log"
 
 /* PDU counter, for correlation between GUI display and log file in debug mode */
 static int pcount = 0;
@@ -165,10 +179,10 @@ static guint PDUerrcount = 0;   /* count of parse errors in one ASN.1 message */
 #define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
 
 
-char pabbrev[] = "asn1";       /* field prefix */
+static char pabbrev[] = "asn1";        /* field prefix */
 
-char fieldname[512];           /* for constructing full names */
-guint pabbrev_pdu_len;         /* length initial part of fieldname with 'abbrev.asn1pdu.' */
+static char fieldname[512];            /* for constructing full names */
+static guint pabbrev_pdu_len;          /* length initial part of fieldname with 'abbrev.asn1pdu.' */
 
 /*
  * Text strings describing the standard, universal, ASN.1 names.
@@ -177,13 +191,13 @@ guint pabbrev_pdu_len;            /* length initial part of fieldname with 'abbrev.asn1pdu
 #define ASN1_EOI 4 /* this is in the class number space... */
 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
 
-char tag_class[] = "UACPX";
+static const char tag_class[] = "UACPX";
 
-char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
+static const char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
 
-char *asn1_con[] = { "Primitive", "Constructed" };
+static const char *asn1_con[] = { "Primitive", "Constructed" };
 
-char *asn1_tag[] = {
+static const char *asn1_tag[] = {
        /*  0 */ "EOC",             "Boolean",        "Integer",          "BitString",
        /*  4 */ "OctetString",     "Null",           "ObjectIdentifier", "ObjectDescriptor",
        /*  8 */ "External",        "Real",           "Enumerated",       "tag11",
@@ -197,7 +211,7 @@ char *asn1_tag[] = {
 };
 
 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
-gboolean tbl_types_verified = FALSE;
+static gboolean tbl_types_verified = FALSE;
 
 typedef enum { /* copied from .../snacc/c-lib/boot/tbl.h */
         TBL_BOOLEAN = 0,
@@ -222,11 +236,11 @@ typedef enum {    /* copied from .../snacc/c-lib/boot/tbl.h */
        TBL_reserved,           /* this sequence has been visited */
        TBL_CHOICE_immediate,   /* immediate choice, no next */
 
-       TBL_INVALID,            /* incorrect value for this enum */
+       TBL_INVALID             /* incorrect value for this enum */
 } TBLTypeId;
 
 /* Universal tags mapped to snacc ASN.1 table types */
-int asn1_uni_type[] = {
+static int asn1_uni_type[] = {
        /*  0 */ TBL_INVALID,     TBL_BOOLEAN,     TBL_INTEGER,     TBL_BITSTRING,
        /*  4 */ TBL_OCTETSTRING, TBL_NULL,        TBL_OID,         TBL_INVALID,
        /*  8 */ TBL_INVALID,     TBL_REAL,        TBL_ENUMERATED,  TBL_INVALID,
@@ -253,7 +267,8 @@ int asn1_uni_type[] = {
 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
 
 /* text tables for debugging and GUI */
-char *tbl_types[] = {  /*  0 */        "tbl-boolean",
+static const char *tbl_types[] = {
+                      /*  0 */ "tbl-boolean",
                       /*  1 */ "tbl-integer",
                       /*  2 */ "tbl-bitstring",
                       /*  2 */ "tbl-octetstring",
@@ -276,7 +291,7 @@ char *tbl_types[] = {  /*  0 */     "tbl-boolean",
 
                       /* 19 */ "tbl-invalid",
 };
-char *tbl_types_asn1[] = {
+static const char *tbl_types_asn1[] = {
                       /*  0 */ "BOOLEAN",
                       /*  1 */ "INTEGER",
                       /*  2 */ "BITSTRING",
@@ -301,7 +316,7 @@ char *tbl_types_asn1[] = {
                       /* 19 */ "INVALID entry",
 };
 /* conversion from snacc type to appropriate ethereal type */
-guint tbl_types_ethereal[] = {
+static guint tbl_types_ethereal[] = {
                       /*  0 */ FT_BOOLEAN,     /* TBL_BOOLEAN */
                       /*  1 */ FT_UINT32,      /* TBL_INTEGER */
                       /*  2 */ FT_UINT32,      /* TBL_BITSTRING */
@@ -326,7 +341,7 @@ guint tbl_types_ethereal[] = {
                       /* 19 */ FT_NONE,        /* TBL_INVALID */               
 };
 
-char *tbl_types_ethereal_txt[] = {
+static const char *tbl_types_ethereal_txt[] = {
                       /*  0 */ "FT_BOOLEAN",   /* TBL_BOOLEAN */
                       /*  1 */ "FT_UINT32",    /* TBL_INTEGER */
                       /*  2 */ "FT_UINT32",    /* TBL_BITSTRING */
@@ -351,15 +366,47 @@ char *tbl_types_ethereal_txt[] = {
                       /* 19 */ "FT_NONE",      /* TBL_INVALID */               
 };
 
+typedef struct _PDUinfo PDUinfo;
+struct _PDUinfo {
+       guint type;
+       const char *name;
+       const char *typename;
+       const char *fullname;
+       guchar tclass;
+       guint tag;
+       guint flags;
+       GNode *reference;
+       gint typenum;
+       gint basetype;          /* parent type */
+       gint mytype;            /* original type number, typenum may have gone through a reference */
+       gint value_id;          /* ethereal field id for the value in this PDU */
+       gint type_id;           /* ethereal field id for the type of this PDU */
+       hf_register_info value_hf; /* ethereal field info for this value */
+};
+
+
+/* bits in the flags collection */
+#define PDU_OPTIONAL    1
+#define PDU_IMPLICIT    2
+#define PDU_NAMEDNUM    4
+#define PDU_REFERENCE    8
+#define PDU_TYPEDEF   0x10
+#define PDU_ANONYMOUS 0x20
+#define PDU_TYPETREE  0x40
+
+#define PDU_CHOICE    0x08000000   /* manipulated by the PDUname routine */
+
+static guint PDUinfo_initflags = 0;    /* default flags for newly allocated PDUinfo structs */
+
 /* description of PDU properties as passed from the matching routine
  * to the decoder and GUI.
  */
 typedef struct _PDUprops PDUprops;
 struct _PDUprops {
        guint type;     /* value from enum TBLTypeId */
-       char *name;
-       char *typename;
-       char *fullname;
+       const char *name;
+       const char *typename;
+       const char *fullname;
        guint flags;
        gpointer data;
        gint value_id;
@@ -373,10 +420,10 @@ struct _PDUprops {
 #define OUT_FLAG_noname             0x10
 #define OUT_FLAG_constructed 0x20
 
-PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
-char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
+static PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
+static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
 
-char empty[] = "";             /* address of the empt string, avoids many tests for NULL */
+static const char empty[] = "";                /* address of the empt string, avoids many tests for NULL */
 #define MAX_OTSLEN 256         /* max printed size for an octet string */
 
 
@@ -385,12 +432,12 @@ char empty[] = "";                /* address of the empt string, avoids many tests for NULL */
 #ifdef NEST                    /* only for debugging */
 /* show nesting, only for debugging... */
 #define MAXTAGS MAX_NEST
-struct {
+static struct {
        guchar cls;
        guchar tag;
 } taglist[MAXTAGS];
 
-char *showtaglist(guint level)
+static char *showtaglist(guint level)
 {
        static char tagtxt[BUFLM];
        char *p = tagtxt;
@@ -419,7 +466,7 @@ char *showtaglist(guint level)
        return tagtxt;
 }
 
-guint
+static guint
 get_context(guint level)
 {
        guint ctx = 0;
@@ -437,7 +484,7 @@ get_context(guint level)
 /* Convert a bit string to an ascii representation for printing
  * -- not thread safe ...
  */
-char *showbits(guchar *val, guint count)
+static const char *showbits(guchar *val, guint count)
 {
        static char str[BUFLM];
        guint i;
@@ -457,7 +504,8 @@ char *showbits(guchar *val, guint count)
 }
 
 /* get bitnames string for bits set */
-char * showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
+static const char *
+showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
 {
        static char str[BUFLL];
        guint i;
@@ -487,7 +535,7 @@ char * showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
 /* Convert an oid to its conventional text representation
  * -- not thread safe...
  */
-char *showoid(subid_t *oid, guint len)
+static char *showoid(subid_t *oid, guint len)
 {
        static char str[BUFLM];
        guint i;
@@ -504,12 +552,13 @@ char *showoid(subid_t *oid, guint len)
 }
 
 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
-char *showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
+static char *
+showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
 {
        guint dohex = 0;
        guint i;
        char *str, *p;
-       char *endstr = empty;
+       const char *endstr = empty;
 
        if (len == 0) {
                str = g_malloc(1);
@@ -550,7 +599,7 @@ char *showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, a
 }
 
 /* allow NULL pointers in strcmp, handle them as empty strings */
-int
+static int
 g_strcmp(gconstpointer a, gconstpointer b)
 {
        if (a == 0) a = empty;
@@ -558,8 +607,103 @@ g_strcmp(gconstpointer a, gconstpointer b)
        return strcmp(a, b);
 }
 
-guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
-void PDUreset(int count, int counr2);
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* WARNING   WARNING   WARNING   WARNING   WARNING   WARNING */
+/*                                                          */
+/* Most of the following routine is guesswork in order to    */
+/* speed up resynchronisation if the dissector lost the      */
+/* encoding due to incomplete captures, or a capture that    */
+/* starts in the middle of a fragmented ip packet            */
+/* If this poses to many problems, these settings can be     */
+/* made part of the protocol settings in the user interface  */
+/*************************************************************/
+
+/* check length for a reasonable value, return a corrected value */
+static int
+checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
+{
+       int newlen = len;
+
+       if ( ! def) {
+               g_snprintf(lenstr, strmax, "indefinite");
+               return len;
+       }
+
+       if (len < 0)            /* negative ..... */
+               newlen = 4;
+
+       if (cls != ASN1_UNI) {  /* don't know about the tags */
+               if (len > 131071)
+                       newlen = 64;
+       } else {
+               switch (tag) {
+               case ASN1_EOC:  /* End Of Contents    */
+               case ASN1_NUL:  /* Null               */
+                       newlen = 0;
+                       break;
+               case ASN1_BOL:  /* Boolean            */
+                       newlen = 1;
+                       break;
+               case ASN1_INT:  /* Integer            */
+               case ASN1_ENUM: /* Enumerated         */
+                       if (len > 8)
+                               newlen = 4;
+                       break;
+               case ASN1_BTS:  /* Bit String         */
+                       if (len > 8)
+                               newlen = 4;
+                       break;
+               case ASN1_OTS:  /* Octet String       */
+               case ASN1_NUMSTR: /* Numerical String   */
+               case ASN1_PRNSTR: /* Printable String   */
+               case ASN1_TEXSTR: /* Teletext String    */
+               case ASN1_VIDSTR: /* Video String       */
+               case ASN1_IA5STR: /* IA5 String         */
+               case ASN1_GRASTR: /* Graphical String   */
+               case ASN1_VISSTR: /* Visible String     */
+               case ASN1_GENSTR: /* General String     */
+               if (len > 65535)
+                       newlen = 32;
+               break;
+               case ASN1_OJI:          /* Object Identifier  */
+               case ASN1_OJD:          /* Description        */
+               case ASN1_EXT:          /* External           */
+                       if (len > 64)
+                               newlen = 16;
+                       break;
+               case ASN1_REAL:         /* Real               */
+                       if (len >16)
+                               newlen = 8;
+                       break;
+               case ASN1_SEQ:          /* Sequence           */
+               case ASN1_SET:          /* Set                */
+                       if (len > 65535)
+                               newlen = 64;
+                       break;
+               case ASN1_UNITIM:       /* Universal Time     */
+               case ASN1_GENTIM:       /* General Time       */
+                       if (len > 32)
+                               newlen = 15;
+                       break;
+
+               default:
+                       if (len > 131071)
+                               newlen = 64;
+                       break;                                                  
+               }
+       }
+
+       if (newlen != len) {
+               /* a change was needed.... */
+               g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
+       } else {
+               g_snprintf(lenstr, strmax, "%d", len);
+       }
+       return newlen;
+}
+
+static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
+static void PDUreset(int count, int counr2);
 
 static void 
 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
@@ -570,7 +714,7 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
   char tagstr[BUFLS];
   char headstr[BUFLL];
   char offstr[BUFLS];
-  char *name;
+  const char *name, *tname;
   volatile guint boffset;
   volatile int i = 0;          /* PDU counter */
   proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
@@ -607,7 +751,7 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
   offstr[0] = 0;
   if ((first_pdu_offset > 0) && !reassembled) {
          boffset = first_pdu_offset;
-         snprintf(offstr, sizeof(offstr), " at %d", boffset);
+         g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
   }
 
   /* open BER decoding */
@@ -620,17 +764,17 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
   PDUreset(pcount, 0);         /* arguments are just for debugging */
   getPDUprops(&props, boffset, cls, tag, con);
   name = props.name;
+  tname = props.typename;
+
+  len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
 
   if (asn1_debug) {
-         if (def) {
-                 snprintf(lenstr, sizeof(lenstr), "%d", len);
-         } else {
-                 strncpy(lenstr, "indefinite", sizeof(lenstr) );
-         }
-         snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
 
-         snprintf(headstr, sizeof(headstr), "first%s: %s %d %s, %s, %s, len=%s, off=%d, size=%d ",
+         g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
+
+         g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
                   offstr,
+                  tname,
                   name,   
                   pcount,
                   asn1_cls[cls],
@@ -642,12 +786,12 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                  );
   } else {
          if (props.flags & OUT_FLAG_noname) {
-                 snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
+                 g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
                  name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
          }
-         snprintf(headstr, sizeof(headstr), "first pdu%s: %s ", offstr, name );
+         g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
   }
-  
+
   /* Set the info column */
   if(check_col(pinfo->cinfo, COL_INFO)){
     col_add_str(pinfo->cinfo, COL_INFO, headstr );
@@ -670,6 +814,9 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 
        tree2 = proto_item_add_subtree(ti, ett_asn1);
        
+       proto_tree_add_item_hidden(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
+                                  def? (int) (offset - boffset + len) :  -1, TRUE);
+
        offset = boffset; /* the first packet */
         while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
            ti2 = 0;
@@ -682,19 +829,18 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
            PDUreset(pcount, i+1);
            getPDUprops(&props, boffset, cls, tag, con);
            name = props.name;
+           tname = props.typename;
            
            if (!def)
                    len = tvb_length_remaining(tvb, offset);
 
+           len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
+
            if (asn1_debug) {
-                   if (def) {
-                           snprintf(lenstr, sizeof(lenstr), "%d", len);
-                   } else {
-                           strncpy(lenstr, "indefinite", sizeof(lenstr));
-                   }
-                   snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
 
-                   snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
+                   g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
+
+                   g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
                             asn1_cls[cls],
                             asn1_con[con],
                             ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
@@ -705,13 +851,13 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                    if (props.value_id == -1)
                            ti2 = proto_tree_add_text(tree2, tvb, boffset,
                                                      def? (int) (offset - boffset + len) :  -1,
-                                                     "%s: %s %d-%d %s", current_pduname, name,
-                                                     pcount, i+1, headstr);
+                                                     "%s: (%s)%s %d-%d %s", current_pduname,
+                                                     tname, name, pcount, i+1, headstr);
                    else {
                            ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
                                                      def? (int) (offset - boffset + len) :  -1,
-                                                     "%s: %s %d-%d %s ~", current_pduname, name,
-                                                     pcount, i+1, headstr);
+                                                     "%s: (%s)%s %d-%d %s ~", current_pduname,
+                                                     tname, name, pcount, i+1, headstr);
 
                             if (props.type_id != -1)
                                 proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
@@ -720,17 +866,17 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                    }
            } else {
                    if (props.flags & OUT_FLAG_noname) {
-                           snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
+                           g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
                            name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
                    }
                    if (props.value_id == -1)
                            ti2 = proto_tree_add_text(tree2, tvb, boffset,
                                                      def? (int) (offset - boffset + len) :  -1,
-                                                     "%s: %s", current_pduname, name);
+                                                     "%s: (%s)%s", current_pduname, tname, name);
                    else {
                            ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
                                                      def? (int) (offset - boffset + len) :  -1,
-                                                     "%s: %s ~", current_pduname, name);
+                                                     "%s: (%s)%s ~", current_pduname, tname, name);
                            if (props.type_id != -1)
                                proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
                                                      def? (int) (offset - boffset + len) :  -1, TRUE);
@@ -744,7 +890,9 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 #endif /* NEST */
 
            if (!def) len++; /* make sure we get an exception if we run off the end! */
+
            offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
+
            proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
 
            i++; /* one more full message handled */
@@ -785,13 +933,13 @@ dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 }
 
 /* decode an ASN.1 sequence, until we have consumed the specified length */
-guint
+static guint
 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
 {
   ASN1_SCK asn1;
   guint ret, cls, con, tag, def, len, boffset, soffset, eos;
   guint value;
-  char *clsstr, *constr, *tagstr;
+  const char *clsstr, *constr, *tagstr;
   char tagbuf[BUFLM];
   char lenbuf[BUFLM];
   char nnbuf[BUFLS];
@@ -805,7 +953,8 @@ decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, in
   static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s";      /* bit field */
   static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s";           /* constructed */
   static char matchind[] = " ~"; /* indication of possible match */
-  char *name, *ename, *tname, *oname;
+  const char *name, *ename, *tname;
+  char *oname;
   PDUprops props;
 
   ti = 0;                      /* suppress gcc warning */
@@ -837,14 +986,15 @@ decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, in
          if ((cls == ASN1_UNI) && ( tag < 32 )) {
                  tagstr = asn1_tag[tag];
          } else {
-                 snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
+                 g_snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
                  tagstr = tagbuf;
          }
+
+         len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
+
          if (def) {
-                 snprintf(lenbuf, sizeof(lenbuf), "%d", len);
-                 snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
+                 g_snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
          } else {
-                 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
                  strncpy(nnbuf, "NN-", sizeof(nnbuf));
                                /* make sure we get an exception if we run off the end! */
                  len = tvb_length_remaining(tvb, offset) + 1;
@@ -1554,18 +1704,18 @@ decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, in
 /*  search throug the ASN.1 description for appropriate names                                  */
 /************************************************************************************************/
 
-guint lev_limit = G_MAXINT;;
+guint lev_limit = G_MAXINT;
 
 int icount = 0;                        /* item counter */
 
-guint
+static guint
 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
 {
        ASN1_SCK asn1;
        guint eos, ret, cls, con, tag, def, len, value;
        guchar *octets, *bits, unused;
        subid_t *oid;
-       char *clsstr, *constr, *tagstr;
+       const char *clsstr, *constr, *tagstr;
        char tagbuf[BUFLM];
        char lenbuf[BUFLM];
        GNode *cur_node = 0;
@@ -1577,7 +1727,7 @@ parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
 
        while(offset < eos) {
                if (ptr)        /* build pointer tree to all asn1 enteties */
-                       cur_node = g_node_append_data(ptr, (void *)offset);
+                       cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
 
                asn1_open(&asn1, tvb, offset);
                ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
@@ -1588,14 +1738,14 @@ parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
                if ((cls == ASN1_UNI) && ( tag < 32 )) {
                        tagstr = asn1_tag[tag];
                } else {
-                       snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
+                       g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
                        tagstr = tagbuf;
                }
                if (def) {
-                       snprintf(lenbuf, sizeof(lenbuf), "%d", len);
+                       g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
                } else {
                        strncpy(lenbuf, "indefinite", sizeof(lenbuf));
-                       len = tvb_length_remaining(tvb, offset);;
+                       len = tvb_length_remaining(tvb, offset);
                }
 
                switch(cls) {
@@ -1668,7 +1818,7 @@ parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
 
                case ASN1_CTX:          /* fprintf(stderr, "Context\n"); */
                        tagstr = tagbuf;
-                       snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
+                       g_snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
                        if (def && !con) {
                                /* defined length, not constructed, must be a string.... */
                                asn1_string_value_decode(&asn1, len, &octets); /* read value */
@@ -1692,9 +1842,10 @@ parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
        return offset;
 }
 
-void showGNodes(GNode *p, int n);
+static void showGNodes(GNode *p, int n);
 
-gboolean
+#if 0
+static gboolean
 myLeaf(GNode *node, gpointer data)
 {
        ASN1_SCK asn1;
@@ -1713,11 +1864,11 @@ myLeaf(GNode *node, gpointer data)
        if ((cls == ASN1_UNI) && ( tag < 32 )) {
                tagstr = asn1_tag[tag];
        } else {
-               snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
+               g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
                tagstr = tagbuf;
        }
        if (def) {
-               snprintf(lenbuf, sizeof(lenbuf), "%d", len);
+               g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
        } else {
                strncpy(lenbuf, "indefinite", sizeof(lenbuf));
        }
@@ -1728,8 +1879,8 @@ myLeaf(GNode *node, gpointer data)
        return FALSE;
 }
 
-void
-list_modules()
+static void
+list_modules(void)
 {
        if (asn1_verbose) g_message("build GNode tree:");
        showGNodes(g_node_first_child(asn1_nodes), 0);
@@ -1742,9 +1893,10 @@ list_modules()
        g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
 
 }
+#endif
 
-void
-tt_build_tree()                        /* build a GNode tree with all offset's to ASN.1 entities */
+static void
+tt_build_tree(void)            /* build a GNode tree with all offset's to ASN.1 entities */
 {
        if (asn1_nodes)
                g_node_destroy(asn1_nodes);
@@ -1756,7 +1908,7 @@ tt_build_tree()                   /* build a GNode tree with all offset's to ASN.1 entities */
 
 /*****************************************************************************************************/
 
-guint anonCount;  /* for naming anonymous types */
+static guint anonCount;  /* for naming anonymous types */
 
 typedef struct _TBLModule      TBLModule;
 typedef struct _TBLTypeDef     TBLTypeDef;
@@ -1766,7 +1918,6 @@ typedef struct _TBLTypeRef        TBLTypeRef;
 typedef struct _TBLNamedNumber TBLNamedNumber;
 typedef struct _TBLRange       TBLRange;
 
-typedef enum _tbl_t tbl_t;
 enum _tbl_t {
        TBLTYPE_Module,
        TBLTYPE_TypeDef,
@@ -1774,10 +1925,12 @@ enum _tbl_t {
        TBLTYPE_Type,
        TBLTYPE_TypeRef,
        TBLTYPE_NamedNumber,
-       TBLTYPE_Range,
+       TBLTYPE_Range
 };
+typedef enum _tbl_t tbl_t;
 /* text for 'tbl_t' type for debugging */
-char *data_types[] = { "Module",
+static const char *data_types[] = {
+                       "Module",
                        "TypeDef",
                        "Tag",
                        "Type",
@@ -1786,13 +1939,13 @@ char *data_types[] = {  "Module",
                        "Range",
 };
 
-typedef enum _TBLTypeContent_t TBLTypeContent_t;
 enum _TBLTypeContent_t {
        TBLTYPETYPE_None,
        TBLTYPETYPE_Primitive,
        TBLTYPETYPE_Elements,
-       TBLTYPETYPE_TypeRef,
+       TBLTYPETYPE_TypeRef
 };
+typedef enum _TBLTypeContent_t TBLTypeContent_t;
 
 struct _TBLNamedNumber {
        tbl_t   type;
@@ -1853,7 +2006,7 @@ struct _TT {
 
 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
 
-guint
+static guint
 get_asn1_int(guint want_tag, guint offset)
 {
        ASN1_SCK asn1;
@@ -1881,7 +2034,7 @@ get_asn1_int(guint want_tag, guint offset)
        return 0;
 }
 
-subid_t *                      /* with prepended length ..... */
+static subid_t *                       /* with prepended length ..... */
 get_asn1_oid(guint want_tag, guint offset)
 {
        ASN1_SCK asn1;
@@ -1900,7 +2053,7 @@ get_asn1_oid(guint want_tag, guint offset)
                                asn1_oid_value_decode(&asn1, len, &oid, &con);
                                oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
                                memmove(&oid[1], oid, con*sizeof(guint));
-                               oid[0] = con;;
+                               oid[0] = con;
                                return oid;
                        } else
                                ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
@@ -1912,7 +2065,7 @@ get_asn1_oid(guint want_tag, guint offset)
        return 0;
 }
 
-guchar *                       /* 0 terminated string */
+static guchar *                        /* 0 terminated string */
 get_asn1_string(guint want_tag, guint offset)
 {
        ASN1_SCK asn1;
@@ -1942,7 +2095,7 @@ get_asn1_string(guint want_tag, guint offset)
        return 0;
 }
 
-guint
+static guint
 get_asn1_uint(guint offset)
 {
        ASN1_SCK asn1;
@@ -1961,7 +2114,7 @@ get_asn1_uint(guint offset)
        return value;
 }
 
-gboolean
+static gboolean
 check_tag(guint want_tag, guint offset)
 {
        ASN1_SCK asn1;
@@ -1980,7 +2133,8 @@ check_tag(guint want_tag, guint offset)
        return FALSE;
 }
 
-gboolean
+#if 0
+static gboolean
 constructed(guint offset)
 {
        ASN1_SCK asn1;
@@ -2001,8 +2155,9 @@ constructed(guint offset)
 
        return FALSE;
 }
+#endif
 
-void
+static void
 define_constraint(GNode *p, GNode *q)
 {
        TBLRange *range = g_malloc(sizeof(TBLRange));
@@ -2014,14 +2169,14 @@ define_constraint(GNode *p, GNode *q)
 
        p = g_node_first_child(p);
        
-       range->from = get_asn1_int(0, (guint)p->data);
+       range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
 
-       range->to = get_asn1_int(1, (guint)p->data);
+       range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
 
 }
 
-void
+static void
 define_namednumber(GNode *p, GNode *q)
 {
        TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
@@ -2033,13 +2188,13 @@ define_namednumber(GNode *p, GNode *q)
        
        p = g_node_first_child(p);
        
-       num->name = get_asn1_string(0, (guint)p->data);
+       num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
 
-       num->value = get_asn1_int(1, (guint)p->data);
+       num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
 }
 
-void
+static void
 define_typeref(GNode *p, GNode *q)
 {
        TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
@@ -2051,13 +2206,13 @@ define_typeref(GNode *p, GNode *q)
 
        p = g_node_first_child(p);
 
-       ref->typeDefId = get_asn1_uint((guint)p->data);
+       ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
 
-       ref->implicit = get_asn1_int(ASN1_BOL, (guint)p->data);
+       ref->implicit = get_asn1_int(ASN1_BOL, GPOINTER_TO_UINT(p->data));
 }
 
-void
+static void
 define_tag(GNode *p, GNode *q)
 {
        TBLTag *type = g_malloc(sizeof(TBLTag));
@@ -2069,14 +2224,14 @@ define_tag(GNode *p, GNode *q)
 
        p = g_node_first_child(p);
        
-       type->tclass = get_asn1_int(ASN1_ENUM, (guint)p->data);
+       type->tclass = get_asn1_int(ASN1_ENUM, GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
 
-       type->code = get_asn1_int(ASN1_INT, (guint)p->data);
+       type->code = get_asn1_int(ASN1_INT, GPOINTER_TO_UINT(p->data));
        
 }
 
-void
+static void
 define_type(GNode *p, GNode *q)
 {
        GNode *r;
@@ -2088,13 +2243,13 @@ define_type(GNode *p, GNode *q)
 
        /* g_message("define_type %p, %p", p, q); */
 
-       type->typeId = get_asn1_int(0, (guint)p->data);
+       type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
 
-       type->optional = get_asn1_int(1, (guint)p->data);
+       type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
 
-       if (check_tag(2, (guint)p->data)) { /* optional, need empty node if not there ?*/
+       if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
                r = g_node_first_child(p);
                while (r) {
                        define_tag(r, t);
@@ -2103,15 +2258,15 @@ define_type(GNode *p, GNode *q)
                p = g_node_next_sibling(p);
        }
 
-       if (!check_tag(3, (guint)p->data)) {
+       if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
                g_warning("expect tag 3, ERROR");
        }
        r = g_node_first_child(p);
                /* a choice ... */
        type->content = TBLTYPETYPE_None;
-       if (check_tag(0, (guint)r->data)) type->content = TBLTYPETYPE_Primitive;
-       if (check_tag(1, (guint)r->data)) type->content = TBLTYPETYPE_Elements;
-       if (check_tag(2, (guint)r->data)) type->content = TBLTYPETYPE_TypeRef;
+       if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
+       if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
+       if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
        switch(type->content) {
                case TBLTYPETYPE_Primitive:
                        break;
@@ -2133,21 +2288,21 @@ define_type(GNode *p, GNode *q)
 
        type->fieldName = 0;
        type->anonymous = FALSE;
-       if (p && check_tag(4, (guint)p->data)) {
-               type->fieldName = get_asn1_string(4, (guint)p->data);
+       if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
+               type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
                p = g_node_next_sibling(p);
        } else {
                type->anonymous = TRUE;
        }
 
        type->constraint = FALSE;
-       if (p && check_tag(5, (guint)p->data)) {
+       if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
                type->constraint = TRUE;
                define_constraint(p, t);
                p = g_node_next_sibling(p);
        }
        
-       if (p && check_tag(6, (guint)p->data)) {
+       if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
                r =  g_node_first_child(p);
                while(r) {
                        define_namednumber(r, t);
@@ -2156,7 +2311,7 @@ define_type(GNode *p, GNode *q)
        }
 }
 
-void
+static void
 define_typedef(GNode *p, GNode *q)
 {
        TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
@@ -2169,10 +2324,10 @@ define_typedef(GNode *p, GNode *q)
 
        p = g_node_first_child(p);
        
-       type_def->typeDefId = get_asn1_uint((guint)p->data);
+       type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
        
-       type_def->typeName = get_asn1_string(ASN1_PRNSTR, (guint)p->data);
+       type_def->typeName = get_asn1_string(ASN1_PRNSTR, GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
        
        define_type(g_node_first_child(p), t);
@@ -2181,7 +2336,7 @@ define_typedef(GNode *p, GNode *q)
        type_def->isPdu = (p != 0);  /* true if it exists, value ignored */
 }
 
-void
+static void
 define_module(GNode *p, GNode *q)
 {
        TBLModule *module = g_malloc(sizeof(TBLModule));
@@ -2194,16 +2349,16 @@ define_module(GNode *p, GNode *q)
        
        p = g_node_first_child(p);
        
-       module->name = get_asn1_string(0, (guint)p->data);
+       module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
        
        module->id = 0;
-       if (check_tag(1, (guint)p->data)) { /* optional */ 
-               module->id = get_asn1_oid(1, (guint)p->data);
+       if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */ 
+               module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
                p = g_node_next_sibling(p);
        }
        
-       module->isUseful = get_asn1_int(2, (guint)p->data);
+       module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
 
        p = g_node_first_child(p);
@@ -2215,11 +2370,11 @@ define_module(GNode *p, GNode *q)
 
 typedef struct _SearchDef SearchDef;
 struct _SearchDef {
-       char *key;
+       const char *key;
        GNode *here;
 };
 
-gboolean
+static gboolean
 is_typedef(GNode *node, gpointer data)
 {
        TBLTypeDef *d = (TBLTypeDef *)node->data;
@@ -2255,7 +2410,7 @@ struct _NameDefs {
 #define ALLOC_INCR 4
 #define CLASSREF (ASN1_PRV+1)
 
-gboolean
+static gboolean
 is_named(GNode *node, gpointer data)
 {
        TBLNamedNumber *num = (TBLNamedNumber *)node->data;
@@ -2279,7 +2434,7 @@ is_named(GNode *node, gpointer data)
        return FALSE;
 }
 
-gboolean
+static gboolean
 index_typedef(GNode *node, gpointer data)
 {
        TBLTypeDef *d = (TBLTypeDef *)node->data;
@@ -2334,11 +2489,18 @@ index_typedef(GNode *node, gpointer data)
        return FALSE;
 }
 
-TypeRef *typeDef_names = 0;
-guint numTypedefs = 0;
+static TypeRef *typeDef_names = 0;
+static guint numTypedefs = 0;
 
-void
-get_values()                   /* collect values from ASN.1 tree */
+static gboolean
+free_node_data(GNode *node, gpointer data _U_)
+{
+       g_free(node->data);
+       return FALSE;
+}
+
+static void
+get_values(void)               /* collect values from ASN.1 tree */
                                /* coded according to the tbl.asn1 description of snacc output */ 
 {                              /* This routine does not leave references to the tvbuff or */
                                /* to the asn1_nodes, both can be freed by the caller of this.*/
@@ -2346,31 +2508,35 @@ get_values()                    /* collect values from ASN.1 tree */
        SearchDef sd;
        NameDefs nd;
        guint i;
-       char X, *t, *s, *E;
+       char X;
+       const char *t, *s, *E;
        static char missing[] = "  **missing**  ";
 
        if (asn1_verbose) g_message("interpreting tree");
        typeDef_names = 0;  /* just forget allocated any data .... */
        
-       if (data_nodes)
+       if (data_nodes) {
+               g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+                   free_node_data, NULL);
                g_node_destroy(data_nodes);
+       }
                        
        data_nodes = g_node_new(0);
 
        p = g_node_first_child(asn1_nodes); /* top of the data tree */
        
        p = g_node_first_child(p);
-       TT.totalNumModules = get_asn1_uint((guint)p->data);
+       TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
-       TT.totalNumTypeDefs = get_asn1_uint((guint)p->data);
+       TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
-       TT.totalNumTypes = get_asn1_uint((guint)p->data);
+       TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
-       TT.totalNumTags = get_asn1_uint((guint)p->data);
+       TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
-       TT.totalNumStrings = get_asn1_uint((guint)p->data);
+       TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
-       TT.totalLenStrings = get_asn1_uint((guint)p->data);
+       TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
        p = g_node_next_sibling(p);
 
        p = g_node_first_child(p);
@@ -2438,7 +2604,7 @@ get_values()                      /* collect values from ASN.1 tree */
 
 }
 
-void
+static void
 showGNode(GNode *p, int n)
 {
        if (p == 0) return;
@@ -2462,7 +2628,7 @@ showGNode(GNode *p, int n)
                        break;
                case TBLTYPE_Type: {
                        TBLType *t = (TBLType *)p->data;
-                       char *fn, *s = empty;
+                       const char *fn, *s = empty;
                        if (t->fieldName)
                                s = t->fieldName;
                        /* typeId is a value from enum TBLTypeId */
@@ -2473,7 +2639,7 @@ showGNode(GNode *p, int n)
                        break;
                case TBLTYPE_Tag: {
                        TBLTag *t = (TBLTag *)p->data;
-                       char *s = empty;
+                       const char *s = empty;
                        if ((t->tclass == ASN1_UNI) && (t->code < 32))
                                s = asn1_tag[t->code];
                        if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
@@ -2494,7 +2660,7 @@ showGNode(GNode *p, int n)
                        break;
                case TBLTYPE_TypeRef: {
                        TBLTypeRef *r = (TBLTypeRef *)p->data;
-                       char *s = empty;
+                       const char *s = empty;
                        if (typeDef_names)
                                s = typeDef_names[r->typeDefId].name;
                        if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
@@ -2514,7 +2680,7 @@ showGNode(GNode *p, int n)
        }
 }
 
-void
+static void
 showGNodes(GNode *p, int n)
 {
        if (p == 0) return;
@@ -2523,7 +2689,7 @@ showGNodes(GNode *p, int n)
        showGNodes(p->next, n);
 }
 
-void showGenv(GNode *p, int n, int m)
+static void showGenv(GNode *p, int n, int m)
 {
        int i;
 
@@ -2541,8 +2707,8 @@ void showGenv(GNode *p, int n, int m)
 
 }
 
-void
-debug_dump_TT()                        /* dump contents of TT struct, for debugging */
+static void
+debug_dump_TT(void)            /* dump contents of TT struct, for debugging */
 {
        if (asn1_verbose)
                g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
@@ -2554,7 +2720,7 @@ debug_dump_TT()                   /* dump contents of TT struct, for debugging */
                        TT.totalLenStrings);
 }
 
-void
+static void
 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
                const gchar *message, gpointer user_data)
 {
@@ -2563,26 +2729,42 @@ static char eol[] = "\r\n";
 
        (void) log_domain; (void) log_level; (void) user_data; /* make references */
 
-       if (logf == 0) {
-               logf = fopen(asn1_logfile, "w");
+       if (logf == NULL && asn1_logfile) {
+               logf = eth_fopen(asn1_logfile, "w");
        }
+       if (logf) {
        fputs(message, logf);
        fputs(eol, logf);
+        fflush(logf);   /* debugging ... */
+        }
 }
 
-void
-read_asn1_type_table(char *filename)
+static void
+read_asn1_type_table(const char *filename)
 {
        FILE *f;
        guint size;
        guchar *data;
        struct stat stat;
 
-       f = fopen(filename, "rb");
+       if ((filename == 0) || (strlen(filename) == 0))
+               return;         /* no filename provided */
+
+       f = eth_fopen(filename, "rb");
        if (f == 0) {
-               if (strcmp(filename, default_asn1_filename) != NULL ||
-                   errno != ENOENT)
-                       g_warning("error opening %s, %s", filename, strerror(errno));
+               /*
+                * Ignore "file not found" errors if it's the old default
+                * ASN.1 file name, as we never shipped such a file.
+                * Also, on Win32, ignore the earlier default, which
+                * had a "/" rather than a "\" as the last pathname
+                * separator.
+                */
+               if ((strcmp(filename, old_default_asn1_filename) != 0
+#ifdef _WIN32
+                   && strcmp(filename, bad_separator_old_default_asn1_filename) != 0
+#endif
+                   ) || errno != ENOENT)
+                       report_open_failure(filename, errno, FALSE);
                return;
        }
        fstat(fileno(f), &stat);
@@ -2622,12 +2804,14 @@ read_asn1_type_table(char *filename)
        tt_build_tree();
        if (asn1_verbose) g_message("read %d items from %s", icount, filename); 
 
-       /* list_modules(); */
+#if 0
+       list_modules();
+#endif
 
        get_values();
 
        g_node_destroy(asn1_nodes);     asn1_nodes = 0;
-#ifndef WIN32          /* tvb_free not yet exported to plugins... */
+#ifndef _WIN32         /* tvb_free not yet exported to plugins... */
        tvb_free(asn1_desc);
 #endif
                                        asn1_desc = 0;
@@ -2638,44 +2822,13 @@ read_asn1_type_table(char *filename)
        debug_dump_TT();  
 }
 
-typedef struct _PDUinfo PDUinfo;
-struct _PDUinfo {
-       guint type;
-       char *name;
-       char *typename;
-       char *fullname;
-       guchar tclass;
-       guint tag;
-       guint flags;
-       GNode *reference;
-       gint typenum;
-       gint basetype;          /* parent type */
-       gint mytype;            /* original type number, typenum may have gone through a reference */
-       gint value_id;          /* ethereal field id for the value in this PDU */
-       gint type_id;           /* ethereal field id for the type of this PDU */
-       hf_register_info value_hf; /* ethereal field info for this value */
-};
-
-
-/* bits in the flags collection */
-#define PDU_OPTIONAL    1
-#define PDU_IMPLICIT    2
-#define PDU_NAMEDNUM    4
-#define PDU_REFERENCE    8
-#define PDU_TYPEDEF   0x10
-#define PDU_ANONYMOUS 0x20
-#define PDU_TYPETREE  0x40
-
-#define PDU_CHOICE    0x08000000   /* manipulated by the PDUname routine */
-
-guint PDUinfo_initflags = 0;   /* default flags for newly allocated PDUinfo structs */
 
 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
         g_warning("**** unexpected type %s, want %s, at line %d", \
                        data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
 
 
-void
+static void
 save_reference(PDUinfo *p)
 {
        gint i = p->mytype;
@@ -2686,19 +2839,24 @@ save_reference(PDUinfo *p)
        g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
 }
 
-void
+static void
 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex);
 
 
 
        /* evaluate typeref, pointer to current pdu node and typedef */
-void
+static void
 tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
 {
        GNode *q;
        PDUinfo *p = (PDUinfo *)pdu->data, *p1;
        guint nvals;
        value_string *v;
+
+       if (n > 40) {  /* don't believe this....! ...... stop recursion ...... */
+               g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
+               return;
+       }
        
        CHECKTYPE(tree, TBLTYPE_TypeDef);
 
@@ -2750,14 +2908,18 @@ tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
 
                ss[0] = 0;
                if (p->tclass==CLASSREF)
-                       snprintf(ss, 128, ", CLASSREF %d", p->tag);
+                       g_snprintf(ss, 128, ", CLASSREF %d", p->tag);
                if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
                
                if (p->tclass==CLASSREF) {
                        TypeRef *tr;
+                       int i = p->basetype;
                        /* CLASSREF....., get it defined using type of the reference */
 
-                       tr = &typeDef_names[p->tag];
+                       /* p->basetype may be -1 .... ? XXX */
+                       if (i == -1)
+                               i = p->tag;
+                       tr = &typeDef_names[i];
                        if (asn1_verbose)
                                g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
                                          p->tag, tr->name, tr->pdu);
@@ -2852,7 +3014,7 @@ tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
        }
 }
 
-void
+static void
 tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
 {
        GNode *q, *pdu1;
@@ -2862,7 +3024,7 @@ tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, sour
        value_string *v;
 
        if (n > 40) {  /* don't believe this....! ...... stop recursion ...... */
-               g_warning("**** n>40, return [recursion too deep] ****************");
+               g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
                return;
        }
 
@@ -2872,8 +3034,8 @@ tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, sour
        pdu1 = pdu;             /* save start location for append */
        while (list) {          /* handle all entries */
                if (asn1_verbose)
-                       g_message("%*s+handle a %s", n*2, empty,
-                                 data_types[((TBLTag *)list->data)->type]);
+                       g_message("%*s+handle a %s, list=%p", n*2, empty,
+                                 data_types[((TBLTag *)list->data)->type], list);
 
                if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
                        list = g_node_next_sibling(list);
@@ -2882,7 +3044,12 @@ tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, sour
                                break;
                }
 
-               if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) { 
+               /******* change to positive comparation, but leave comment for reference
+                * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) { 
+                *      CHECKTYPE(list, TBLTYPE_Type);
+                */
+
+                if (((TBLTag *)list->data)->type == TBLTYPE_Type) { 
                        CHECKTYPE(list, TBLTYPE_Type);
 
                        p = g_malloc0(sizeof(PDUinfo));
@@ -2905,7 +3072,7 @@ tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, sour
                        p->name = ((TBLType *)list->data)->fieldName;
                        
                        ni = fullindex;
-                       ni += sprintf(&fieldname[ni], ".%s", p->name);
+                       ni += snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
                        p->fullname = g_strdup(fieldname);
                        
                        /* initialize field info */
@@ -2996,6 +3163,7 @@ tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, sour
                case TBL_SETOF:
                case TBL_CHOICE:
                        CHECKTYPE(q, TBLTYPE_Tag);
+                       q = g_node_first_child(list);
                        tbl_type(n+1, pdu, q, ni);
                        break;
                        
@@ -3088,11 +3256,11 @@ tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, sour
        }
 }
 
-void
+static void
 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
 {
        PDUinfo *rinfo;
-       char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
+       const char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
 
        if (info) {
                tt = TBLTYPE(info->type);
@@ -3143,7 +3311,7 @@ PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
 }
 
 
-void
+static void
 showPDUtree(GNode *p, int n)
 {
        PDUinfo *info;
@@ -3164,8 +3332,8 @@ showPDUtree(GNode *p, int n)
        return;
 }
 
-gboolean
-build_pdu_tree(char *pduname)
+static gboolean
+build_pdu_tree(const char *pduname)
 {
        SearchDef sd;
        guint pdudef, i, tcount;
@@ -3174,6 +3342,10 @@ build_pdu_tree(char *pduname)
 
        if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
 
+       if (!data_nodes) {
+               if (asn1_verbose) g_message("no data nodes");
+               return FALSE;
+       }
        sd.key = pduname;
        sd.here = 0;
        g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
@@ -3185,6 +3357,13 @@ build_pdu_tree(char *pduname)
                return FALSE;
        }
 
+       /* If there's an existing PDU tree, free it */
+       if (PDUtree) {
+               g_node_traverse(PDUtree, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+                   free_node_data, NULL);
+               g_node_destroy(PDUtree);
+       }
+
        /* initialize the PDU tree, hand craft the root entry */
 
        info = g_malloc0(sizeof(PDUinfo));
@@ -3332,7 +3511,7 @@ build_pdu_tree(char *pduname)
 #ifdef DISSECTOR_WITH_GUI
 /* This cannot work in tethereal.... don't include for now */
 #if GTK_MAJOR_VERSION >= 2
-#define SHOWPDU        /* this needs GTK2, which is not yet on Win32 .............. */
+#define SHOWPDU        /* this needs GTK2 */
 #endif
 #endif /* DISSECTOR_WITH_GUI */
 #ifdef SHOWPDU
@@ -3350,9 +3529,9 @@ enum
    N_COLUMNS
 };
 
-FILE *namelist = 0;
+static FILE *namelist = 0;
 
-void
+static void
 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
 {
        GtkTreeIter iter2;
@@ -3424,10 +3603,10 @@ struct DefFind {
 };
 
 #define PATHSTACKMAX 10
-GtkTreePath *pathstack[PATHSTACKMAX];
-gint pathstackp = 0;
+static GtkTreePath *pathstack[PATHSTACKMAX];
+static gint pathstackp = 0;
 
-void add_path(GtkTreePath *p)
+static void add_path(GtkTreePath *p)
 {
        if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
                gtk_tree_path_free(pathstack[0]); /* we forget about this one */
@@ -3437,13 +3616,15 @@ void add_path(GtkTreePath *p)
        pathstack[pathstackp++] = p;
 }
 
-GtkTreePath *pop_path() {
+static GtkTreePath *pop_path(void)
+{
        if (pathstackp > 0)
                return pathstack[--pathstackp];
        return 0;
 }
 
-gboolean find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+static gboolean
+find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
 {
        gint def;
 
@@ -3459,7 +3640,7 @@ gboolean find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *it
 
 }
 
-void
+static void
 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
 {
        GtkTreeIter iter;
@@ -3635,8 +3816,8 @@ static gint button_press_callback( GtkWidget      *widget,
 }
 
 
-void
-create_message_window()
+static void
+create_message_window(void)
 {
        GtkCellRenderer *renderer;
        GtkTreeStore *model;
@@ -3678,7 +3859,7 @@ create_message_window()
        model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
                                   G_TYPE_STRING, G_TYPE_STRING);
 
-       namelist = fopen("namelist.txt", "w");
+       namelist = eth_fopen("namelist.txt", "w");
        build_tree_view(model, PDUtree, NULL);
        fclose(namelist);
        namelist = 0;
@@ -3788,13 +3969,13 @@ create_message_window()
  *    routines to find names to go with the decoded data stream                                        *
  ************************************************************************************************/
 typedef struct _statestack statestack;
-struct _statestack {
+static struct _statestack {
        GNode *node;
        guint type;
        guint offset;
-       char *name;
+       const char *name;
 } PDUstate[1024];
-gint PDUstatec = 0;
+static gint PDUstatec = 0;
 
 #define PUSHNODE(x)   { PDUstate[PDUstatec++] = (x); }
 #define STORENODE(x)  { PDUstate[PDUstatec-1] = (x); }
@@ -3819,11 +4000,12 @@ gint PDUstatec = 0;
                                pos.node=0;PUSHNODE(pos);return ret;}}
 
 
-void
+static void
 showstack(statestack *pos, char *txt, int n)
 {
-       char buf[1024], *name, *type, *stype;
-       char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
+       char buf[1024];
+       const char *name, *type, *stype;
+       const char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
        int i, j;
        GNode *g;
        statestack *p;
@@ -3885,10 +4067,10 @@ showstack(statestack *pos, char *txt, int n)
        g_message(buf);
 }
 
-void
+static void
 showrefNode(GNode *node, int n)
 {
-       char *name = empty, *type = empty, *tname = empty;
+       const char *name = empty, *type = empty, *tname = empty;
        int cls = 0, tag = 0;
        PDUinfo *info;
        GNode *ref = 0;
@@ -3914,10 +4096,10 @@ showrefNode(GNode *node, int n)
                showrefNode(ref, n+1);
 }
 
-void
+static void
 showNode(GNode *node, int n, int m)
 {
-       char *name = empty, *type = empty;
+       const char *name = empty, *type = empty;
        GNode *ref = 0;
 
        if (n > m)
@@ -3943,7 +4125,7 @@ showNode(GNode *node, int n, int m)
        if (node->next) showNode(node->next, n, m);
 }
 
-void
+static void
 PDUreset(int count, int count2)
 {
        statestack pos;
@@ -3961,14 +4143,14 @@ PDUreset(int count, int count2)
 
        if (PDUtree) {
                pos.node = PDUtree; /* root of the tree */
-               pos.name = GETNAME;;
+               pos.name = GETNAME;
                pos.type = GETTYPE | TBL_REPEAT;
                pos.offset = 0;
                PUSHNODE(pos);
        }
 }
 
-GNode *                                /* find GNode for a choice element, 0 if none */
+static GNode *                 /* find GNode for a choice element, 0 if none */
 makechoice(GNode *p, guint class, guint tag)
 {
        GNode *q;
@@ -4011,12 +4193,12 @@ makechoice(GNode *p, guint class, guint tag)
 }
 
                /* offset is for debugging only, a reference to output on screen */
-PDUprops *
+static PDUprops *
 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
 {
        statestack pos, pos2, save_pos;
        PDUinfo *info;
-       char *ret, *tmp;
+       const char *ret, *tmp;
        int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
        static char namestr[64]; /* enough ? */
        static char posstr[40];
@@ -4572,12 +4754,12 @@ getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
        return out;
 }
 
-char *
+static const char *
 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
 {
        GNode *list;
        PDUinfo *info;
-       char *ret, *name;
+       const char *ret, *name;
        static char unnamed[] = "*unnamed*";
        
        (void) cls; (void) tag;         /* make a reference */
@@ -4620,26 +4802,30 @@ void
 proto_register_asn1(void) {
 
   static const enum_val_t type_recursion_opts[] = {
-         { "0", 0 },
-         { "1", 1 },
-         { "2", 2 },
-         { "3", 3 },
-         { "4", 4 },
-         { "5", 5 },
-         { "6", 6 },
-         { "7", 7 },
-         { "8", 8 },
-         { "9", 9 },
-         { NULL, -1},
+         { "0", "0", 0 },
+         { "1", "1", 1 },
+         { "2", "2", 2 },
+         { "3", "3", 3 },
+         { "4", "4", 4 },
+         { "4", "5", 5 },
+         { "6", "6", 6 },
+         { "7", "7", 7 },
+         { "8", "8", 8 },
+         { "9", "9", 9 },
+         { NULL, NULL, -1},
   };
 
   static gint *ett[1+MAX_NEST+MAXPDU];
 
+  char tmpstr[64];
+
   module_t *asn1_module;
   int i, j;
 
+  asn1_logfile = get_tempfile_path(ASN1LOGFILE);
 
-  asn1_logfile = g_strdup(ASN1LOGFILE);
+  current_asn1 = g_strdup("");
+  asn1_filename = g_strdup(current_asn1);
 
   current_pduname = g_strdup("ASN1");
   asn1_pduname = g_strdup(current_pduname);
@@ -4661,23 +4847,58 @@ proto_register_asn1(void) {
 
   asn1_module = prefs_register_protocol(proto_asn1,
                                        proto_reg_handoff_asn1);
+#ifdef JUST_ONE_PORT
   prefs_register_uint_preference(asn1_module, "tcp_port",
                                 "ASN.1 TCP Port",
                                 "The TCP port on which "
-                                "ASN.1 packets will be read",
+                                "ASN.1 messages will be read",
                                 10, &global_tcp_port_asn1);
   prefs_register_uint_preference(asn1_module, "udp_port",
                                 "ASN.1 UDP Port",
                                 "The UDP port on which "
-                                "ASN.1 packets will be read",
+                                "ASN.1 messages will be read",
                                 10, &global_udp_port_asn1);
+  prefs_register_uint_preference(asn1_module, "sctp_port",
+                                "ASN.1 SCTP Port",
+                                "The SCTP port on which "
+                                "ASN.1 messages will be read",
+                                10, &global_sctp_port_asn1);
+#else
+  g_snprintf(tmpstr, sizeof(tmpstr), "%u", TCP_PORT_ASN1);
+  range_convert_str(&global_tcp_ports_asn1, tmpstr, 65535);
+  
+  g_snprintf(tmpstr, sizeof(tmpstr), "%u", UDP_PORT_ASN1);
+  range_convert_str(&global_udp_ports_asn1, tmpstr, 65535);
+  
+  g_snprintf(tmpstr, sizeof(tmpstr), "%u", SCTP_PORT_ASN1);
+  range_convert_str(&global_sctp_ports_asn1, tmpstr, 65535);
+  
+  prefs_register_range_preference(asn1_module, "tcp_ports",
+                                "ASN.1 TCP Ports",
+                                "The TCP ports on which "
+                                "ASN.1 messages will be read",
+                                &global_tcp_ports_asn1, 65535);
+  prefs_register_range_preference(asn1_module, "udp_ports",
+                                "ASN.1 UDP Ports",
+                                "The UDP ports on which "
+                                "ASN.1 messages will be read",
+                                &global_udp_ports_asn1, 65535);
+  prefs_register_range_preference(asn1_module, "sctp_ports",
+                                "ASN.1 SCTP Ports",
+                                "The SCTP ports on which "
+                                "ASN.1 messages will be read",
+                                &global_sctp_ports_asn1, 65535);
+#endif /* JUST_ONE_PORT */
+
   prefs_register_bool_preference(asn1_module, "desegment_messages",
                                 "Desegment TCP",
                                 "Desegment ASN.1 messages that span TCP segments",
                                 &asn1_desegment);
 
-  default_asn1_filename = get_datafile_path(ASN1FILE);
-  asn1_filename = default_asn1_filename;
+  old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
+#ifdef _WIN32
+  bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
+#endif
 
   prefs_register_string_preference(asn1_module, "file",
                                   "ASN.1 type table file",
@@ -4705,46 +4926,114 @@ proto_register_asn1(void) {
                                 "ASN.1 debug mode",
                                 "Extra output useful for debuging",
                                 &asn1_debug);
-
+#if 0
   prefs_register_bool_preference(asn1_module, "message_win",
                                 "Show ASN.1 tree",
                                 "show full message description",
                                 &asn1_message_win);
+#else
+  prefs_register_obsolete_preference(asn1_module, "message_win");
+#endif
   prefs_register_bool_preference(asn1_module, "verbose_log",
                                 "Write very verbose log",
-                                "log to file " ASN1LOGFILE,
+                                "log to file $TMP/" ASN1LOGFILE,
                                 &asn1_verbose);
 }
 
 /* The registration hand-off routing */
 
+static dissector_handle_t asn1_handle;
+
+static void
+register_tcp_port(guint32 port)
+{
+  dissector_add("tcp.port", port, asn1_handle);
+}
+
+static void
+unregister_tcp_port(guint32 port)
+{
+  dissector_delete("tcp.port", port, asn1_handle);
+}
+
+static void
+register_udp_port(guint32 port)
+{
+  dissector_add("udp.port", port, asn1_handle);
+}
+
+static void
+unregister_udp_port(guint32 port)
+{
+  dissector_delete("udp.port", port, asn1_handle);
+}
+
+static void
+register_sctp_port(guint32 port)
+{
+  dissector_add("sctp.port", port, asn1_handle);
+}
+
+static void
+unregister_sctp_port(guint32 port)
+{
+  dissector_delete("sctp.port", port, asn1_handle);
+}
+
 void
 proto_reg_handoff_asn1(void) {
   static int asn1_initialized = FALSE;
-  static dissector_handle_t asn1_handle;
+#ifndef JUST_ONE_PORT
+  char *tcp_ports_asn1_string, *udp_ports_asn1_string, *sctp_ports_asn1_string;
+#endif
 
   pcount = 0;
 
-  if (asn1_verbose) g_message("prefs change: tcpport=%d, udpport=%d, desegnment=%d, asn1file=%s, "
-                 "pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
-         global_tcp_port_asn1, global_udp_port_asn1, asn1_desegment, asn1_filename,
-         asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
+#ifdef JUST_ONE_PORT
+  if (asn1_verbose) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegnment=%d, "
+               "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
+         global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
+         asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
+#else
+  if (asn1_verbose) {
+    tcp_ports_asn1_string = range_convert_range(global_tcp_ports_asn1);
+    udp_ports_asn1_string = range_convert_range(global_udp_ports_asn1);
+    sctp_ports_asn1_string = range_convert_range(global_sctp_ports_asn1);
+    g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegnment=%d, "
+               "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
+         tcp_ports_asn1_string, udp_ports_asn1_string, sctp_ports_asn1_string, asn1_desegment,
+         asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
+  }
+#endif /* JUST_ONE_PORT */
 
   if(!asn1_initialized) {
     asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
     asn1_initialized = TRUE;
-  } else {
-    dissector_delete("tcp.port", tcp_port_asn1, asn1_handle);
-    dissector_delete("udp.port", udp_port_asn1, asn1_handle);
-  }
+  } else {     /* clean up ports and their lists */
+#ifdef JUST_ONE_PORT
+    unregister_tcp_port(tcp_port_asn1);
+    unregister_udp_port(udp_port_asn1);
+    unregister_sctp_port(sctp_port_asn1);
+#else
+    if (tcp_ports_asn1 != NULL) {
+      range_foreach(tcp_ports_asn1, unregister_tcp_port);
+      g_free(tcp_ports_asn1);
+    }
 
-  tcp_port_asn1 = global_tcp_port_asn1;
-  udp_port_asn1 = global_udp_port_asn1;
-  
-  dissector_add("tcp.port", global_tcp_port_asn1, asn1_handle);
-  dissector_add("udp.port", global_udp_port_asn1, asn1_handle);
+    if (udp_ports_asn1 != NULL) {
+      range_foreach(udp_ports_asn1, unregister_udp_port);
+      g_free(udp_ports_asn1);
+    }
+    
+    if (sctp_ports_asn1 != NULL) {
+      range_foreach(sctp_ports_asn1, unregister_sctp_port);
+      g_free(sctp_ports_asn1);
+    }
+#endif /* JUST_ONE_PORT */
+  }
 
-  if ( g_strcmp(asn1_filename, current_asn1) != 0) { /* new defintions, parse it */
+  if (strcmp(asn1_filename, current_asn1) != 0) {
+         /* new definitions, parse the file if we have one */
          /* !!! should be postponed until we really need it !!! */
 #ifdef READSYNTAX
          read_asn1_type_table(asn1_filename);
@@ -4752,7 +5041,8 @@ proto_reg_handoff_asn1(void) {
          g_free(current_asn1);
          current_asn1 = g_strdup(asn1_filename);
   }
-  if (g_strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
+  if (!PDUtree ||      /* no tree built yet for PDU type */
+      strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
          if (build_pdu_tree(asn1_pduname)) {
                  g_free(current_pduname);
                  current_pduname = g_strdup(asn1_pduname);
@@ -4767,32 +5057,47 @@ proto_reg_handoff_asn1(void) {
          create_message_window();
   }
 #endif /* SHOWPDU */
-}
 
-/* Start the functions we need for the plugin stuff */
+  /* If we now have a PDU tree, register for the port or ports we have */
+  if (PDUtree) {
+#ifdef JUST_ONE_PORT
+    tcp_port_asn1 = global_tcp_port_asn1;
+    udp_port_asn1 = global_udp_port_asn1;
+    sctp_port_asn1 = global_sctp_port_asn1;
 
-#ifndef __ETHEREAL_STATIC__
+    register_tcp_port(tcp_port_asn1);
+    register_udp_port(udp_port_asn1);
+    register_sctp_port(sctp_port_asn1);
+#else
+    tcp_ports_asn1 = range_copy(global_tcp_ports_asn1);
+    udp_ports_asn1 = range_copy(global_udp_ports_asn1);
+    sctp_ports_asn1 = range_copy(global_sctp_ports_asn1);
 
-G_MODULE_EXPORT void
-plugin_reg_handoff(void){
-  proto_reg_handoff_asn1();
+    range_foreach(tcp_ports_asn1, register_tcp_port);
+    range_foreach(udp_ports_asn1, register_udp_port);
+    range_foreach(sctp_ports_asn1, register_sctp_port);
+  }
+#endif /* JUST_ONE_PORT */
 }
 
+/* Start the functions we need for the plugin stuff */
+
+#ifndef ENABLE_STATIC
+
 G_MODULE_EXPORT void
-plugin_init(plugin_address_table_t *pat
-#ifndef PLUGINS_NEED_ADDRESS_TABLE
-_U_
-#endif
-)
+plugin_register(void)
 {
-  /* initialise the table of pointers needed in Win32 DLLs */
-  plugin_address_table_init(pat);
   /* register the new protocol, protocol fields, and subtrees */
   if (proto_asn1 == -1) { /* execute protocol initialization only once */
     proto_register_asn1();
   }
 }
 
+G_MODULE_EXPORT void
+plugin_reg_handoff(void){
+  proto_reg_handoff_asn1();
+}
+
 #endif
 
 /* End the functions we need for plugin stuff */