Add in some heuristics to try to detect AIX libpcap format. (This works
[obnox/wireshark/wip.git] / packet-snmp.c
index 9d896a40dbbf9e0e28468bda5e19442ed47e62f2..9528ecc54a8aacf233017a4235a7b9fca43c697a 100644 (file)
@@ -1,12 +1,18 @@
 /* packet-snmp.c
  * Routines for SNMP (simple network management protocol)
- * D.Jorand (c) 1998
+ * Copyright (C) 1998 Didier Jorand
  *
- * $Id: packet-snmp.c,v 1.35 2000/05/30 03:35:54 guy Exp $
+ * See RFC 1157 for SNMPv1.
+ *
+ * See RFCs 1901, 1905, and 1906 for SNMPv2c.
+ *
+ * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u.
+ *
+ * $Id: packet-snmp.c,v 1.71 2001/09/03 10:33:07 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
- * Copyright 1998 Didier Jorand
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
  *
  * Some stuff from:
  * 
 # include <netinet/in.h>
 #endif
 
-#define MAX_STRING_LEN 1024    /* TBC */
+#define MAX_STRING_LEN 2048    /* TBC */
+
+#ifdef linux
+#include <dlfcn.h>
+#endif
 
 #include <glib.h>
 
 #include "packet.h"
+#include "strutil.h"
+#include "conversation.h"
 #include "etypes.h"
 #include "packet-ipx.h"
 
 #  include <ucd-snmp/mib.h>
 
    /*
-    * Sigh.  UCD SNMP 4.1.1 makes "snmp_set_full_objid()" a macro
-    * that calls "ds_set_boolean()" with the first two arguments
-    * being DS_LIBRARY_ID and DS_LIB_PRINT_FULL_OID; this means that,
+    * Sigh.  UCD SNMP 4.1.1 makes "snmp_set_suffix_only()" a macro
+    * that calls "ds_set_int()" with the first two arguments
+    * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that,
     * when building with 4.1.1, we need to arrange that
     * <ucd-snmp/default_store.h> is included, to define those two values
-    * and to declare "ds_set_boolean()".
+    * and to declare "ds_int()".
     *
     * However:
     *
     *     as that includes <ucd-snmp/snmp.h>, and that defines a whole
     *     bunch of values that we also define ourselves.
     *
-    * So we only include it if "snmp_set_full_objid" is defined as
+    * So we only include it if "snmp_set_suffix_only" is defined as
     * a macro.
     */
-#  ifdef snmp_set_full_objid
+#  ifdef snmp_set_suffix_only
 #   include <ucd-snmp/default_store.h>
 #  endif
 
 
 #include "packet-snmp.h"
 
+/* Null string of type "guchar[]". */
+static const guchar nullstring[] = "";
+
+/* Take a pointer that may be null and return a pointer that's not null
+   by turning null pointers into pointers to the above null string. */
+#define        SAFE_STRING(s)  (((s) != NULL) ? (s) : nullstring)
+
 static int proto_snmp = -1;
 static int proto_smux = -1;
 
 static gint ett_snmp = -1;
 static gint ett_smux = -1;
+static gint ett_parameters = -1;
+static gint ett_parameters_qos = -1;
 static gint ett_global = -1;
 static gint ett_flags = -1;
 static gint ett_secur = -1;
@@ -311,7 +332,8 @@ static const value_string smux_prio[] = {
 
 static const value_string smux_sout[] = {
        { SMUX_SOUT_COMMIT,             "Commit" },
-       { SMUX_SOUT_ROLLBACK,           "Rollback" }
+       { SMUX_SOUT_ROLLBACK,           "Rollback" },
+       { 0,                            NULL }
 };
 
 /* Error status values */
@@ -497,78 +519,127 @@ snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
 }
 
 static void
-dissect_snmp_parse_error(const u_char *pd, int offset, frame_data *fd,
+dissect_snmp_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
                   proto_tree *tree, const char *field_name, int ret)
 {
        const gchar *errstr;
 
-       if (check_col(fd, COL_INFO)) {
-               switch (ret) {
+       switch (ret) {
 
-               case ASN1_ERR_EMPTY:
-                       errstr = "Ran out of data";
-                       break;
+       case ASN1_ERR_EOC_MISMATCH:
+               errstr = "EOC mismatch";
+               break;
 
-               case ASN1_ERR_EOC_MISMATCH:
-                       errstr = "EOC mismatch";
-                       break;
+       case ASN1_ERR_WRONG_TYPE:
+               errstr = "Wrong type for that item";
+               break;
 
-               case ASN1_ERR_WRONG_TYPE:
-                       errstr = "Wrong type for that item";
-                       break;
+       case ASN1_ERR_LENGTH_NOT_DEFINITE:
+               errstr = "Length was indefinite";
+               break;
 
-               case ASN1_ERR_LENGTH_NOT_DEFINITE:
-                       errstr = "Length was indefinite";
-                       break;
+       case ASN1_ERR_LENGTH_MISMATCH:
+               errstr = "Length mismatch";
+               break;
 
-               case ASN1_ERR_LENGTH_MISMATCH:
-                       errstr = "Length mismatch";
-                       break;
+       case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
+               errstr = "Wrong length for that item's type";
+               break;
 
-               case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
-                       errstr = "Wrong length for that item's type";
-                       break;
+       default:
+               errstr = "Unknown error";
+               break;
+       }
 
-               default:
-                       errstr = "Unknown error";
-                       break;
-               }
-               col_add_fstr(fd, COL_INFO,
+       if (check_col(pinfo->fd, COL_INFO)) {
+               col_add_fstr(pinfo->fd, COL_INFO,
                    "ERROR: Couldn't parse %s: %s", field_name, errstr);
        }
-
-       dissect_data(pd, offset, fd, tree);
+       if (tree != NULL) {
+               proto_tree_add_text(tree, tvb, offset, 0,
+                   "ERROR: Couldn't parse %s: %s", field_name, errstr);
+               dissect_data(tvb, offset, pinfo, tree);
+       }
 }
 
 static void
-dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
+dissect_snmp_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
                   proto_tree *tree, const char *message)
 {
-       if (check_col(fd, COL_INFO))
-               col_add_str(fd, COL_INFO, message);
+       if (check_col(pinfo->fd, COL_INFO))
+               col_add_str(pinfo->fd, COL_INFO, message);
 
-       dissect_data(pd, offset, fd, tree);
+       if (tree != NULL) {
+               proto_tree_add_text(tree, tvb, offset, 0, "%s", message);
+               dissect_data(tvb, offset, pinfo, tree);
+       }
 }
 
-static void
-format_oid(gchar *buf, subid_t *oid, guint oid_length)
+static gchar *
+format_oid(subid_t *oid, guint oid_length)
 {
-       int i;
+       char *result;
+       int result_len;
        int len;
+       unsigned int i;
+       char *buf;
 
+       result_len = oid_length * 22;
+       result = g_malloc(result_len + 1);
+       buf = result;
        len = sprintf(buf, "%lu", (unsigned long)oid[0]);
        buf += len;
        for (i = 1; i < oid_length;i++) {
                len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
                buf += len;
        }
+       return result;
 }
 
 #ifdef HAVE_SPRINT_VALUE
-static void
-format_value(gchar *buf, struct variable_list *variable, subid_t *variable_oid,
+static gchar *
+format_var(struct variable_list *variable, subid_t *variable_oid,
     guint variable_oid_length, gushort vb_type, guint vb_length)
 {
+       gchar *buf;
+
+       switch (vb_type) {
+
+       case SNMP_INTEGER:
+       case SNMP_COUNTER:
+       case SNMP_GAUGE:
+       case SNMP_TIMETICKS:
+               /* We don't know how long this will be, but let's guess it
+                  fits within 128 characters; that should be enough for an
+                  integral value plus some sort of type indication. */
+               buf = g_malloc(128);
+               break;
+
+       case SNMP_OCTETSTR:
+       case SNMP_IPADDR:
+       case SNMP_OPAQUE:
+       case SNMP_NSAP:
+       case SNMP_BITSTR:
+       case SNMP_COUNTER64:
+               /* We don't know how long this will be, but let's guess it
+                  fits within 128 characters plus 4 characters per octet. */
+               buf = g_malloc(128 + 4*vb_length);
+               break;
+
+       case SNMP_OBJECTID:
+               /* We don't know how long this will be, but let's guess it
+                  fits within 128 characters plus 32 characters per subid
+                  (10 digits plus period, or a subid name). */
+               buf = g_malloc(1024 + 32*vb_length);
+               break;
+
+       default:
+               /* Should not happen. */
+               g_assert_not_reached();
+               buf = NULL;
+               break;
+       }
+
        variable->next_variable = NULL;
        variable->name = variable_oid;
        variable->name_length = variable_oid_length;
@@ -608,6 +679,7 @@ format_value(gchar *buf, struct variable_list *variable, subid_t *variable_oid,
 
        case SNMP_OBJECTID:
                variable->type = VALTYPE_OBJECTID;
+               vb_length *= sizeof (subid_t);  /* XXX - necessary? */
                break;
 
        case SNMP_BITSTR:
@@ -619,15 +691,18 @@ format_value(gchar *buf, struct variable_list *variable, subid_t *variable_oid,
                break;
        }
        variable->val_len = vb_length;
+
        sprint_value(buf, variable_oid, variable_oid_length, variable);
+       return buf;
 }
 #endif
 
 static int
 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
-    guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp)
+    guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp,
+    gboolean unsafe)
 {
-       const guchar *start;
+       int start;
        guint length;
        gboolean def;
        guint vb_length;
@@ -644,21 +719,20 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
        subid_t *vb_oid;
        guint vb_oid_length;
 
-       gchar vb_display_string[MAX_STRING_LEN]; /* TBC */
+       gchar *vb_display_string;
 
 #ifdef HAVE_SPRINT_VALUE
        struct variable_list variable;
 #if defined(HAVE_UCD_SNMP_SNMP_H)
        long value;
 #endif
-#else  /* HAVE_SPRINT_VALUE */
-       int i;
+#endif /* HAVE_SPRINT_VALUE */
+       unsigned int i;
        gchar *buf;
        int len;
-#endif /* HAVE_SPRINT_VALUE */
 
        /* parse the type of the object */
-       start = asn1->pointer;
+       start = asn1->offset;
        ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
        if (ret != ASN1_ERR_NOERROR)
                return ret;
@@ -684,25 +758,29 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
                    &vb_integer_value);
                if (ret != ASN1_ERR_NOERROR)
                        return ret;
-               length = asn1->pointer - start;
+               length = asn1->offset - start;
                if (snmp_tree) {
 #ifdef HAVE_SPRINT_VALUE
+                       if (!unsafe) {
 #if defined(HAVE_UCD_SNMP_SNMP_H)
-                       value = vb_integer_value;
-                       variable.val.integer = &value;
+                               value = vb_integer_value;
+                               variable.val.integer = &value;
 #elif defined(HAVE_SNMP_SNMP_H)
-                       variable.val.integer = &vb_integer_value;
+                               variable.val.integer = &vb_integer_value;
 #endif
-                       format_value(vb_display_string, &variable,
-                           variable_oid, variable_oid_length, vb_type,
-                           vb_length);
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
-                           "Value: %s", vb_display_string);
-#else
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                               vb_display_string = format_var(&variable,
+                                   variable_oid, variable_oid_length, vb_type,
+                                   vb_length);
+                               proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                                   length,
+                                   "Value: %s", vb_display_string);
+                               g_free(vb_display_string);
+                               break;  /* we added formatted version to the tree */
+                       }
+#endif /* HAVE_SPRINT_VALUE */
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
                            "Value: %s: %d (%#x)", vb_type_name,
                            vb_integer_value, vb_integer_value);
