Handle SNMP-over-TCP.
[obnox/wireshark/wip.git] / packet-snmp.c
index 4a33b2795cd4cd26d18d9f04cb54eb34ccfd23e3..5761c770c739b1ce72195c3d362c6a41e8642776 100644 (file)
@@ -1,21 +1,23 @@
 /* packet-snmp.c
  * Routines for SNMP (simple network management protocol)
- * D.Jorand (c) 1998
+ * Copyright (C) 1998 Didier Jorand
  *
  * See RFC 1157 for SNMPv1.
  *
  * See RFCs 1901, 1905, and 1906 for SNMPv2c.
  *
- * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u.
+ * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u [historic].
  *
- * $Id: packet-snmp.c,v 1.58 2001/01/30 02:13:43 guy Exp $
+ * See RFCs 2570-2576 for SNMPv3
+ *
+ * $Id: packet-snmp.c,v 1.113 2003/09/06 01:21:00 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:
- * 
+ *
  * GXSNMP -- An snmp mangament application
  * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
  * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <string.h>
 #include <ctype.h>
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-#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 <epan/packet.h>
+#include <epan/strutil.h>
+#include <epan/conversation.h>
 #include "etypes.h"
+#include "prefs.h"
 #include "packet-ipx.h"
+#include "packet-hpext.h"
+#include "packet-frame.h"
+
+#ifdef HAVE_SOME_SNMP
+
+#ifdef HAVE_NET_SNMP
+# include <net-snmp/net-snmp-config.h>
+# include <net-snmp/mib_api.h>
+# include <net-snmp/library/default_store.h>
+# include <net-snmp/config_api.h>
+#else /* HAVE_NET_SNMP */
+# include <ucd-snmp/ucd-snmp-config.h>
+# include <ucd-snmp/asn1.h>
+# include <ucd-snmp/snmp_api.h>
+# include <ucd-snmp/snmp_impl.h>
+# include <ucd-snmp/mib.h>
+# include <ucd-snmp/default_store.h>
+# include <ucd-snmp/read_config.h>
+# include <ucd-snmp/tools.h>
+#endif /* HAVE_NET_SNMP */
+
+#ifndef NETSNMP_DS_LIBRARY_ID
+# define NETSNMP_DS_LIBRARY_ID DS_LIBRARY_ID
+# define NETSNMP_DS_LIB_NO_TOKEN_WARNINGS DS_LIB_NO_TOKEN_WARNINGS
+# define NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY DS_LIB_PRINT_SUFFIX_ONLY
+# define netsnmp_ds_set_boolean ds_set_boolean
+# define netsnmp_ds_set_int ds_set_int
+#endif
 
-#if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
- /*
-  * UCD or CMU SNMP?
-  */
-# if defined(HAVE_UCD_SNMP_SNMP_H)
-   /*
-    * UCD SNMP.
-    */
-#  include <ucd-snmp/asn1.h>
-#  include <ucd-snmp/snmp_api.h>
-#  include <ucd-snmp/snmp_impl.h>
-#  include <ucd-snmp/mib.h>
-
-   /*
-    * 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_int()".
-    *
-    * However:
-    *
-    *  1) we can't include it on earlier versions (at least not 3.6.2),
-    *     as it doesn't exist in those versions;
-    *
-    *  2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
-    *     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_suffix_only" is defined as
-    * a macro.
-    */
-#  ifdef snmp_set_suffix_only
-#   include <ucd-snmp/default_store.h>
-#  endif
-
-   /*
-    * XXX - for now, we assume all versions of UCD SNMP have it.
-    */
-#  define HAVE_SPRINT_VALUE
-
-   /*
-    * Define values "sprint_value()" expects.
-    */
-#  define VALTYPE_INTEGER      ASN_INTEGER
-#  define VALTYPE_COUNTER      ASN_COUNTER
-#  define VALTYPE_GAUGE                ASN_GAUGE
-#  define VALTYPE_TIMETICKS    ASN_TIMETICKS
-#  define VALTYPE_STRING       ASN_OCTET_STR
-#  define VALTYPE_IPADDR       ASN_IPADDRESS
-#  define VALTYPE_OPAQUE       ASN_OPAQUE
-#  define VALTYPE_NSAP         ASN_NSAP
-#  define VALTYPE_OBJECTID     ASN_OBJECT_ID
-#  define VALTYPE_BITSTR       ASN_BIT_STR
-#  define VALTYPE_COUNTER64    ASN_COUNTER64
-# elif defined(HAVE_SNMP_SNMP_H)
-   /*
-    * CMU SNMP.
-    */
-#  include <snmp/snmp.h>
+#ifdef WIN32
+# include <epan/filesystem.h>
+#endif /* WIN32 */
 
    /*
-    * Some older versions of CMU SNMP may lack these values (e.g., the
-    * "libsnmp3.6" package for Debian, which is based on some old
-    * CMU SNMP, perhaps 1.0); for now, we assume they also lack
-    * "sprint_value()".
+    * Define values "sprint_realloc_value()" expects.
     */
-#  ifdef SMI_INTEGER
-#   define HAVE_SPRINT_VALUE
-    /*
-     * Define values "sprint_value()" expects.
-     */
-#   define VALTYPE_INTEGER     SMI_INTEGER
-#   define VALTYPE_COUNTER     SMI_COUNTER32
-#   define VALTYPE_GAUGE       SMI_GAUGE32
-#   define VALTYPE_TIMETICKS   SMI_TIMETICKS
-#   define VALTYPE_STRING      SMI_STRING
-#   define VALTYPE_IPADDR      SMI_IPADDRESS
-#   define VALTYPE_OPAQUE      SMI_OPAQUE
-#   define VALTYPE_NSAP                SMI_STRING
-#   define VALTYPE_OBJECTID    SMI_OBJID
-#   define VALTYPE_BITSTR      ASN_BIT_STR
-#   define VALTYPE_COUNTER64   SMI_COUNTER64
-#  endif
-  /*
-   * Now undo all the definitions they "helpfully" gave us, so we don't get
-   * complaints about redefining them.
-   *
-   * Why, oh why, is there no library that provides code to
-   *
-   *   1) read MIB files;
-   *
-   *   2) translate object IDs into names;
-   *
-   *   3) let you find out, for a given object ID, what the type, enum
-   *      values, display hint, etc. are;
-   *
-   * in a *simple* fashion, without assuming that your code is part of an
-   * SNMP agent or client that wants a pile of definitions of PDU types,
-   * etc.?  Is it just that 99 44/100% of the code that uses an SNMP library
-   * *is* part of an agent or client, and really *does* need that stuff,
-   * and *doesn't* need the interfaces we want?
-   */
-#  undef SNMP_ERR_NOERROR
-#  undef SNMP_ERR_TOOBIG
-#  undef SNMP_ERR_NOSUCHNAME
-#  undef SNMP_ERR_BADVALUE
-#  undef SNMP_ERR_READONLY
-#  undef SNMP_ERR_NOACCESS
-#  undef SNMP_ERR_WRONGTYPE
-#  undef SNMP_ERR_WRONGLENGTH
-#  undef SNMP_ERR_WRONGENCODING
-#  undef SNMP_ERR_WRONGVALUE
-#  undef SNMP_ERR_NOCREATION
-#  undef SNMP_ERR_INCONSISTENTVALUE
-#  undef SNMP_ERR_RESOURCEUNAVAILABLE
-#  undef SNMP_ERR_COMMITFAILED
-#  undef SNMP_ERR_UNDOFAILED
-#  undef SNMP_ERR_AUTHORIZATIONERROR
-#  undef SNMP_ERR_NOTWRITABLE
-#  undef SNMP_ERR_INCONSISTENTNAME
-#  undef SNMP_TRAP_COLDSTART
-#  undef SNMP_TRAP_WARMSTART
-#  undef SNMP_TRAP_LINKDOWN
-#  undef SNMP_TRAP_LINKUP
-#  undef SNMP_TRAP_EGPNEIGHBORLOSS
-#  undef SNMP_TRAP_ENTERPRISESPECIFIC
-# endif
-#endif
+# define VALTYPE_INTEGER       ASN_INTEGER
+# define VALTYPE_COUNTER       ASN_COUNTER
+# define VALTYPE_GAUGE         ASN_GAUGE
+# define VALTYPE_TIMETICKS     ASN_TIMETICKS
+# define VALTYPE_STRING                ASN_OCTET_STR
+# define VALTYPE_IPADDR                ASN_IPADDRESS
+# define VALTYPE_OPAQUE                ASN_OPAQUE
+# define VALTYPE_NSAP          ASN_NSAP
+# define VALTYPE_OBJECTID      ASN_OBJECT_ID
+# define VALTYPE_BITSTR                ASN_BIT_STR
+# define VALTYPE_COUNTER64     ASN_COUNTER64
+
+#endif /* HAVE_SOME_SNMP */
 
 #include "asn1.h"
 
 #include "packet-snmp.h"
-
-/* Null string of type "guchar[]". */
-static const guchar nullstring[] = "";
+#include "format-oid.h"
 
 /* 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)
+   by turning null pointers into pointers to the above null string,
+   and, if the argument pointer wasn't null, make sure we handle
+   non-printable characters in the string by escaping them. */
+#define        SAFE_STRING(s, l)       (((s) != NULL) ? format_text((s), (l)) : "")
 
 static int proto_snmp = -1;
-static int proto_smux = -1;
+
+static gboolean display_oid = TRUE;
 
 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;
 
+static int hf_snmp_version = -1;
+static int hf_snmp_community = -1;
+static int hf_snmp_request_id = -1;
+static int hf_snmp_pdutype = -1;
+static int hf_snmp_agent = -1;
+static int hf_snmp_enterprise = -1;
+static int hf_snmp_error_status = -1;
+static int hf_snmp_oid = -1;
+static int hf_snmp_traptype = -1;
+static int hf_snmp_spectraptype = -1;
+static int hf_snmp_timestamp = -1;
 static int hf_snmpv3_flags = -1;
 static int hf_snmpv3_flags_auth = -1;
 static int hf_snmpv3_flags_crypt = -1;
 static int hf_snmpv3_flags_report = -1;
 
+static int proto_smux = -1;
+
+static gint ett_smux = -1;
+
+static int hf_smux_version = -1;
+static int hf_smux_pdutype = -1;
+
+/* desegmentation of SNMP-over-TCP */
+static gboolean snmp_desegment = TRUE;
+
+static dissector_handle_t snmp_handle;
+static dissector_handle_t data_handle;
+
 #define TH_AUTH   0x01
 #define TH_CRYPT  0x02
 #define TH_REPORT 0x04
 
-static const true_false_string flags_set_truth = {
-  "Set",
-  "Not set"
-};
-
 #define UDP_PORT_SNMP          161
 #define UDP_PORT_SNMP_TRAP     162
+#define TCP_PORT_SNMP          161
+#define TCP_PORT_SNMP_TRAP     162
 #define TCP_PORT_SMUX          199
 
 /* Protocol version numbers */
@@ -337,26 +265,63 @@ static const value_string smux_sout[] = {
 };
 
 /* Error status values */
+#ifndef SNMP_ERR_NOERROR
 #define SNMP_ERR_NOERROR               0
+#endif
+#ifndef SNMP_ERR_TOOBIG
 #define SNMP_ERR_TOOBIG                        1
+#endif
+#ifndef SNMP_ERR_NOSUCHNAME
 #define SNMP_ERR_NOSUCHNAME            2
+#endif
+#ifndef SNMP_ERR_BADVALUE
 #define SNMP_ERR_BADVALUE              3
+#endif
+#ifndef SNMP_ERR_READONLY
 #define SNMP_ERR_READONLY              4
-#define SNMP_ERR_GENERROR              5
-
+#endif
+#ifndef SNMP_ERR_GENERR
+#define SNMP_ERR_GENERR                        5
+#endif
+#ifndef SNMP_ERR_NOACCESS
 #define SNMP_ERR_NOACCESS              6
+#endif
+#ifndef SNMP_ERR_WRONGTYPE
 #define SNMP_ERR_WRONGTYPE             7
+#endif
+#ifndef SNMP_ERR_WRONGLENGTH
 #define SNMP_ERR_WRONGLENGTH           8
+#endif
+#ifndef SNMP_ERR_WRONGENCODING
 #define SNMP_ERR_WRONGENCODING         9
+#endif
+#ifndef SNMP_ERR_WRONGVALUE
 #define SNMP_ERR_WRONGVALUE            10
+#endif
+#ifndef SNMP_ERR_NOCREATION
 #define SNMP_ERR_NOCREATION            11
+#endif
+#ifndef SNMP_ERR_INCONSISTENTVALUE
 #define SNMP_ERR_INCONSISTENTVALUE     12
+#endif
+#ifndef SNMP_ERR_RESOURCEUNAVAILABLE
 #define SNMP_ERR_RESOURCEUNAVAILABLE   13
+#endif
+#ifndef SNMP_ERR_COMMITFAILED
 #define SNMP_ERR_COMMITFAILED          14
+#endif
+#ifndef SNMP_ERR_UNDOFAILED
 #define SNMP_ERR_UNDOFAILED            15
+#endif
+#ifndef SNMP_ERR_AUTHORIZATIONERROR
 #define SNMP_ERR_AUTHORIZATIONERROR    16
+#endif
+#ifndef SNMP_ERR_NOTWRITABLE
 #define SNMP_ERR_NOTWRITABLE           17
+#endif
+#ifndef SNMP_ERR_INCONSISTENTNAME
 #define SNMP_ERR_INCONSISTENTNAME      18