-#endif
                }
                break;
 
@@ -713,25 +791,29 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
                    &vb_uinteger_value);
                if (ret != ASN1_ERR_NOERROR)
                        return ret;
-               length = asn1->pointer - start;
+               length = asn1->offset - start;
                if (snmp_tree) {
 #ifdef HAVE_SPRINT_VALUE
+                       if (!unsafe) {
 #if defined(HAVE_UCD_SNMP_SNMP_H)
-                       value = vb_uinteger_value;
-                       variable.val.integer = &value;
+                               value = vb_uinteger_value;
+                               variable.val.integer = &value;
 #elif defined(HAVE_SNMP_SNMP_H)
-                       variable.val.integer = &vb_uinteger_value;
+                               variable.val.integer = &vb_uinteger_value;
 #endif
-                       format_value(vb_display_string, &variable,
-                           variable_oid, variable_oid_length, vb_type,
-                           vb_length);
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
-                           "Value: %s", vb_display_string);
-#else
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                               vb_display_string = format_var(&variable,
+                                   variable_oid, variable_oid_length, vb_type,
+                                   vb_length);
+                               proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                                   length,
+                                   "Value: %s", vb_display_string);
+                               g_free(vb_display_string);
+                               break;  /* we added formatted version to the tree */
+                       }
+#endif /* HAVE_SPRINT_VALUE */
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
                            "Value: %s: %u (%#x)", vb_type_name,
                            vb_uinteger_value, vb_uinteger_value);
-#endif
                }
                break;
 
@@ -741,20 +823,25 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
        case SNMP_NSAP:
        case SNMP_BITSTR:
        case SNMP_COUNTER64:
-               ret = asn1_octet_string_value_decode (asn1, vb_length,
+               ret = asn1_string_value_decode (asn1, vb_length,
                    &vb_octet_string);
                if (ret != ASN1_ERR_NOERROR)
                        return ret;
-               length = asn1->pointer - start;
+               length = asn1->offset - start;
                if (snmp_tree) {
 #ifdef HAVE_SPRINT_VALUE
-                       variable.val.string = vb_octet_string;
-                       format_value(vb_display_string, &variable,
-                           variable_oid, variable_oid_length, vb_type,
-                           vb_length);
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
-                           "Value: %s", vb_display_string);
-#else
+                       if (!unsafe) {
+                               variable.val.string = vb_octet_string;
+                               vb_display_string = format_var(&variable,
+                                   variable_oid, variable_oid_length, vb_type,
+                                   vb_length);
+                               proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                                   length,
+                                   "Value: %s", vb_display_string);
+                               g_free(vb_display_string);
+                               break;  /* we added formatted version to the tree */
+                       }
+#endif /* HAVE_SPRINT_VALUE */
                        /*
                         * If some characters are not printable, display
                         * the string as bytes.
@@ -770,6 +857,7 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
                                 * character, before we got to the end
                                 * of the string.
                                 */
+                               vb_display_string = g_malloc(4*vb_length);
                                buf = &vb_display_string[0];
                                len = sprintf(buf, "%03u", vb_octet_string[0]);
                                buf += len;
@@ -778,15 +866,16 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
                                            vb_octet_string[i]);
                                        buf += len;
                                }
-                               proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                               proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
                                    "Value: %s: %s", vb_type_name,
                                    vb_display_string);
+                               g_free(vb_display_string);
                        } else {
-                               proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                               proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
                                    "Value: %s: %.*s", vb_type_name,
-                                   (int)vb_length, vb_octet_string);
+                                   (int)vb_length,
+                                   SAFE_STRING(vb_octet_string));
                        }
-#endif
                }
                g_free(vb_octet_string);
                break;
@@ -795,9 +884,9 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
                ret = asn1_null_decode (asn1, vb_length);
                if (ret != ASN1_ERR_NOERROR)
                        return ret;
-               length = asn1->pointer - start;
+               length = asn1->offset - start;
                if (snmp_tree) {
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
                            "Value: %s", vb_type_name);
                }
                break;
@@ -807,44 +896,48 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
                    &vb_oid_length);
                if (ret != ASN1_ERR_NOERROR)
                        return ret;
-               length = asn1->pointer - start;
+               length = asn1->offset - start;
                if (snmp_tree) {
 #ifdef HAVE_SPRINT_VALUE
-                       variable.val.objid = vb_oid;
-                       format_value(vb_display_string, &variable,
-                           variable_oid, variable_oid_length, vb_type,
-                           vb_length*sizeof (subid_t));
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
-                           "Value: %s", vb_display_string);
-#else
-                       format_oid(vb_display_string, vb_oid, vb_oid_length);
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                       if (!unsafe) {
+                               variable.val.objid = vb_oid;
+                               vb_display_string = format_var(&variable,
+                                   variable_oid, variable_oid_length, vb_type,
+                                   vb_length);
+                               proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                                   length,
+                                   "Value: %s", vb_display_string);
+                               break;  /* we added formatted version to the tree */
+                       }
+#endif /* HAVE_SPRINT_VALUE */
+                       vb_display_string = format_oid(vb_oid, vb_oid_length);
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
                            "Value: %s: %s", vb_type_name, vb_display_string);
-#endif
+                       g_free(vb_display_string);
                }
                g_free(vb_oid);
                break;
 
        case SNMP_NOSUCHOBJECT:
-               length = asn1->pointer - start;
+               length = asn1->offset - start;
                if (snmp_tree) {
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
                            "Value: %s: no such object", vb_type_name);
                }
                break;
 
        case SNMP_NOSUCHINSTANCE:
-               length = asn1->pointer - start;
+               length = asn1->offset - start;
                if (snmp_tree) {
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
                            "Value: %s: no such instance", vb_type_name);
                }
                break;
 
        case SNMP_ENDOFMIBVIEW:
-               length = asn1->pointer - start;
+               length = asn1->offset - start;
                if (snmp_tree) {
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
                            "Value: %s: end of mib view", vb_type_name);
                }
                break;
@@ -858,8 +951,8 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
 }
 
 static void
-dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
-    proto_tree *tree, ASN1_SCK asn1, guint pdu_type, const guchar *start)
+dissect_common_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, ASN1_SCK asn1, guint pdu_type, int start)
 {
        gboolean def;
        guint length;
@@ -886,7 +979,7 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
        guint timestamp;
        guint timestamp_length;
 
-       gchar oid_string[MAX_STRING_LEN]; /* TBC */
+       gchar *oid_string;
 
        guint variable_bindings_length;
 
@@ -897,17 +990,18 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
        gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
 #endif
+       gboolean unsafe;
 
        int ret;
        guint cls, con, tag;
 
        pdu_type_string = val_to_str(pdu_type, pdu_types,
            "Unknown PDU type %#x");
-       if (check_col(fd, COL_INFO))
-               col_add_str(fd, COL_INFO, pdu_type_string);
-       length = asn1.pointer - start;
+       if (check_col(pinfo->fd, COL_INFO))
+               col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
+       length = asn1.offset - start;
        if (tree) {
-               proto_tree_add_text(tree, NullTVB, offset, length,
+               proto_tree_add_text(tree, tvb, offset, length,
                    "PDU type: %s", pdu_type_string);
        }
        offset += length;
@@ -926,12 +1020,12 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                /* request id */
                ret = asn1_uint32_decode (&asn1, &request_id, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "request ID", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(tree, NullTVB, offset, length,
+                       proto_tree_add_text(tree, tvb, offset, length,
                            "Request Id: %#x", request_id);
                }
                offset += length;
@@ -939,7 +1033,7 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                /* error status, or getbulk non-repeaters */
                ret = asn1_uint32_decode (&asn1, &error_status, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
                                                           : "error status",
                            ret);
@@ -947,10 +1041,10 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                }
                if (tree) {
                        if (pdu_type == SNMP_MSG_GETBULK) {
-                               proto_tree_add_text(tree, NullTVB, offset,
+                               proto_tree_add_text(tree, tvb, offset,
                                    length, "Non-repeaters: %u", error_status);
                        } else {
-                               proto_tree_add_text(tree, NullTVB, offset,
+                               proto_tree_add_text(tree, tvb, offset,
                                    length, "Error Status: %s",
                                    val_to_str(error_status, error_statuses,
                                      "Unknown (%d)"));
@@ -961,7 +1055,7 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                /* error index, or getbulk max-repetitions */
                ret = asn1_uint32_decode (&asn1, &error_index, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
                                                           : "error index",
                            ret);
@@ -969,10 +1063,10 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                }
                if (tree) {
                        if (pdu_type == SNMP_MSG_GETBULK) {
-                               proto_tree_add_text(tree, NullTVB, offset,
+                               proto_tree_add_text(tree, tvb, offset,
                                    length, "Max repetitions: %u", error_index);
                        } else {
-                               proto_tree_add_text(tree, NullTVB, offset,
+                               proto_tree_add_text(tree, tvb, offset,
                                    length, "Error Index: %u", error_index);
                        }
                }
@@ -984,24 +1078,25 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
                    &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "enterprise OID", ret);
                        return;
                }
                if (tree) {
-                       format_oid(oid_string, enterprise, enterprise_length);
-                       proto_tree_add_text(tree, NullTVB, offset, length,
+                       oid_string = format_oid(enterprise, enterprise_length);
+                       proto_tree_add_text(tree, tvb, offset, length,
                            "Enterprise: %s", oid_string);
+                       g_free(oid_string);
                }
                g_free(enterprise);
                offset += length;
 
                /* agent address */
-               start = asn1.pointer;
+               start = asn1.offset;
                ret = asn1_header_decode (&asn1, &cls, &con, &tag,
                    &def, &agent_address_length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "agent address", ret);
                        return;
                }
@@ -1009,27 +1104,35 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                    (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
                        /* GXSNMP 0.0.15 says the latter is "needed for
                           Banyan" */
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "agent_address", ASN1_ERR_WRONG_TYPE);
                        return;
                }
                if (agent_address_length != 4) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
                        return;
                }
-               ret = asn1_octet_string_value_decode (&asn1,
+               ret = asn1_string_value_decode (&asn1,
                    agent_address_length, &agent_address);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "agent address", ret);
                        return;
                }
-               length = asn1.pointer - start;
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(tree, NullTVB, offset,
-                            agent_address_length,
-                           "Agent address: %s", ip_to_str(agent_address));
+                       if (agent_address_length != 4) {
+                               proto_tree_add_text(tree, tvb, offset,
+                                   length,
+                                   "Agent address: <length is %u, not 4>",
+                                   agent_address_length);
+                       } else {
+                               proto_tree_add_text(tree, tvb, offset,
+                                   length,
+                                   "Agent address: %s",
+                                   ip_to_str(agent_address));
+                       }
                }
                g_free(agent_address);
                offset += length;
@@ -1037,12 +1140,12 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                /* generic trap type */
                ret = asn1_uint32_decode (&asn1, &trap_type, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "generic trap type", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(tree, NullTVB, offset, length,
+                       proto_tree_add_text(tree, tvb, offset, length,
                            "Trap type: %s",
                            val_to_str(trap_type, trap_types, "Unknown (%u)"));
                }               
@@ -1051,42 +1154,42 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                /* specific trap type */
                ret = asn1_uint32_decode (&asn1, &specific_type, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "specific trap type", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(tree, NullTVB, offset, length,
+                       proto_tree_add_text(tree, tvb, offset, length,
                            "Specific trap type: %u (%#x)",
                            specific_type, specific_type);
                }               
                offset += length;
                
                /* timestamp */
-               start = asn1.pointer;
+               start = asn1.offset;
                ret = asn1_header_decode (&asn1, &cls, &con, &tag,
                    &def, &timestamp_length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "timestamp", ret);
                        return;
                }
                if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
                    (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "timestamp", ASN1_ERR_WRONG_TYPE);
                        return;
                }
                ret = asn1_uint32_value_decode(&asn1, timestamp_length,
                    &timestamp);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "timestamp", ret);
                        return;
                }