+#endif
 
 static const value_string error_statuses[] = {
        { SNMP_ERR_NOERROR,             "NO ERROR" },
@@ -364,7 +329,7 @@ static const value_string error_statuses[] = {
        { SNMP_ERR_NOSUCHNAME,          "NO SUCH NAME" },
        { SNMP_ERR_BADVALUE,            "BAD VALUE" },
        { SNMP_ERR_READONLY,            "READ ONLY" },
-       { SNMP_ERR_GENERROR,            "GENERIC ERROR" },
+       { SNMP_ERR_GENERR,              "GENERIC ERROR" },
        { SNMP_ERR_NOACCESS,            "NO ACCESS" },
        { SNMP_ERR_WRONGTYPE,           "WRONG TYPE" },
        { SNMP_ERR_WRONGLENGTH,         "WRONG LENGTH" },
@@ -383,13 +348,27 @@ static const value_string error_statuses[] = {
 
 /* General SNMP V1 Traps */
 
+#ifndef SNMP_TRAP_COLDSTART
 #define SNMP_TRAP_COLDSTART            0
+#endif
+#ifndef SNMP_TRAP_WARMSTART
 #define SNMP_TRAP_WARMSTART            1
+#endif
+#ifndef SNMP_TRAP_LINKDOWN
 #define SNMP_TRAP_LINKDOWN             2
+#endif
+#ifndef SNMP_TRAP_LINKUP
 #define SNMP_TRAP_LINKUP               3
+#endif
+#ifndef SNMP_TRAP_AUTHFAIL
 #define SNMP_TRAP_AUTHFAIL             4
+#endif
+#ifndef SNMP_TRAP_EGPNEIGHBORLOSS
 #define SNMP_TRAP_EGPNEIGHBORLOSS      5
+#endif
+#ifndef SNMP_TRAP_ENTERPRISESPECIFIC
 #define SNMP_TRAP_ENTERPRISESPECIFIC   6
+#endif
 
 static const value_string trap_types[] = {
        { SNMP_TRAP_COLDSTART,          "COLD START" },
@@ -519,68 +498,71 @@ 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) {
-
-               case ASN1_ERR_EMPTY:
-                       errstr = "Ran out of data";
-                       break;
-
-               case ASN1_ERR_EOC_MISMATCH:
-                       errstr = "EOC mismatch";
-                       break;
-
-               case ASN1_ERR_WRONG_TYPE:
-                       errstr = "Wrong type for that item";
-                       break;
+       char *errstr;
 
-               case ASN1_ERR_LENGTH_NOT_DEFINITE:
-                       errstr = "Length was indefinite";
-                       break;
+       errstr = asn1_err_to_str(ret);
 
-               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;
-
-               default:
-                       errstr = "Unknown error";
-                       break;
-               }
-               col_add_fstr(fd, COL_INFO,
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_add_fstr(pinfo->cinfo, COL_INFO,
                    "ERROR: Couldn't parse %s: %s", field_name, errstr);
        }
-
-       old_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);
+               call_dissector(data_handle,
+                   tvb_new_subset(tvb, offset, -1, -1), 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->cinfo, COL_INFO))
+               col_add_str(pinfo->cinfo, COL_INFO, message);
 
-       old_dissect_data(pd, offset, fd, tree);
+       if (tree != NULL) {
+               proto_tree_add_text(tree, tvb, offset, 0, "%s", message);
+               call_dissector(data_handle,
+                   tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
+       }
 }
 
-static gchar *
+gchar *
 format_oid(subid_t *oid, guint oid_length)
 {
        char *result;
        int result_len;
-       int len, i;
+       int len;
+       unsigned int i;
        char *buf;
+#ifdef HAVE_SOME_SNMP
+       guchar *oid_string;
+       size_t oid_string_len;
+       size_t oid_out_len;
+#endif
 
        result_len = oid_length * 22;
+
+#ifdef HAVE_SOME_SNMP
+       /*
+        * Get the decoded form of the OID, and add its length to the
+        * length of the result string.
+        *
+        * XXX - check for "sprint_realloc_objid()" failure.
+        */
+       oid_string_len = 256;
+       oid_string = g_malloc(oid_string_len);
+       *oid_string = '\0';
+       oid_out_len = 0;
+       sprint_realloc_objid(&oid_string, &oid_string_len, &oid_out_len, 1,
+           oid, oid_length);
+       result_len += strlen(oid_string) + 3;
+#endif
+
        result = g_malloc(result_len + 1);
        buf = result;
        len = sprintf(buf, "%lu", (unsigned long)oid[0]);
@@ -589,50 +571,102 @@ format_oid(subid_t *oid, guint oid_length)
                len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
                buf += len;
        }
+
+#ifdef HAVE_SOME_SNMP
+       /*
+        * Append the decoded form of the OID.
+        */
+       sprintf(buf, " (%s)", oid_string);
+       g_free(oid_string);
+#endif
+
        return result;
 }
 
-#ifdef HAVE_SPRINT_VALUE
-static gchar *
+/* returns the decoded (can be NULL) and non_decoded OID strings,
+   returned pointers shall be freed by the caller */
+void 
+new_format_oid(subid_t *oid, guint oid_length, 
+              gchar **non_decoded, gchar **decoded)
+{
+       int len;
+       unsigned int i;
+       char *buf;
+
+#ifdef HAVE_SOME_SNMP
+       guchar *oid_string;
+       size_t oid_string_len;
+       size_t oid_out_len;
+
+       /*
+        * Get the decoded form of the OID, and add its length to the
+        * length of the result string.
+        */
+
+       oid_string_len = 256;
+       oid_string = g_malloc(oid_string_len);
+       *oid_string = '\0';
+       oid_out_len = 0;
+       sprint_realloc_objid(&oid_string, &oid_string_len, &oid_out_len, 1,
+                            oid, oid_length);
+       *decoded = oid_string;
+#else
+       *decoded = NULL;
+#endif
+
+       *non_decoded = g_malloc(oid_length * 22 + 1);
+       buf = *non_decoded;
+       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;
+       }
+}
+
+#ifdef HAVE_SOME_SNMP
+static guchar *
+check_var_length(guint vb_length, guint required_length)
+{
+       guchar *buf;
+       static const char badlen_fmt[] = "Length is %u, should be %u";
+
+       if (vb_length != required_length) {
+               /* Enough room for the largest "Length is XXX,
+                  should be XXX" message - 10 digits for each
+                  XXX. */
+               buf = g_malloc(sizeof badlen_fmt + 10 + 10);
+               sprintf(buf, badlen_fmt, vb_length, required_length);
+               return buf;
+       }
+       return NULL;    /* length is OK */
+}
+
+static guchar *
 format_var(struct variable_list *variable, subid_t *variable_oid,
-    guint variable_oid_length, gushort vb_type, guint vb_length)
+    guint variable_oid_length, gushort vb_type, guint val_len)
 {
-       gchar *buf;
+       guchar *buf;
+       size_t buf_len;
+       size_t out_len;
 
        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);
+               /* Length has to be 4 bytes. */
+               buf = check_var_length(val_len, 4);
+               if (buf != NULL)
+                       return buf;     /* it's not 4 bytes */
                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);
+       case SNMP_COUNTER64:
+               /* Length has to be 8 bytes. */
+               buf = check_var_length(val_len, 8);
+               if (buf != NULL)
+                       return buf;     /* it's not 8 bytes */
                break;
 
        default:
-               /* Should not happen. */
-               g_assert_not_reached();
-               buf = NULL;
                break;
        }
 