-               length = asn1.pointer - start;
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(tree, NullTVB, offset, length,
+                       proto_tree_add_text(tree, tvb, offset, length,
                            "Timestamp: %u", timestamp);
                }               
                offset += length;
@@ -1097,7 +1200,7 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
        /* get header for variable-bindings sequence */
        ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
        if (ret != ASN1_ERR_NOERROR) {
-               dissect_snmp_parse_error(pd, offset, fd, tree,
+               dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                        "variable bindings header", ret);
                return;
        }
@@ -1112,7 +1215,7 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                /* parse type */
                ret = asn1_sequence_decode(&asn1, &variable_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                                "variable binding header", ret);
                        return;
                }
@@ -1122,37 +1225,66 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
                ret = asn1_oid_decode (&asn1, &variable_oid,
                    &variable_oid_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "variable binding OID", ret);
                        return;
                }
                sequence_length += length;
 
+               unsafe = FALSE;
                if (tree) {
-                       format_oid(oid_string, variable_oid,
+                       oid_string = format_oid(variable_oid,
                            variable_oid_length);
                        
 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
                        sprint_objid(vb_oid_string, variable_oid,
                            variable_oid_length);
-                       proto_tree_add_text(tree, NullTVB, offset, sequence_length,
+                       proto_tree_add_text(tree, tvb, offset, sequence_length,
                            "Object identifier %d: %s (%s)", vb_index,
                            oid_string, vb_oid_string);
-#else
-                       
-                       proto_tree_add_text(tree, NullTVB, offset, sequence_length,
+#ifdef HAVE_SNMP_SNMP_H
+                       /*
+                        * CMU SNMP has a bug wherein "sprint_value()"
+                        * calls "get_symbol()", passing it the
+                        * OID supplied, to get an information about the
+                        * variable, and blithely assumes that it will
+                        * never get a null pointer back and dereferences
+                        * the resulting pointer.
+                        *
+                        * Not true.  If there's nothing in the MIB
+                        * about *any* of the components of the OID,
+                        * it'll return a null pointer.
+                        *
+                        * So we have to check for that, and pass
+                        * down to "snmp_variable_decode" a flag
+                        * saying "don't pass this to 'sprint_value()'.
+                        *
+                        * We check for that by looking for a decoded
+                        * OID string beginning with "." followed by a
+                        * digit, meaning it couldn't even find any
+                        * symbolic representation for the very
+                        * beginning of the OID string.
+                        */
+                       if (vb_oid_string[0] == '.' &&
+                           isdigit((guchar)vb_oid_string[1]))
+                               unsafe = TRUE;
+#endif /* HAVE_SNMP_SNMP_H */
+#else /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
+                       proto_tree_add_text(tree, tvb, offset, sequence_length,
                            "Object identifier %d: %s", vb_index,
                            oid_string);
-#endif
+#endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
+                       g_free(oid_string);
                }
                offset += sequence_length;
                variable_bindings_length -= sequence_length;
                                
                /* Parse the variable's value */
                ret = snmp_variable_decode(tree, variable_oid,
-                   variable_oid_length, &asn1, offset, &length);
+                   variable_oid_length, &asn1, offset, &length,
+                   unsafe);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "variable", ret);
                        return;
                }
@@ -1161,12 +1293,141 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
        }
 }
 
+static const value_string qos_vals[] = {
+       { 0x0,  "No authentication or privacy" },
+       { 0x1,  "Authentication, no privacy" },
+       { 0x2,  "Authentication and privacy" },
+       { 0x3,  "Authentication and privacy" },
+       { 0,    NULL },
+};
+
+static void
+dissect_snmp2u_parameters(proto_tree *tree, tvbuff_t *tvb, int offset, int length,
+    guchar *parameters, int parameters_length)
+{
+       proto_item *item;
+       proto_tree *parameters_tree;
+       proto_tree *qos_tree;
+       guint8 model;
+       guint8 qos;
+       guint8 len;
+
+       item = proto_tree_add_text(tree, tvb, offset, length,
+           "Parameters");
+       parameters_tree = proto_item_add_subtree(item, ett_parameters);
+       offset += length - parameters_length;
+
+       if (parameters_length < 1)
+               return;
+       model = *parameters;
+       proto_tree_add_text(parameters_tree, tvb, offset, 1,
+           "model: %u", model);
+       offset += 1;
+       parameters += 1;
+       parameters_length -= 1;
+       if (model != 1) {
+               /* Unknown model. */
+               proto_tree_add_text(parameters_tree, tvb, offset,
+                   parameters_length, "parameters: %s",
+                   bytes_to_str(parameters, parameters_length));
+               return;
+       }
+
+       if (parameters_length < 1)
+               return;
+       qos = *parameters;
+       item = proto_tree_add_text(parameters_tree, tvb, offset, 1,
+           "qoS: 0x%x", qos);
+       qos_tree = proto_item_add_subtree(item, ett_parameters_qos);
+       proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
+           decode_boolean_bitfield(qos, 0x04,
+               8, "Generation of report PDU allowed",
+                  "Generation of report PDU not allowed"));
+       proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
+           decode_enumerated_bitfield(qos, 0x03,
+               8, qos_vals, "%s"));
+       offset += 1;
+       parameters += 1;
+       parameters_length -= 1;
+
+       if (parameters_length < 12)
+               return;
+       proto_tree_add_text(parameters_tree, tvb, offset, 12,
+           "agentID: %s", bytes_to_str(parameters, 12));
+       offset += 12;
+       parameters += 12;
+       parameters_length -= 12;
+
+       if (parameters_length < 4)
+               return;
+       proto_tree_add_text(parameters_tree, tvb, offset, 4,
+           "agentBoots: %u", pntohl(parameters));
+       offset += 4;
+       parameters += 4;
+       parameters_length -= 4;
+
+       if (parameters_length < 4)
+               return;
+       proto_tree_add_text(parameters_tree, tvb, offset, 4,
+           "agentTime: %u", pntohl(parameters));
+       offset += 4;
+       parameters += 4;
+       parameters_length -= 4;
+
+       if (parameters_length < 2)
+               return;
+       proto_tree_add_text(parameters_tree, tvb, offset, 2,
+           "maxSize: %u", pntohs(parameters));
+       offset += 2;
+       parameters += 2;
+       parameters_length -= 2;
+
+       if (parameters_length < 1)
+               return;
+       len = *parameters;
+       proto_tree_add_text(parameters_tree, tvb, offset, 1,
+           "userLen: %u", len);
+       offset += 1;
+       parameters += 1;
+       parameters_length -= 1;
+
+       if (parameters_length < len)
+               return;
+       proto_tree_add_text(parameters_tree, tvb, offset, len,
+           "userName: %.*s", len, parameters);
+       offset += len;
+       parameters += len;
+       parameters_length -= len;
+
+       if (parameters_length < 1)
+               return;
+       len = *parameters;
+       proto_tree_add_text(parameters_tree, tvb, offset, 1,
+           "authLen: %u", len);
+       offset += 1;
+       parameters += 1;
+       parameters_length -= 1;
+
+       if (parameters_length < len)
+               return;
+       proto_tree_add_text(parameters_tree, tvb, offset, len,
+           "authDigest: %s", bytes_to_str(parameters, len));
+       offset += len;
+       parameters += len;
+       parameters_length -= len;
+
+       if (parameters_length < 1)
+               return;
+       proto_tree_add_text(parameters_tree, tvb, offset, parameters_length,
+           "contextSelector: %s", bytes_to_str(parameters, parameters_length));
+}
+
 void
-dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
+dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
     proto_tree *tree, char *proto_name, int proto, gint ett)
 {
        ASN1_SCK asn1;
-       const guchar *start;
+       int start;
        gboolean def;
        gboolean encrypted;
        guint length;
@@ -1212,12 +1473,12 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
        int ret;
        guint cls, con, tag;
 
-       if (check_col(fd, COL_PROTOCOL))
-               col_add_str(fd, COL_PROTOCOL, proto_name);
+       if (check_col(pinfo->fd, COL_PROTOCOL))
+               col_add_str(pinfo->fd, COL_PROTOCOL, proto_name);
 
        if (tree) {
-               item = proto_tree_add_item(tree, proto, NullTVB, offset,
-                   END_OF_FRAME, NULL);
+               item = proto_tree_add_item(tree, proto, tvb, offset,
+                   tvb_length_remaining(tvb, offset), FALSE);
                snmp_tree = proto_item_add_subtree(item, ett);
        }
 
@@ -1226,10 +1487,10 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
         * parsing is likely to fail.
         */
        /* parse the SNMP header */
-       asn1_open(&asn1, &pd[offset], END_OF_FRAME);
+       asn1_open(&asn1, tvb, offset);
        ret = asn1_sequence_decode(&asn1, &message_length, &length);
        if (ret != ASN1_ERR_NOERROR) {
-               dissect_snmp_parse_error(pd, offset, fd, tree,
+               dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
                        "message header", ret);
                return;
        }
@@ -1237,12 +1498,12 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
 
        ret = asn1_uint32_decode (&asn1, &version, &length);
        if (ret != ASN1_ERR_NOERROR) {
-               dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
-                   ret);
+               dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
+                   "version number", ret);
                return;
        }
        if (snmp_tree) {
-               proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+               proto_tree_add_text(snmp_tree, tvb, offset, length,
                    "Version: %s",
                    val_to_str(version, versions, "Unknown version %#x"));
        }
@@ -1255,136 +1516,127 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                ret = asn1_octet_string_decode (&asn1, &community, 
                    &community_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree, 
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
                            "community", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
-                           "Community: %.*s", community_length, community);
+                       proto_tree_add_text(snmp_tree, tvb, offset, length,
+                           "Community: %.*s", community_length,
+                           SAFE_STRING(community));
                }
                g_free(community);
                offset += length;
                break;
        case SNMP_VERSION_2u:
-               /* FIXME */
+               ret = asn1_octet_string_decode (&asn1, &community, 
+                   &community_length, &length);
+               if (tree) {
+                       dissect_snmp2u_parameters(snmp_tree, tvb, offset, length,
+                           community, community_length);
+               }
+               g_free(community);
+               offset += length;
                break;
        case SNMP_VERSION_3:
                ret = asn1_sequence_decode(&asn1, &global_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
                                "message global header", ret);
                        return;
                }
                if (snmp_tree) {
-                       item = proto_tree_add_text(snmp_tree, NullTVB, offset,
+                       item = proto_tree_add_text(snmp_tree, tvb, offset,
                            global_length + length, "Message Global Header");
                        global_tree = proto_item_add_subtree(item, ett_global);
-                       proto_tree_add_text(global_tree, NullTVB, offset,
+                       proto_tree_add_text(global_tree, tvb, offset,
                            length,
                            "Message Global Header Length: %d", global_length);
                }
                offset += length;
                ret = asn1_uint32_decode (&asn1, &msgid, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree, 
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
                            "message id", ret);
                        return;
                }
                if (global_tree) {
-                       proto_tree_add_text(global_tree, NullTVB, offset,
+                       proto_tree_add_text(global_tree, tvb, offset,
                            length, "Message ID: %d", msgid);
                }
                offset += length;
                ret = asn1_uint32_decode (&asn1, &msgmax, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree, 
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
                            "message max size", ret);
                        return;
                }
                if (global_tree) {
-                       proto_tree_add_text(global_tree, NullTVB, offset,
+                       proto_tree_add_text(global_tree, tvb, offset,
                            length, "Message Max Size: %d", msgmax);
                }
                offset += length;
                ret = asn1_octet_string_decode (&asn1, &msgflags, 
                    &msgflags_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree, 
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
                            "message flags", ret);
                        return;
                }
                if (msgflags_length != 1) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
                            "message flags wrong length", ret);
                        g_free(msgflags);
                        return;
                }
                if (global_tree) {
                        item = proto_tree_add_uint_format(global_tree,
-                           hf_snmpv3_flags, NullTVB, offset, length,
+                           hf_snmpv3_flags, tvb, offset, length,
                            msgflags[0], "Flags: 0x%02x", msgflags[0]);
                        flags_tree = proto_item_add_subtree(item, ett_flags);
-                       proto_tree_add_item(flags_tree, hf_snmpv3_flags_report,
-                           NullTVB, offset, length, msgflags[0]);
-                       proto_tree_add_item(flags_tree, hf_snmpv3_flags_crypt,
-                           NullTVB, offset, length, msgflags[0]);
-                       proto_tree_add_item(flags_tree, hf_snmpv3_flags_auth,
-                           NullTVB, offset, length, msgflags[0]);
+                       proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
+                           tvb, offset, length, msgflags[0]);
+                       proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
+                           tvb, offset, length, msgflags[0]);
+                       proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
+                           tvb, offset, length, msgflags[0]);
                }
                encrypted = msgflags[0] & TH_CRYPT;
                g_free(msgflags);
                offset += length;
                ret = asn1_uint32_decode (&asn1, &msgsec, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree, 
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
                            "message security model", ret);
                        return;
                }
                if (global_tree) {
-                       proto_tree_add_text(global_tree, NullTVB, offset,
+                       proto_tree_add_text(global_tree, tvb, offset,
                            length, "Message Security Model: %s",
                            val_to_str(msgsec, sec_models,
                            "Unknown model %#x"));
                }
                offset += length;
                switch(msgsec) {
-               case SNMP_SEC_V1:
-               case SNMP_SEC_V2C:
-                       ret = asn1_octet_string_decode (&asn1, 
-                           &secparm, &secparm_length, &length);
-                       if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "Message Security Parameters", ret);
-                               return;
-                       }
-                       if (snmp_tree) {
-                               proto_tree_add_text(snmp_tree, NullTVB, offset,
-                                   length, "Message Security Parameters: %.*s",
-                                   secparm_length, secparm);
-                       }
-                       g_free(secparm);
-                       offset += length;
-                       break;
                case SNMP_SEC_USM:
-                       start = asn1.pointer;
+                       start = asn1.offset;
                        ret = asn1_header_decode (&asn1, &cls, &con, &tag,
                            &def, &secparm_length);