@@ -675,7 +709,6 @@ format_var(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:
@@ -686,18 +719,36 @@ format_var(struct variable_list *variable, subid_t *variable_oid,
                variable->type = VALTYPE_COUNTER64;
                break;
        }
-       variable->val_len = vb_length;
+       variable->val_len = val_len;
 
-       sprint_value(buf, variable_oid, variable_oid_length, variable);
+       /*
+        * XXX - check for "sprint_realloc_objid()" failure.
+        */
+       buf_len = 256;
+       buf = g_malloc(buf_len);
+       *buf = '\0';
+       out_len = 0;
+       sprint_realloc_value(&buf, &buf_len, &out_len, 1,  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)
+snmp_variable_decode(proto_tree *snmp_tree,
+    subid_t *variable_oid
+#ifndef HAVE_SOME_SNMP
+       _U_
+#endif
+    ,
+    guint variable_oid_length
+#ifndef HAVE_SOME_SNMP
+       _U_
+#endif
+    ,
+    ASN1_SCK *asn1, int offset, guint *lengthp)
 {
-       const guchar *start;
+       int start;
        guint length;
        gboolean def;
        guint vb_length;
@@ -716,19 +767,17 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
 
        gchar *vb_display_string;
 
-#ifdef HAVE_SPRINT_VALUE
+#ifdef HAVE_SOME_SNMP
        struct variable_list variable;
-#if defined(HAVE_UCD_SNMP_SNMP_H)
        long value;
-#endif
-#else  /* HAVE_SPRINT_VALUE */
-       int i;
+#else /* HAVE_SOME_SNMP */
+       unsigned int i;
        gchar *buf;
        int len;
-#endif /* HAVE_SPRINT_VALUE */
+#endif /* HAVE_SOME_SNMP */
 
        /* 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;
@@ -754,26 +803,24 @@ 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 defined(HAVE_UCD_SNMP_SNMP_H)
+#ifdef HAVE_SOME_SNMP
                        value = vb_integer_value;
                        variable.val.integer = &value;
-#elif defined(HAVE_SNMP_SNMP_H)
-                       variable.val.integer = &vb_integer_value;
-#endif
                        vb_display_string = format_var(&variable,
                            variable_oid, variable_oid_length, vb_type,
                            vb_length);
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                           length,
                            "Value: %s", vb_display_string);
                        g_free(vb_display_string);
-#else
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+#else /* HAVE_SOME_SNMP */
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                           length,
                            "Value: %s: %d (%#x)", vb_type_name,
                            vb_integer_value, vb_integer_value);
-#endif
+#endif /* HAVE_SOME_SNMP */
                }
                break;
 
@@ -784,26 +831,24 @@ 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 defined(HAVE_UCD_SNMP_SNMP_H)
+#ifdef HAVE_SOME_SNMP
                        value = vb_uinteger_value;
                        variable.val.integer = &value;
-#elif defined(HAVE_SNMP_SNMP_H)
-                       variable.val.integer = &vb_uinteger_value;
-#endif
                        vb_display_string = format_var(&variable,
                            variable_oid, variable_oid_length, vb_type,
                            vb_length);
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                           length,
                            "Value: %s", vb_display_string);
                        g_free(vb_display_string);
-#else
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+#else /* HAVE_SOME_SNMP */
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                           length,
                            "Value: %s: %u (%#x)", vb_type_name,
                            vb_uinteger_value, vb_uinteger_value);
-#endif
+#endif /* HAVE_SOME_SNMP */
                }
                break;
 
@@ -817,17 +862,18 @@ snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
                    &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
+#ifdef HAVE_SOME_SNMP
                        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, NullTVB, offset, length,
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                           length,
                            "Value: %s", vb_display_string);
                        g_free(vb_display_string);
-#else
+#else /* HAVE_SOME_SNMP */
                        /*
                         * If some characters are not printable, display
                         * the string as bytes.
@@ -852,16 +898,18 @@ 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,
-                                   "Value: %s: %.*s", vb_type_name,
-                                   (int)vb_length, vb_octet_string);
+                               proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                                   length,
+                                   "Value: %s: %s", vb_type_name,
+                                   SAFE_STRING(vb_octet_string, vb_length));
                        }
-#endif
+#endif /* HAVE_SOME_SNMP */
                }
                g_free(vb_octet_string);
                break;
@@ -870,9 +918,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;
@@ -882,45 +930,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
+#ifdef HAVE_SOME_SNMP
                        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, NullTVB, offset, length,
+                           vb_oid_length * sizeof (subid_t));
+                       proto_tree_add_text(snmp_tree, asn1->tvb, offset,
+                           length,
                            "Value: %s", vb_display_string);
-#else
+                       g_free(vb_display_string);
+#else /* HAVE_SOME_SNMP */
                        vb_display_string = format_oid(vb_oid, vb_oid_length);
-                       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);
-#endif
                        g_free(vb_display_string);
+#endif /* HAVE_SOME_SNMP */
                }
                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;
@@ -934,8 +985,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;
@@ -952,6 +1003,8 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
        subid_t *enterprise;
        guint enterprise_length;
 
+       guint32 agent_ipaddr;
+
        guint8 *agent_address;
        guint agent_address_length;
 
@@ -970,21 +1023,18 @@ dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
        guint variable_length;
        subid_t *variable_oid;
        guint variable_oid_length;
-#if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
-       gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
-#endif
 
        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->cinfo, COL_INFO))
+               col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
+       length = asn1.offset - start;
        if (tree) {
-               proto_tree_add_text(tree, NullTVB, offset, length,
-                   "PDU type: %s", pdu_type_string);
+               proto_tree_add_uint(tree, hf_snmp_pdutype, tvb, offset, length,
+                   pdu_type);
        }
        offset += length;
 
@@ -1002,20 +1052,20 @@ 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,
-                           "Request Id: %#x", request_id);
+                       proto_tree_add_uint(tree, hf_snmp_request_id,
+                               tvb, offset, length, request_id);
                }
                offset += length;
-               
+
                /* 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);
@@ -1023,13 +1073,13 @@ 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,
-                                   length, "Error Status: %s",
-                                   val_to_str(error_status, error_statuses,
-                                     "Unknown (%d)"));
+                               proto_tree_add_uint(tree, 
+                                                   hf_snmp_error_status,
+                                                   tvb, offset,
+                                                   length, error_status);
                        }
                }
                offset += length;
@@ -1037,7 +1087,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);
@@ -1045,10 +1095,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);
                        }
                }
@@ -1060,25 +1110,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) {
                        oid_string = format_oid(enterprise, enterprise_length);
-                       proto_tree_add_text(tree, NullTVB, offset, length,
-                           "Enterprise: %s", oid_string);
+                       proto_tree_add_string(tree, hf_snmp_enterprise, tvb,
+                           offset, length, 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;
                }
@@ -1086,85 +1136,92 @@ 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_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, 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 {
+                               memcpy((guint8 *)&agent_ipaddr, agent_address,
+                                   agent_address_length);
+                               proto_tree_add_ipv4(tree, hf_snmp_agent, tvb,
+                                   offset, length, agent_ipaddr);
+                       }
                }
                g_free(agent_address);
                offset += length;
-               
+
                /* 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,
-                           "Trap type: %s",
-                           val_to_str(trap_type, trap_types, "Unknown (%u)"));
-               }               
+                       proto_tree_add_uint(tree, hf_snmp_traptype, tvb,
+                           offset, length, trap_type);
+               }
                offset += length;
-               
+
                /* 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,
-                           "Specific trap type: %u (%#x)",
-                           specific_type, specific_type);
-               }               
+                       proto_tree_add_uint(tree, hf_snmp_spectraptype, tvb,
+                           offset, length, 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,
-                           "Timestamp: %u", timestamp);
-               }               
+                       proto_tree_add_uint(tree, hf_snmp_timestamp, tvb,
+                           offset, length, timestamp);
+               }
                offset += length;
                break;
        }
@@ -1173,7 +1230,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;
        }
@@ -1188,7 +1245,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;
                }
@@ -1198,38 +1255,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;
 
-               if (tree) {
-                       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,
-                           "Object identifier %d: %s (%s)", vb_index,
-                           oid_string, vb_oid_string);
-#else
-                       
-                       proto_tree_add_text(tree, NullTVB, offset, sequence_length,
-                           "Object identifier %d: %s", vb_index,
-                           oid_string);
-#endif
-                       g_free(oid_string);
+               if (display_oid || tree) {
+
+                 gchar *decoded_oid;
+                 gchar *non_decoded_oid;
+
+                 new_format_oid(variable_oid, variable_oid_length,
+                                &non_decoded_oid, &decoded_oid);
+                 
+                 if (display_oid && check_col(pinfo->cinfo, COL_INFO)) {
+                   col_append_fstr(pinfo->cinfo, COL_INFO, 
+                                   " %s", 
+                                   (decoded_oid == NULL) ? non_decoded_oid :
+                                   decoded_oid);
+                 }
+                 
+                 if (tree) {
+                   if (decoded_oid) {
+                     proto_tree_add_string_format(tree, hf_snmp_oid,
+                                                  tvb, offset, 
+                                                  sequence_length, 
+                                                  decoded_oid,
+                                                  "Object identifier %d: %s (%s)", 
+                                                  vb_index, 
+                                                  non_decoded_oid,
+                                                  decoded_oid);
+                     /* add also the non decoded oid string */
+                     proto_tree_add_string_hidden(tree, hf_snmp_oid,
+                                                  tvb, offset, 
+                                                  sequence_length,
+                                                  non_decoded_oid);
+                   } else {
+                     proto_tree_add_string_format(tree, hf_snmp_oid,
+                                                  tvb, offset, 
+                                                  sequence_length, 
+                                                  non_decoded_oid,
+                                                  "Object identifier %d: %s", 
+                                                  vb_index, 
+                                                  non_decoded_oid);
+                   }
+                 }
+                 
+                 if (decoded_oid) g_free(decoded_oid);
+                 g_free(non_decoded_oid);
+
                }
+
                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);
                if (ret != ASN1_ERR_NOERROR) {
-                       dissect_snmp_parse_error(pd, offset, fd, tree,
+                       dissect_snmp_parse_error(tvb, offset, pinfo, tree,
                            "variable", ret);
                        return;
                }
@@ -1247,7 +1332,7 @@ static const value_string qos_vals[] = {
 };
 
 static void
-dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
+dissect_snmp2u_parameters(proto_tree *tree, tvbuff_t *tvb, int offset, int length,
     guchar *parameters, int parameters_length)
 {
        proto_item *item;
@@ -1257,7 +1342,7 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
        guint8 qos;
        guint8 len;
 
-       item = proto_tree_add_text(tree, NullTVB, offset, length,
+       item = proto_tree_add_text(tree, tvb, offset, length,
            "Parameters");
        parameters_tree = proto_item_add_subtree(item, ett_parameters);
        offset += length - parameters_length;
@@ -1265,15 +1350,14 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
        if (parameters_length < 1)
                return;
        model = *parameters;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
+       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, NullTVB, offset,
-                   parameters_length, "parameters: %s",
+               proto_tree_add_text(parameters_tree, tvb, offset,                   parameters_length, "parameters: %s",
                    bytes_to_str(parameters, parameters_length));
                return;
        }
@@ -1281,14 +1365,14 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
        if (parameters_length < 1)
                return;
        qos = *parameters;
-       item = proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
+       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, NullTVB, offset, 1, "%s",
+       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, NullTVB, offset, 1, "%s",
+       proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
            decode_enumerated_bitfield(qos, 0x03,
                8, qos_vals, "%s"));
        offset += 1;
@@ -1297,7 +1381,7 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
 
        if (parameters_length < 12)
                return;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, 12,
+       proto_tree_add_text(parameters_tree, tvb, offset, 12,
            "agentID: %s", bytes_to_str(parameters, 12));
        offset += 12;
        parameters += 12;
@@ -1305,7 +1389,7 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
 
        if (parameters_length < 4)
                return;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, 4,
+       proto_tree_add_text(parameters_tree, tvb, offset, 4,
            "agentBoots: %u", pntohl(parameters));
        offset += 4;
        parameters += 4;
@@ -1313,7 +1397,7 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
 
        if (parameters_length < 4)
                return;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, 4,
+       proto_tree_add_text(parameters_tree, tvb, offset, 4,
            "agentTime: %u", pntohl(parameters));
        offset += 4;
        parameters += 4;
@@ -1321,7 +1405,7 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
 
        if (parameters_length < 2)
                return;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, 2,
+       proto_tree_add_text(parameters_tree, tvb, offset, 2,
            "maxSize: %u", pntohs(parameters));
        offset += 2;
        parameters += 2;
@@ -1330,7 +1414,7 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
        if (parameters_length < 1)
                return;
        len = *parameters;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
+       proto_tree_add_text(parameters_tree, tvb, offset, 1,
            "userLen: %u", len);
        offset += 1;
        parameters += 1;
@@ -1338,7 +1422,7 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
 
        if (parameters_length < len)
                return;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, len,
+       proto_tree_add_text(parameters_tree, tvb, offset, len,
            "userName: %.*s", len, parameters);
        offset += len;
        parameters += len;
@@ -1347,7 +1431,7 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
        if (parameters_length < 1)
                return;
        len = *parameters;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
+       proto_tree_add_text(parameters_tree, tvb, offset, 1,
            "authLen: %u", len);
        offset += 1;
        parameters += 1;
@@ -1355,7 +1439,7 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
 
        if (parameters_length < len)
                return;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, len,
+       proto_tree_add_text(parameters_tree, tvb, offset, len,
            "authDigest: %s", bytes_to_str(parameters, len));
        offset += len;
        parameters += len;
@@ -1363,16 +1447,17 @@ dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
 
        if (parameters_length < 1)
                return;
-       proto_tree_add_text(parameters_tree, NullTVB, offset, parameters_length,
+       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,
-    proto_tree *tree, char *proto_name, int proto, gint ett)
+guint
+dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, int proto, gint ett, gboolean is_tcp)
 {
+       guint length_remaining;
        ASN1_SCK asn1;
-       const guchar *start;
+       int start;
        gboolean def;
        gboolean encrypted;
        guint length;
@@ -1387,6 +1472,7 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
        guint32 enginetime;
 
        guchar *msgflags;
+       guchar *commustr;
        guchar *community;
        guchar *secparm;
        guchar *cengineid;
@@ -1418,39 +1504,142 @@ 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 (tree) {
-               item = proto_tree_add_item(tree, proto, NullTVB, offset,
-                   END_OF_FRAME, FALSE);
-               snmp_tree = proto_item_add_subtree(item, ett);
-       }
+       /*
+        * This will throw an exception if we don't have any data left.
+        * That's what we want.  (See "tcp_dissect_pdus()", which is
+        * similar, but doesn't have to deal with ASN.1.
+        * XXX - can we make "tcp_dissect_pdus()" provide enough
+        * information to the "get_pdu_len" routine so that we could
+        * have that routine deal with ASN.1, and just use
+        * "tcp_dissect_pdus()"?)
+        */
+       length_remaining = tvb_ensure_length_remaining(tvb, offset);
 
        /* NOTE: we have to parse the message piece by piece, since the
         * capture length may be less than the message length: a 'global'
         * parsing is likely to fail.
         */
-       /* parse the SNMP header */
-       asn1_open(&asn1, &pd[offset], END_OF_FRAME);
+
+       /*
+        * If this is SNMP-over-TCP, we might have to do reassembly
+        * in order to read the "Sequence Of" header.
+        */
+       if (is_tcp && snmp_desegment && pinfo->can_desegment) {
+               /*
+                * This is TCP, and we should, and can, do reassembly.
+                *
+                * Is the "Sequence Of" header split across segment
+                * boundaries?  We requre at least 6 bytes for the
+                * header, which allows for a 4-byte length (ASN.1
+                * BER).
+                */
+               if (length_remaining < 6) {
+                       pinfo->desegment_offset = offset;
+                       pinfo->desegment_len = 6 - length_remaining;
+
+                       /*
+                        * Return 0, which means "I didn't dissect anything
+                        * because I don't have enough data - we need
+                        * to desegment".
+                        */
+                       return 0;
+               }
+       }
+
+       /*
+        * OK, try to read the "Sequence Of" header; this gets the total
+        * length of the SNMP message.
+        */
+       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,
+               if (tree) {
+                       item = proto_tree_add_item(tree, proto, tvb, offset,
+                           -1, FALSE);
+                       snmp_tree = proto_item_add_subtree(item, ett);
+               }
+               dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
                        "message header", ret);