-                       length = asn1.pointer - start;
+                       length = asn1.offset - start;
                        if (cls != ASN1_UNI && con != ASN1_PRI && 
                            tag != ASN1_OTS) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "Message Security Parameters",
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "Message Security Parameters",
                                    ASN1_ERR_WRONG_TYPE);
                                return;
                        }
                        if (snmp_tree) {
-                               item = proto_tree_add_text(snmp_tree, NullTVB,
+                               item = proto_tree_add_text(snmp_tree, tvb,
                                    offset, secparm_length + length,
                                    "Message Security Parameters");
                                secur_tree = proto_item_add_subtree(item,
                                    ett_secur);
-                               proto_tree_add_text(secur_tree, NullTVB, offset,
+                               proto_tree_add_text(secur_tree, tvb, offset,
                                    length, 
                                    "Message Security Parameters Length: %d",
                                    secparm_length);
@@ -1393,20 +1645,20 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                        ret = asn1_sequence_decode(&asn1, &secparm_length,
                            &length);
                        if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree,
-                                   "USM sequence header", ret);
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "USM sequence header", ret);
                                return;
                        }
                        offset += length;
                        ret = asn1_octet_string_decode (&asn1, &aengineid, 
                            &aengineid_length, &length);
                        if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "authoritative engine id", ret);
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "authoritative engine id", ret);
                                return;
                        }
                        if (secur_tree) {
-                               proto_tree_add_text(secur_tree, NullTVB, offset,
+                               proto_tree_add_text(secur_tree, tvb, offset,
                                    length, "Authoritative Engine ID: %s",
                                    bytes_to_str(aengineid, aengineid_length));
                        }
@@ -1414,24 +1666,24 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                        offset += length;
                        ret = asn1_uint32_decode (&asn1, &engineboots, &length);
                        if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "engine boots", ret);
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "engine boots", ret);
                                return;
                        }
                        if (secur_tree) {
-                               proto_tree_add_text(secur_tree, NullTVB,
+                               proto_tree_add_text(secur_tree, tvb,
                                    offset, length, "Engine Boots: %d", 
                                    engineboots);
                        }
                        offset += length;
                        ret = asn1_uint32_decode (&asn1, &enginetime, &length);
                        if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "engine time", ret);
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree,  "engine time", ret);
                                return;
                        }
                        if (secur_tree) {
-                               proto_tree_add_text(secur_tree, NullTVB,
+                               proto_tree_add_text(secur_tree, tvb,
                                    offset, length, "Engine Time: %d", 
                                    enginetime);
                        }
@@ -1439,26 +1691,27 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                        ret = asn1_octet_string_decode (&asn1, &username, 
                            &username_length, &length);
                        if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "user name", ret);
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "user name", ret);
                                return;
                        }
                        if (secur_tree) {
-                               proto_tree_add_text(secur_tree, NullTVB, offset,
+                               proto_tree_add_text(secur_tree, tvb, offset,
                                    length, "User Name: %.*s", 
-                                   username_length, username);
+                                   username_length,
+                                   SAFE_STRING(username));
                        }
                        g_free(username);
                        offset += length;
                        ret = asn1_octet_string_decode (&asn1, &authpar, 
                            &authpar_length, &length);
                        if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "authentication parameter", ret);
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "authentication parameter", ret);
                                return;
                        }
                        if (secur_tree) {
-                               proto_tree_add_text(secur_tree, NullTVB, offset,
+                               proto_tree_add_text(secur_tree, tvb, offset,
                                    length, "Authentication Parameter: %s",
                                    bytes_to_str(authpar, authpar_length));
                        }
@@ -1467,12 +1720,12 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                        ret = asn1_octet_string_decode (&asn1, &privpar, 
                            &privpar_length, &length);
                        if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "privacy parameter", ret);
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "privacy parameter", ret);
                                return;
                        }
                        if (secur_tree) {
-                               proto_tree_add_text(secur_tree, NullTVB, offset,
+                               proto_tree_add_text(secur_tree, tvb, offset,
                                    length, "Privacy Parameter: %s",
                                    bytes_to_str(privpar, privpar_length));
                        }
@@ -1483,12 +1736,13 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                        ret = asn1_octet_string_decode (&asn1, 
                            &secparm, &secparm_length, &length);
                        if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "Message Security Parameters", ret);
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "Message Security Parameters",
+                                   ret);
                                return;
                        }
                        if (snmp_tree) {
-                               proto_tree_add_text(snmp_tree, NullTVB, offset,
+                               proto_tree_add_text(snmp_tree, tvb, offset,
                                    length,
                                    "Message Security Parameters Data"
                                    " (%d bytes)", secparm_length);
@@ -1502,20 +1756,20 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                        ret = asn1_octet_string_decode (&asn1, &cryptpdu,
                            &cryptpdu_length, &length);
                        if (ret != ASN1_ERR_NOERROR) {
-                               dissect_snmp_parse_error(pd, offset, fd, tree, 
-                                   "encrypted PDU header", ret);
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "encrypted PDU header", ret);
                                return;
                        }
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                       proto_tree_add_text(snmp_tree, tvb, offset, length,
                            "Encrypted PDU (%d bytes)", length);
                        g_free(cryptpdu);
-                       if (check_col(fd, COL_INFO))
-                               col_add_str(fd, COL_INFO, "Encrypted PDU");
+                       if (check_col(pinfo->fd, COL_INFO))
+                               col_set_str(pinfo->fd, COL_INFO, "Encrypted PDU");
                        return;
                }
                ret = asn1_sequence_decode(&asn1, &global_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
                                "PDU header", ret);
                        return;
                }
@@ -1523,12 +1777,12 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                ret = asn1_octet_string_decode (&asn1, &cengineid, 
                    &cengineid_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree, 
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
                            "context engine id", ret);
                        return;
                }
                if (snmp_tree) {
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                       proto_tree_add_text(snmp_tree, tvb, offset, length,
                            "Context Engine ID: %s",
                            bytes_to_str(cengineid, cengineid_length));
                }
@@ -1537,45 +1791,46 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                ret = asn1_octet_string_decode (&asn1, &cname, 
                    &cname_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree, 
+                       dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
                            "context name", ret);
                        return;
                }
                if (snmp_tree) {
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
-                           "Context Name: %s", cname);
+                       proto_tree_add_text(snmp_tree, tvb, offset, length,
+                           "Context Name: %.*s", cname_length,
+                           SAFE_STRING(cname));
                }
                g_free(cname);
                offset += length;
                break;
        default:
-               dissect_snmp_error(pd, offset, fd, tree,
+               dissect_snmp_error(tvb, offset, pinfo, snmp_tree,
                    "PDU for unknown version of SNMP");
                return;
        }
 
-       start = asn1.pointer;
+       start = asn1.offset;
        ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
            &pdu_length);
        if (ret != ASN1_ERR_NOERROR) {
-               dissect_snmp_parse_error(pd, offset, fd, tree,
+               dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
                    "PDU type", ret);
                return;
        }
        if (cls != ASN1_CTX || con != ASN1_CON) {
-               dissect_snmp_parse_error(pd, offset, fd, tree,
+               dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
                    "PDU type", ASN1_ERR_WRONG_TYPE);
                return;
        }
-       dissect_common_pdu(pd, offset, fd, snmp_tree, asn1, pdu_type, start);
+       dissect_common_pdu(tvb, offset, pinfo, snmp_tree, asn1, pdu_type, start);
 }
 
 static void
-dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
+dissect_smux_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
     proto_tree *tree, int proto, gint ett)
 {
        ASN1_SCK asn1;
-       const guchar *start;
+       int start;
        gboolean def;
        guint length;
 
@@ -1598,19 +1853,19 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
        subid_t *regid;
        guint regid_length;
 
-       gchar oid_string[MAX_STRING_LEN]; /* TBC */
+       gchar *oid_string;
 
        proto_tree *smux_tree = NULL;
        proto_item *item = NULL;
        int ret;
        guint cls, con;
 
-       if (check_col(fd, COL_PROTOCOL))
-               col_add_str(fd, COL_PROTOCOL, "SMUX");
+       if (check_col(pinfo->fd, COL_PROTOCOL))
+               col_set_str(pinfo->fd, COL_PROTOCOL, "SMUX");
 
        if (tree) {
-               item = proto_tree_add_item(tree, proto, NullTVB, offset,
-                   END_OF_FRAME, NULL);
+               item = proto_tree_add_item(tree, proto, tvb, offset,
+                   tvb_length_remaining(tvb, offset), FALSE);
                smux_tree = proto_item_add_subtree(item, ett);
        }
 
@@ -1619,49 +1874,51 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
         * parsing is likely to fail.
         */
        /* parse the SNMP header */
-       asn1_open(&asn1, &pd[offset], END_OF_FRAME);
-       start = asn1.pointer;
+       asn1_open(&asn1, tvb, offset);
+       start = asn1.offset;
        ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
            &pdu_length);
        if (ret != ASN1_ERR_NOERROR) {
-               dissect_snmp_parse_error(pd, offset, fd, tree,
+               dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                    "PDU type", ret);
                return;
        }
+
        /* Dissect SMUX here */
        if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
                pdu_type_string = val_to_str(pdu_type, smux_types,
                    "Unknown PDU type %#x");
-               if (check_col(fd, COL_INFO))
-                       col_add_str(fd, COL_INFO, pdu_type_string);
-               length = asn1.pointer - start;
+               if (check_col(pinfo->fd, COL_INFO))
+                       col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "PDU type: %s", pdu_type_string);
                }
                offset += length;
                ret = asn1_uint32_decode (&asn1, &version, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                            "version", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "Version: %d", version);
                }
                offset += length;
 
                ret = asn1_oid_decode (&asn1, &regid, &regid_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                            "registration OID", ret);
                        return;
                }
                if (tree) {
-                       format_oid(oid_string, regid, regid_length);
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       oid_string = format_oid(regid, regid_length);
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "Registration: %s", oid_string);
+                       g_free(oid_string);
                }
                g_free(regid);
                offset += length;
@@ -1669,14 +1926,14 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
                ret = asn1_octet_string_decode (&asn1, &application, 
                    &application_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree, 
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree, 
                            "application", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "Application: %.*s", application_length,
-                            application);
+                            SAFE_STRING(application));
                }
                g_free(application);
                offset += length;
@@ -1684,13 +1941,14 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
                ret = asn1_octet_string_decode (&asn1, &password, 
                    &password_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree, 
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree, 
                            "password", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
-                           "Password: %.*s", password_length, password);
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
+                           "Password: %.*s", password_length,
+                           SAFE_STRING(password));
                }
                g_free(password);
                offset += length;
@@ -1699,22 +1957,22 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
        if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
                pdu_type_string = val_to_str(pdu_type, smux_types,
                    "Unknown PDU type %#x");
-               if (check_col(fd, COL_INFO))
-                       col_add_str(fd, COL_INFO, pdu_type_string);
-               length = asn1.pointer - start;
+               if (check_col(pinfo->fd, COL_INFO))
+                       col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "PDU type: %s", pdu_type_string);
                }
                offset += length;
                ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                            "cause", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset,
+                       proto_tree_add_text(smux_tree, tvb, offset,
                            pdu_length, "Cause: %s",
                            val_to_str(cause, smux_close, 
                                "Unknown cause %#x"));
@@ -1725,48 +1983,49 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
        if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
                pdu_type_string = val_to_str(pdu_type, smux_types,
                    "Unknown PDU type %#x");
-               if (check_col(fd, COL_INFO))
-                       col_add_str(fd, COL_INFO, pdu_type_string);
-               length = asn1.pointer - start;
+               if (check_col(pinfo->fd, COL_INFO))
+                       col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "PDU type: %s", pdu_type_string);
                }
                offset += length;
                ret = asn1_oid_decode (&asn1, &regid, &regid_length, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                            "registration subtree", ret);
                        return;
                }
                if (tree) {
-                       format_oid(oid_string, regid, regid_length);
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       oid_string = format_oid(regid, regid_length);
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "Registration: %s", oid_string);
+                       g_free(oid_string);
                }
                g_free(regid);
                offset += length;
 
                ret = asn1_uint32_decode (&asn1, &priority, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                            "priority", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "Priority: %d", priority);
                }
                offset += length;
 
                ret = asn1_uint32_decode (&asn1, &operation, &length);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                            "operation", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "Operation: %s", 
                            val_to_str(operation, smux_rreq, 
                                "Unknown operation %#x"));
@@ -1777,22 +2036,22 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
        if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
                pdu_type_string = val_to_str(pdu_type, smux_types,
                    "Unknown PDU type %#x");
-               if (check_col(fd, COL_INFO))
-                       col_add_str(fd, COL_INFO, pdu_type_string);
-               length = asn1.pointer - start;
+               if (check_col(pinfo->fd, COL_INFO))
+                       col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "PDU type: %s", pdu_type_string);
                }
                offset += length;
                ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                            "priority", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset,
+                       proto_tree_add_text(smux_tree, tvb, offset,
                            pdu_length, "%s",
                            val_to_str(priority, smux_prio, 
                                "Priority: %#x"));
@@ -1803,22 +2062,22 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
        if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
                pdu_type_string = val_to_str(pdu_type, smux_types,
                    "Unknown PDU type %#x");
-               if (check_col(fd, COL_INFO))
-                       col_add_str(fd, COL_INFO, pdu_type_string);
-               length = asn1.pointer - start;
+               if (check_col(pinfo->fd, COL_INFO))
+                       col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "PDU type: %s", pdu_type_string);
                }
                offset += length;
                ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                            "commit", ret);
                        return;
                }
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset,
+                       proto_tree_add_text(smux_tree, tvb, offset,
                            pdu_length, "%s",
                            val_to_str(commit, smux_sout, 
                                "Unknown SOUT Value: %#x"));
@@ -1827,49 +2086,92 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
                return;
        }
        if (cls != ASN1_CTX || con != ASN1_CON) {
-               dissect_snmp_parse_error(pd, offset, fd, tree,
+               dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
                    "PDU type", ASN1_ERR_WRONG_TYPE);
                return;
        }
-       dissect_common_pdu(pd, offset, fd, smux_tree, asn1, pdu_type, start);
+       dissect_common_pdu(tvb, offset, pinfo, smux_tree, asn1, pdu_type, start);
 }
 
 static void
-dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
+dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 
 {
-       dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
+       conversation_t  *conversation;
+
+       /*
+        * XXX - this is a conversation dissector, and the code to
+        * call a conversation dissector doesn't check for disabled
+        * protocols or set "pinfo->current_proto".
+        */
+       CHECK_DISPLAY_AS_DATA(proto_snmp, tvb, pinfo, tree);
+
+       pinfo->current_proto = "SNMP";
+
+       /*
+        * The first SNMP packet goes to the SNMP port; the second one
+        * may come from some *other* port, but goes back to the same
+        * IP address and port as the ones from which the first packet
+        * came; all subsequent packets presumably go between those two
+        * IP addresses and ports.
+        *
+        * If this packet went to the SNMP port, we check to see if
+        * there's already a conversation with one address/port pair
+        * matching the source IP address and port of this packet,
+        * the other address matching the destination IP address of this
+        * packet, and any destination port.
+        *
+        * If not, we create one, with its address 1/port 1 pair being
+        * the source address/port of this packet, its address 2 being
+        * the destination address of this packet, and its port 2 being
+        * wildcarded, and give it the SNMP dissector as a dissector.
+        */
+       if (pinfo->destport == UDP_PORT_SNMP) {
+         conversation = find_conversation(&pinfo->src, &pinfo->dst, PT_UDP,
+                                          pinfo->srcport, 0, NO_PORT_B);
+         if (conversation == NULL) {
+           conversation = conversation_new(&pinfo->src, &pinfo->dst, PT_UDP,
+                                           pinfo->srcport, 0, NO_PORT2);
+           conversation_set_dissector(conversation, dissect_snmp);
+         }
+       }
+
+       dissect_snmp_pdu(tvb, 0, pinfo, tree, "SNMP", proto_snmp, ett_snmp);
 }
 
 static void