-               return;
+
+               /*
+                * Return the length remaining in the tvbuff, so
+                * if this is SNMP-over-TCP, our caller thinks there's
+                * nothing left to dissect.
+                */
+               return length_remaining;
+       }
+
+       /*
+        * Add the length of the "Sequence Of" header to the message
+        * length.
+        */
+       message_length += length;
+       if (message_length < length) {
+               /*
+                * The message length was probably so large that the
+                * total length overflowed.
+                *
+                * Report this as an error.
+                */
+               show_reported_bounds_error(tvb, pinfo, tree);
+
+               /*
+                * Return the length remaining in the tvbuff, so
+                * if this is SNMP-over-TCP, our caller thinks there's
+                * nothing left to dissect.
+                */
+               return length_remaining;
+       }
+
+       /*
+        * If this is SNMP-over-TCP, we might have to do reassembly
+        * to get all of this message.
+        */
+       if (is_tcp && snmp_desegment && pinfo->can_desegment) {
+               /*
+                * Yes - is the message split across segment boundaries?
+                */
+               if (length_remaining < message_length) {
+                       /*
+                        * Yes.  Tell the TCP dissector where the data
+                        * for this message starts in the data it handed
+                        * us, and how many more bytes we need, and
+                        * return.
+                        */
+                       pinfo->desegment_offset = offset;
+                       pinfo->desegment_len =
+                           message_length - length_remaining;
+
+                       /*
+                        * Return 0, which means "I didn't dissect anything
+                        * because I don't have enough data - we need
+                        * to desegment".
+                        */
+                       return 0;
+               }
+       }
+
+       if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
+               col_set_str(pinfo->cinfo, COL_PROTOCOL,
+                   proto_get_protocol_short_name(proto));
+       }
+
+       if (tree) {
+               item = proto_tree_add_item(tree, proto, tvb, offset,
+                   message_length, FALSE);
+               snmp_tree = proto_item_add_subtree(item, ett);
        }
        offset += length;
 
        ret = asn1_uint32_decode (&asn1, &version, &length);
        if (ret != ASN1_ERR_NOERROR) {
-               dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
-                   ret);
-               return;
+               dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
+                   "version number", ret);
+               return message_length;
        }
        if (snmp_tree) {
-               proto_tree_add_text(snmp_tree, NullTVB, offset, length,
-                   "Version: %s",
-                   val_to_str(version, versions, "Unknown version %#x"));
+               proto_tree_add_uint(snmp_tree, hf_snmp_version, tvb, offset,
+                   length, version);
        }
        offset += length;
 
@@ -1458,26 +1647,30 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
        switch (version) {
        case SNMP_VERSION_1:
        case SNMP_VERSION_2c:
-               ret = asn1_octet_string_decode (&asn1, &community, 
+               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;
+                       return message_length;
                }
                if (tree) {
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
-                           "Community: %.*s", community_length,
-                           SAFE_STRING(community));
+                       commustr = g_malloc(community_length+1);
+                       memcpy(commustr, community, community_length);
+                       commustr[community_length] = '\0';
+
+                       proto_tree_add_string(snmp_tree, hf_snmp_community,
+                           tvb, offset, length, commustr);
+                       g_free(commustr);
                }
                g_free(community);
                offset += length;
                break;
        case SNMP_VERSION_2u:
-               ret = asn1_octet_string_decode (&asn1, &community, 
+               ret = asn1_octet_string_decode (&asn1, &community,
                    &community_length, &length);
                if (tree) {
-                       dissect_snmp2u_parameters(snmp_tree, offset, length,
+                       dissect_snmp2u_parameters(snmp_tree, tvb, offset, length,
                            community, community_length);
                }
                g_free(community);
@@ -1486,77 +1679,77 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
        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;
+                       return message_length;
                }
                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;
+                       return message_length;
                }
                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;
+                       return message_length;
                }
                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, 
+               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;
+                       return message_length;
                }
                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;
+                       return message_length;
                }
                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_boolean(flags_tree, hf_snmpv3_flags_report,
-                           NullTVB, offset, length, msgflags[0]);
+                           tvb, offset, length, msgflags[0]);
                        proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
-                           NullTVB, offset, length, msgflags[0]);
+                           tvb, offset, length, msgflags[0]);
                        proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
-                           NullTVB, offset, length, msgflags[0]);
+                           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;
+                       return message_length;
                }
                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"));
@@ -1564,25 +1757,25 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                offset += length;
                switch(msgsec) {
                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;
-                       if (cls != ASN1_UNI && con != ASN1_PRI && 
+                       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;
+                               return message_length;
                        }
                        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,
-                                   length, 
+                               proto_tree_add_text(secur_tree, tvb, offset,
+                                   length,
                                    "Message Security Parameters Length: %d",
                                    secparm_length);
                        }
@@ -1590,20 +1783,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);
-                               return;
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "USM sequence header", ret);
+                               return message_length;
                        }
                        offset += length;
-                       ret = asn1_octet_string_decode (&asn1, &aengineid, 
+                       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);
-                               return;
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "authoritative engine id", ret);
+                               return message_length;
                        }
                        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));
                        }
@@ -1611,66 +1804,65 @@ 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);
-                               return;
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "engine boots", ret);
+                               return message_length;
                        }
                        if (secur_tree) {
-                               proto_tree_add_text(secur_tree, NullTVB,
-                                   offset, length, "Engine Boots: %d", 
+                               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);
-                               return;
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree,  "engine time", ret);
+                               return message_length;
                        }
                        if (secur_tree) {
-                               proto_tree_add_text(secur_tree, NullTVB,
-                                   offset, length, "Engine Time: %d", 
+                               proto_tree_add_text(secur_tree, tvb,
+                                   offset, length, "Engine Time: %d",
                                    enginetime);
                        }
                        offset += length;
-                       ret = asn1_octet_string_decode (&asn1, &username, 
+                       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);
-                               return;
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "user name", ret);
+                               return message_length;
                        }
                        if (secur_tree) {
-                               proto_tree_add_text(secur_tree, NullTVB, offset,
-                                   length, "User Name: %.*s", 
-                                   username_length,
-                                   SAFE_STRING(username));
+                               proto_tree_add_text(secur_tree, tvb, offset,
+                                   length, "User Name: %s",
+                                   SAFE_STRING(username, username_length));
                        }
                        g_free(username);
                        offset += length;
-                       ret = asn1_octet_string_decode (&asn1, &authpar, 
+                       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);
-                               return;
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "authentication parameter", ret);
+                               return message_length;
                        }
                        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));
                        }
                        g_free(authpar);
                        offset += length;