-dissect_smux(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
+dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 
 {
-       dissect_smux_pdu(pd, offset, fd, tree, proto_smux, ett_smux);
+       dissect_smux_pdu(tvb, 0, pinfo, tree, proto_smux, ett_smux);
 }
 
 void
 proto_register_snmp(void)
 {
+#if defined(HAVE_UCD_SNMP_SNMP_H) && defined(linux)
+       void *libsnmp_handle;
+       int (*snmp_set_suffix_only_p)(int);
+       int (*ds_set_int_p)(int, int, int);
+#endif
+
         static hf_register_info hf[] = {
                { &hf_snmpv3_flags,
                { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
-                   0x0, "" }},
+                   0x0, "", HFILL }},
                { &hf_snmpv3_flags_auth,
                { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
-                   TFS(&flags_set_truth), TH_AUTH, "" }},
+                   TFS(&flags_set_truth), TH_AUTH, "", HFILL }},
                { &hf_snmpv3_flags_crypt,
                { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
-                   TFS(&flags_set_truth), TH_CRYPT, "" }},
+                   TFS(&flags_set_truth), TH_CRYPT, "", HFILL }},
                { &hf_snmpv3_flags_report,
                { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
-                   TFS(&flags_set_truth), TH_REPORT, "" }},
-/*
-                { &hf_variable,
-                { "Name",           "snmp.abbreviation", TYPE, VALS_POINTER }},
-*/
+                   TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
         };
        static gint *ett[] = {
                &ett_snmp,
                &ett_smux,
+               &ett_parameters,
+               &ett_parameters_qos,
                &ett_global,
                &ett_flags,
                &ett_secur,
@@ -1879,11 +2181,119 @@ proto_register_snmp(void)
        /* UCD or CMU SNMP */
        init_mib();
 #ifdef HAVE_UCD_SNMP_SNMP_H
-       snmp_set_full_objid(TRUE);
-#endif
-#endif
-        proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp");
-        proto_smux = proto_register_protocol("SNMP Multiplex Protocol", "smux");
+#ifdef linux
+       /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
+          changed "snmp_set_suffix_only()" from a function to a macro,
+          removing "snmp_set_suffix_only()" from the library; this means
+          that binaries that call "snmp_set_suffix_only()" and
+          that are linked against shared libraries from earlier versions
+          of the UCD SNMP library won't run with shared libraries from
+          4.1.1.
+
+          This is a problem on Red Hat Linux, as pre-6.2 releases
+          came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
+          Versions of Ethereal built on pre-6.2 releases don't run
+          on 6.2, and the current Ethereal RPMs are built on pre-6.2
+          releases, causing problems when users running 6.2 download
+          them and try to use them.
+
+          Building the releases on 6.2 isn't necessarily the answer,
+          as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
+          with a second argument not supported by at least some pre-4.1.1
+          versions of the library - it appears that the 4.0.1 library,
+          at least, checks for invalid arguments and returns an error
+          rather than stomping random memory, but that means that you
+          won't get get OIDs displayed as module-name::sub-OID.
+
+          So we use a trick similar to one I've seen mentioned as
+          used in Windows applications to let you build binaries
+          that run on many different versions of Windows 9x and
+          Windows NT, that use features present on later versions
+          if run on those later versions, but that avoid calling,
+          when run on older versions, routines not present on those
+          older versions.
+
+          I.e., we load "libsnmp.so.0" with "dlopen()", and call
+          "dlsym()" to try to find "snmp_set_suffix_only()"; if we
+          don't find it, we make the appropriate call to
+          "ds_set_int()" instead.  (We load "libsnmp.so.0" rather
+          than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
+          exists only if you've loaded the libsnmp development package,
+          which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
+          don't want to force users to install it or to make said
+          symlink by hand.)
+
+          We do this only on Linux, for now, as we've only seen the
+          problem on Red Hat; it may show up on other OSes that bundle
+          UCD SNMP, or on OSes where it's not bundled but for which
+          binary packages are built that link against a shared version
+          of the UCD SNMP library.  If we run into one of those, we
+          can do this under those OSes as well, *if* "dlopen()" makes
+          the run-time linker use the same search rules as it uses when
+          loading libraries with which the application is linked.
+
+          (Perhaps we could use the GLib wrappers for run-time linking,
+          *if* they're thin enough; however, as this code is currently
+          used only on Linux, we don't worry about that for now.) */
+
+       libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
+       if (libsnmp_handle == NULL) {
+               /* We didn't find "libsnmp.so.0".
+
+                  This could mean that there is no SNMP shared library
+                  on this system, in which case we were linked statically,
+                  in which case whatever call the following line of code
+                  makes will presumably work, as we have the routine it
+                  calls wired into our binary.  (If we were linked
+                  dynamically with "-lsnmp", we would have failed to
+                  start.)
+
+                  It could also mean that there is an SNMP shared library
+                  on this system, but it's called something other than
+                  "libsnmp.so.0"; so far, we've seen the problem we're
+                  working around only on systems where the SNMP shared
+                  library is called "libsnmp.so.0", so we assume for now
+                  that systems with shared SNMP libraries named something
+                  other than "libsnmp.so.0" have an SNMP library that's
+                  not 4.1.1. */
+               snmp_set_suffix_only(2);
+       } else {
+               /* OK, we have it loaded.  Do we have
+                  "snmp_set_suffix_only()"? */
+               snmp_set_suffix_only_p = dlsym(libsnmp_handle,
+                   "snmp_set_suffix_only");
+               if (snmp_set_suffix_only_p != NULL) {
+                       /* Yes - call it. */
+                       (*snmp_set_suffix_only_p)(2);
+               } else {
+                       /* No; do we have "ds_set_int()"? */
+                       ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
+                       if (ds_set_int_p != NULL) {
+                               /* Yes - cal it with DS_LIBRARY_ID,
+                                  DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
+                                  arguments.
+
+                                  We do *not* use DS_LIBRARY_ID or
+                                  DS_LIB_PRINT_SUFFIX_ONLY by name, so that
+                                  we don't require that Ethereal be built
+                                  with versions of UCD SNMP that include
+                                  that value; instead, we use their values
+                                  in UCD SNMP 4.1.1, which are 0 and 4,
+                                  respectively. */
+                               (*ds_set_int_p)(0, 4, 2);
+                       }
+               }
+               dlclose(libsnmp_handle);
+       }
+#else /* linux */
+       snmp_set_suffix_only(2);
+#endif /* linux */
+#endif /* HAVE_UCD_SNMP_SNMP_H */
+#endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
+        proto_snmp = proto_register_protocol("Simple Network Management Protocol",
+           "SNMP", "snmp");
+        proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
+           "SMUX", "smux");
         proto_register_field_array(proto_snmp, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
 }
@@ -1891,10 +2301,12 @@ proto_register_snmp(void)
 void
 proto_reg_handoff_snmp(void)
 {
-       dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp);
-       dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp);
-       dissector_add("tcp.port", TCP_PORT_SMUX, dissect_smux);
-       dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp);
-       dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, dissect_snmp);
-       dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, dissect_snmp);
+       dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp, proto_snmp);
+       dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp, proto_snmp);
+       dissector_add("tcp.port", TCP_PORT_SMUX, dissect_smux, proto_smux);
+       dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp, proto_snmp);
+       dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, dissect_snmp,
+           proto_snmp);
+       dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, dissect_snmp,
+           proto_snmp);
 }