-                       ret = asn1_octet_string_decode (&asn1, &privpar, 
+                       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);
-                               return;
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "privacy parameter", ret);
+                               return message_length;
                        }
                        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));
                        }
@@ -1678,15 +1870,16 @@ dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
                        offset += length;
                        break;
                default:
-                       ret = asn1_octet_string_decode (&asn1, 
+                       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;
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "Message Security Parameters",
+                                   ret);
+                               return message_length;
                        }
                        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);
@@ -1700,81 +1893,82 @@ 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);
-                               return;
+                               dissect_snmp_parse_error(tvb, offset, pinfo,
+                                   snmp_tree, "encrypted PDU header", ret);
+                               return message_length;
                        }
-                       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_set_str(fd, COL_INFO, "Encrypted PDU");
-                       return;
+                       if (check_col(pinfo->cinfo, COL_INFO))
+                               col_set_str(pinfo->cinfo, COL_INFO, "Encrypted PDU");
+                       return message_length;
                }
                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;
+                       return message_length;
                }
                offset += length;
-               ret = asn1_octet_string_decode (&asn1, &cengineid, 
+               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;
+                       return message_length;
                }
                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));
                }
                g_free(cengineid);
                offset += length;
-               ret = asn1_octet_string_decode (&asn1, &cname, 
+               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;
+                       return message_length;
                }
                if (snmp_tree) {
-                       proto_tree_add_text(snmp_tree, NullTVB, offset, length,
-                           "Context Name: %.*s", cname_length,
-                           SAFE_STRING(cname));
+                       proto_tree_add_text(snmp_tree, tvb, offset, length,
+                           "Context Name: %s",
+                           SAFE_STRING(cname, cname_length));
                }
                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;
+               return message_length;
        }
 
-       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;
+               return message_length;
        }
        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;
+               return message_length;
        }
-       dissect_common_pdu(pd, offset, fd, snmp_tree, asn1, pdu_type, start);
+       dissect_common_pdu(tvb, offset, pinfo, snmp_tree, asn1, pdu_type, start);
+       return message_length;
 }
 
 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;
 
@@ -1804,12 +1998,11 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
        int ret;
        guint cls, con;
 
-       if (check_col(fd, COL_PROTOCOL))
-               col_set_str(fd, COL_PROTOCOL, "SMUX");
+       if (check_col(pinfo->cinfo, COL_PROTOCOL))
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMUX");
 
        if (tree) {
-               item = proto_tree_add_item(tree, proto, NullTVB, offset,
-                   END_OF_FRAME, FALSE);
+               item = proto_tree_add_item(tree, proto, tvb, offset, -1, FALSE);
                smux_tree = proto_item_add_subtree(item, ett);
        }
 
@@ -1818,12 +2011,12 @@ 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;
        }
@@ -1832,67 +2025,67 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
        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->cinfo, COL_INFO))
+                       col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
-                           "PDU type: %s", pdu_type_string);
+                       proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+                           offset, length, pdu_type);
                }
                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,
-                           "Version: %d", version);
+                       proto_tree_add_uint(smux_tree, hf_smux_version, tvb,
+                           offset, length, 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) {
                        oid_string = format_oid(regid, regid_length);
-                       proto_tree_add_text(smux_tree, NullTVB, offset, 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_octet_string_decode (&asn1, &application, 
+               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,
-                           "Application: %.*s", application_length,
-                            SAFE_STRING(application));
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
+                           "Application: %s",
+                            SAFE_STRING(application, application_length));
                }
                g_free(application);
                offset += length;
 
-               ret = asn1_octet_string_decode (&asn1, &password, 
+               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,
-                           SAFE_STRING(password));
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
+                           "Password: %s",
+                           SAFE_STRING(password, password_length));
                }
                g_free(password);
                offset += length;
@@ -1901,24 +2094,24 @@ 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->cinfo, COL_INFO))
+                       col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
-                           "PDU type: %s", pdu_type_string);
+                       proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+                           offset, length, pdu_type);
                }
                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, 
+                           val_to_str(cause, smux_close,
                                "Unknown cause %#x"));
                }
                offset += pdu_length;
@@ -1927,23 +2120,23 @@ 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->cinfo, COL_INFO))
+                       col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
-                           "PDU type: %s", pdu_type_string);
+                       proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+                           offset, length, pdu_type);
                }
                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) {
                        oid_string = format_oid(regid, regid_length);
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
                            "Registration: %s", oid_string);
                        g_free(oid_string);
                }
@@ -1952,26 +2145,26 @@ dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
 
                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,
-                           "Operation: %s", 
-                           val_to_str(operation, smux_rreq, 
+                       proto_tree_add_text(smux_tree, tvb, offset, length,
+                           "Operation: %s",
+                           val_to_str(operation, smux_rreq,
                                "Unknown operation %#x"));
                }
                offset += length;
@@ -1980,24 +2173,24 @@ 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->cinfo, COL_INFO))
+                       col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
-                           "PDU type: %s", pdu_type_string);
+                       proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+                           offset, length, pdu_type);
                }
                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, 
+                           val_to_str(priority, smux_prio,
                                "Priority: %#x"));
                }
                offset += pdu_length;
@@ -2006,44 +2199,42 @@ 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->cinfo, COL_INFO))
+                       col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
+               length = asn1.offset - start;
                if (tree) {
-                       proto_tree_add_text(smux_tree, NullTVB, offset, length,
-                           "PDU type: %s", pdu_type_string);
+                       proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+                           offset, length, pdu_type);
                }
                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, 
+                           val_to_str(commit, smux_sout,
                                "Unknown SOUT Value: %#x"));
                }
                offset += pdu_length;
                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)
 {
        conversation_t  *conversation;
 
-       OLD_CHECK_DISPLAY_AS_DATA(proto_snmp, pd, offset, fd, tree);
-
        /*
         * The first SNMP packet goes to the SNMP port; the second one
         * may come from some *other* port, but goes back to the same
@@ -2052,200 +2243,217 @@ dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
         * IP addresses and ports.
         *
         * If this packet went to the SNMP port, we check to see if
-        * there's already a conversation with the source IP address
-        * and port of this packet, the destination IP address of this
-        * packet, and any destination UDP port.  If not, we create
-        * one, with a wildcard UDP port, and give it the SNMP dissector
-        * as a dissector.
+        * 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 (pi.destport == UDP_PORT_SNMP) {
-         conversation = find_conversation(&pi.src, &pi.dst, PT_UDP,
-                                          pi.srcport, 0, NO_DST_PORT);
+       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(&pi.src, &pi.dst, PT_UDP,
-                                           pi.srcport, 0, NULL,
-                                           NO_DST_PORT);
-           old_conversation_set_dissector(conversation, dissect_snmp);
+           conversation = conversation_new(&pinfo->src, &pinfo->dst, PT_UDP,
+                                           pinfo->srcport, 0, NO_PORT2);
+           conversation_set_dissector(conversation, snmp_handle);
          }
        }
 
-       dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
+       dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, FALSE);
 }
 
 static void
-dissect_smux(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
+dissect_snmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       OLD_CHECK_DISPLAY_AS_DATA(proto_smux, pd, offset, fd, tree);
-       dissect_smux_pdu(pd, offset, fd, tree, proto_smux, ett_smux);
+       int offset = 0;
+       guint message_len;
+
+       while (tvb_reported_length_remaining(tvb, offset) > 0) {
+               message_len = dissect_snmp_pdu(tvb, 0, pinfo, tree,
+                   proto_snmp, ett_snmp, TRUE);
+               if (message_len == 0) {
+                       /*
+                        * We don't have all the data for that message,
+                        * so we need to do desegmentation;
+                        * "dissect_snmp_pdu()" has set that up.
+                        */
+                       break;
+               }
+               offset += message_len;
+       }
+}
+
+static void
+dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_smux_pdu(tvb, 0, pinfo, tree, proto_smux, ett_smux);
 }
 
 void
 proto_register_snmp(void)
 {
-#ifdef linux
-       void *libsnmp_handle;
-       int (*snmp_set_suffix_only_p)(int);
-       int (*ds_set_int_p)(int, int, int);
+#if defined(WIN32) && defined(HAVE_SOME_SNMP)
+       char *mib_path;
+#define MIB_PATH_APPEND "snmp\\mibs"
 #endif
 
-        static hf_register_info hf[] = {
+       static hf_register_info hf[] = {
+               { &hf_snmp_version,
+               { "Version", "snmp.version", FT_UINT8, BASE_DEC, VALS(versions),
+                   0x0, "", HFILL }},
+               { &hf_snmp_community,
+               { "Community", "snmp.community", FT_STRING, BASE_NONE, NULL,
+                   0x0, "", HFILL }},
+               { &hf_snmp_request_id,
+               { "Request Id", "snmp.id", FT_UINT32, BASE_HEX, NULL,
+                   0x0, "Id for this transaction", HFILL }},
+               { &hf_snmp_pdutype,
+               { "PDU type", "snmp.pdutype", FT_UINT8, BASE_DEC, VALS(pdu_types),
+                   0x0, "", HFILL }},
+               { &hf_snmp_agent,
+               { "Agent address", "snmp.agent", FT_IPv4, BASE_NONE, NULL,
+                   0x0, "", HFILL }},
+               { &hf_snmp_enterprise,
+               { "Enterprise", "snmp.enterprise", FT_STRING, BASE_NONE, NULL,
+                   0x0, "", HFILL }},
+               { &hf_snmp_error_status,
+               { "Error Status", "snmp.error", FT_UINT8, BASE_DEC, VALS(error_statuses),
+                   0x0, "", HFILL }},
+               { &hf_snmp_oid,
+               { "Object identifier", "snmp.oid", FT_STRING, BASE_NONE, NULL,
+                   0x0, "", HFILL }},
+               { &hf_snmp_traptype,
+               { "Trap type", "snmp.traptype", FT_UINT8, BASE_DEC, VALS(trap_types),
+                   0x0, "", HFILL }},
+               { &hf_snmp_spectraptype,
+               { "Specific trap type", "snmp.spectraptype", FT_UINT32, BASE_DEC, NULL,
+                   0x0, "", HFILL }},
+               { &hf_snmp_timestamp,
+               { "Timestamp", "snmp.timestamp", FT_UINT8, BASE_DEC, NULL,
+                   0x0, "", HFILL }},
                { &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, "" }},
-        };
+                   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,
        };
+       module_t *snmp_module;
+
+#ifdef HAVE_SOME_SNMP
+
+#ifdef WIN32
+       /* Set MIBDIRS so that the SNMP library can find its mibs. */
+       /* XXX - Should we set MIBS or MIBFILES as well? */
+
+       mib_path = g_malloc (strlen(get_datafile_dir()) + strlen(MIB_PATH_APPEND) + 20);
+       sprintf (mib_path, "MIBDIRS=%s\\%s", get_datafile_dir(), MIB_PATH_APPEND);
+       /* Amazingly enough, Windows does not provide setenv(). */
+       if (getenv("MIBDIRS") == NULL)
+               _putenv(mib_path);
+       g_free(mib_path);
 
-#if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
-       /* UCD or CMU SNMP */
+#endif /* WIN32 */
+
+       /*
+        * Suppress warnings about unknown tokens - we aren't initializing
+        * UCD SNMP in its entirety, we're just initializing the
+        * MIB-handling part because that's all we're using, which
+        * means that entries in the configuration file for other
+        * pars of the library will not be handled, and we don't want
+        * the config file reading code to whine about that.
+        */
+       netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+                               NETSNMP_DS_LIB_NO_TOKEN_WARNINGS, TRUE);
+       netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+                           NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY, 2);
+       register_mib_handlers();
+       read_premib_configs();
        init_mib();
-#ifdef HAVE_UCD_SNMP_SNMP_H
-#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",
+       read_configs();
+#endif /* HAVE_SOME_SNMP */
+       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_field_array(proto_snmp, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
+       snmp_handle = create_dissector_handle(dissect_snmp, proto_snmp);
+
+       /* Register configuration preferences */
+       snmp_module = prefs_register_protocol(proto_snmp, NULL);
+       prefs_register_bool_preference(snmp_module, "display_oid",
+               "Show SNMP OID in info column",
+               "Whether the SNMP OID should be shown in the info column",
+               &display_oid);
+       prefs_register_bool_preference(snmp_module, "desegment",
+           "Desegment all SNMP-over-TCP messages spanning multiple TCP segments",
+           "Whether the SNMP dissector should desegment all messages "
+           "spanning multiple TCP segments",
+           &snmp_desegment);
 }
 
 void
 proto_reg_handoff_snmp(void)
 {
-       old_dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp,
-           proto_snmp);
-       old_dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp,
-           proto_snmp);
-       old_dissector_add("tcp.port", TCP_PORT_SMUX, dissect_smux,
-           proto_smux);
-       old_dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp,
-           proto_snmp);
-       old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, dissect_snmp,
-           proto_snmp);
-       old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, dissect_snmp,
-           proto_snmp);
+       dissector_handle_t snmp_tcp_handle;
+
+       dissector_add("udp.port", UDP_PORT_SNMP, snmp_handle);
+       dissector_add("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
+       dissector_add("ethertype", ETHERTYPE_SNMP, snmp_handle);
+       dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
+       dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
+       dissector_add("hpext.dxsap", HPEXT_SNMP, snmp_handle);
+
+       snmp_tcp_handle = create_dissector_handle(dissect_snmp_tcp, proto_snmp);
+       dissector_add("tcp.port", TCP_PORT_SNMP, snmp_tcp_handle);
+       dissector_add("tcp.port", TCP_PORT_SNMP_TRAP, snmp_tcp_handle);
+
+       data_handle = find_dissector("data");
+}
+
+void
+proto_register_smux(void)
+{
+       static hf_register_info hf[] = {
+               { &hf_smux_version,
+               { "Version", "smux.version", FT_UINT8, BASE_DEC, NULL,
+                   0x0, "", HFILL }},
+               { &hf_smux_pdutype,
+               { "PDU type", "smux.pdutype", FT_UINT8, BASE_DEC, VALS(smux_types),
+                   0x0, "", HFILL }},
+       };
+       static gint *ett[] = {
+               &ett_smux,
+       };
+
+       proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
+           "SMUX", "smux");
+       proto_register_field_array(proto_smux, hf, array_length(hf));
+       proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_smux(void)
+{
+       dissector_handle_t smux_handle;
+
+       smux_handle = create_dissector_handle(dissect_smux, proto_smux);
+       dissector_add("tcp.port", TCP_PORT_SMUX, smux_handle);
 }