Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / packet-nbns.c
index cb1728059dc4668e73d56f92c00fc2bb132d7ca4..284a15ece13e13dccc902fcc76c82a5108edd71a 100644 (file)
@@ -1,15 +1,13 @@
 /* packet-nbns.c
  * Routines for NetBIOS-over-TCP packet disassembly (the name dates back
  * to when it had only NBNS)
- * Gilbert Ramirez <gram@verdict.uthscsa.edu>
- * Much stuff added by Guy Harris <guy@netapp.com>
+ * Guy Harris <guy@alum.mit.edu>
  *
- * $Id: packet-nbns.c,v 1.27 1999/09/03 01:43:08 guy Exp $
+ * $Id: packet-nbns.c,v 1.78 2002/08/07 00:43:13 tpot Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
- *
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
 #include <stdio.h>
 #include <string.h>
 #include <glib.h>
-#include "packet.h"
+
+#include <epan/packet.h>
 #include "packet-dns.h"
 #include "packet-netbios.h"
-#include "util.h"
+#include "packet-tcp.h"
+#include "packet-frame.h"
+#include "prefs.h"
 
 static int proto_nbns = -1;
+static int hf_nbns_flags = -1;
+static int hf_nbns_flags_response = -1;
+static int hf_nbns_flags_opcode = -1;
+static int hf_nbns_flags_authoritative = -1;
+static int hf_nbns_flags_truncated = -1;
+static int hf_nbns_flags_recdesired = -1;
+static int hf_nbns_flags_recavail = -1;
+static int hf_nbns_flags_broadcast = -1;
+static int hf_nbns_flags_rcode = -1;
+static int hf_nbns_transaction_id = -1;
+static int hf_nbns_count_questions = -1;
+static int hf_nbns_count_answers = -1;
+static int hf_nbns_count_auth_rr = -1;
+static int hf_nbns_count_add_rr = -1;
+
+static gint ett_nbns = -1;
+static gint ett_nbns_qd = -1;
+static gint ett_nbns_flags = -1;
+static gint ett_nbns_nb_flags = -1;
+static gint ett_nbns_name_flags = -1;
+static gint ett_nbns_rr = -1;
+static gint ett_nbns_qry = -1;
+static gint ett_nbns_ans = -1;
+
 static int proto_nbdgm = -1;
+static int hf_nbdgm_type = -1;
+static int hf_nbdgm_fragment = -1;
+static int hf_nbdgm_first = -1;
+static int hf_nbdgm_node_type = -1;
+static int hf_nbdgm_datagram_id = -1;
+static int hf_nbdgm_src_ip = -1;
+static int hf_nbdgm_src_port = -1;
+
+static gint ett_nbdgm = -1;
+
 static int proto_nbss = -1;
+static int hf_nbss_type = -1;
+static int hf_nbss_flags = -1;
+
+static gint ett_nbss = -1;
+static gint ett_nbss_flags = -1;
+
+/* desegmentation of NBSS over TCP */
+static gboolean nbss_desegment = TRUE;
+
+/* See RFC 1001 and 1002 for information on the first three, and see
+
+       http://www.cifs.com/specs/draft-leach-cifs-v1-spec-01.txt
+
+   Appendix B, and various messages on the CIFS mailing list such as
+
+       http://discuss.microsoft.com/SCRIPTS/WA-MSD.EXE?A2=ind9811A&L=cifs&P=R386
+
+   for information on the fourth. */
+#define UDP_PORT_NBNS  137
+#define UDP_PORT_NBDGM 138
+#define TCP_PORT_NBSS  139
+#define TCP_PORT_CIFS  445
 
 /* Packet structure taken from RFC 1002. See also RFC 1001.
  * Opcode, flags, and rcode treated as "flags", similarly to DNS,
@@ -68,6 +121,7 @@ static int proto_nbss = -1;
 /* Bit fields in the flags */
 #define F_RESPONSE      (1<<15)         /* packet is response */
 #define F_OPCODE        (0xF<<11)       /* query opcode */
+#define OPCODE_SHIFT   11
 #define F_AUTHORITATIVE (1<<10)         /* response is authoritative */
 #define F_TRUNCATED     (1<<9)          /* response is truncated */
 #define F_RECDESIRED    (1<<8)          /* recursion desired */
@@ -75,24 +129,77 @@ static int proto_nbss = -1;
 #define F_BROADCAST     (1<<4)          /* broadcast/multicast packet */
 #define F_RCODE         (0xF<<0)        /* reply code */
 
+static const true_false_string tfs_flags_response = {
+       "Message is a response",
+       "Message is a query"
+};
+
+static const true_false_string tfs_flags_authoritative = {
+       "Server is an authority for domain",
+       "Server is not an authority for domain"
+};
+
+static const true_false_string tfs_flags_truncated = {
+       "Message is truncated",
+       "Message is not truncated"
+};
+
+static const true_false_string tfs_flags_recdesired = {
+       "Do query recursively",
+       "Don't do query recursively"
+};
+
+static const true_false_string tfs_flags_recavail = {
+       "Server can do recursive queries",
+       "Server can't do recursive queries"
+};
+
+static const true_false_string tfs_flags_broadcast = {
+       "Broadcast packet",
+       "Not a broadcast packet"
+};
+
 /* Opcodes */
-#define OPCODE_QUERY          (0<<11)    /* standard query */
-#define OPCODE_REGISTRATION   (5<<11)    /* registration */
-#define OPCODE_RELEASE        (6<<11)    /* release name */
-#define OPCODE_WACK           (7<<11)    /* wait for acknowledgement */
-#define OPCODE_REFRESH        (8<<11)    /* refresh registration */
-#define OPCODE_REFRESHALT     (9<<11)    /* refresh registration (alternate opcode) */
-#define OPCODE_MHREGISTRATION (15<<11)   /* multi-homed registration */
+#define OPCODE_QUERY          0         /* standard query */
+#define OPCODE_REGISTRATION   5         /* registration */
+#define OPCODE_RELEASE        6         /* release name */
+#define OPCODE_WACK           7         /* wait for acknowledgement */
+#define OPCODE_REFRESH        8         /* refresh registration */
+#define OPCODE_REFRESHALT     9         /* refresh registration (alternate opcode) */
+#define OPCODE_MHREGISTRATION 15        /* multi-homed registration */
+
+static const value_string opcode_vals[] = {
+         { OPCODE_QUERY,          "Name query"                 },
+         { OPCODE_REGISTRATION,   "Registration"               },
+         { OPCODE_RELEASE,        "Release"                    },
+         { OPCODE_WACK,           "Wait for acknowledgment"    },
+         { OPCODE_REFRESH,        "Refresh"                    },
+         { OPCODE_REFRESHALT,     "Refresh (alternate opcode)" },
+         { OPCODE_MHREGISTRATION, "Multi-homed registration"   },
+         { 0,                     NULL                         }
+};
 
 /* Reply codes */
-#define RCODE_NOERROR   (0<<0)
-#define RCODE_FMTERROR  (1<<0)
-#define RCODE_SERVFAIL  (2<<0)
-#define RCODE_NAMEERROR (3<<0)
-#define RCODE_NOTIMPL   (4<<0)
-#define RCODE_REFUSED   (5<<0)
-#define RCODE_ACTIVE    (6<<0)
-#define RCODE_CONFLICT  (7<<0)
+#define RCODE_NOERROR   0
+#define RCODE_FMTERROR  1
+#define RCODE_SERVFAIL  2
+#define RCODE_NAMEERROR 3
+#define RCODE_NOTIMPL   4
+#define RCODE_REFUSED   5
+#define RCODE_ACTIVE    6
+#define RCODE_CONFLICT  7
+
+static const value_string rcode_vals[] = {
+         { RCODE_NOERROR,   "No error"                        },
+         { RCODE_FMTERROR,  "Request was invalidly formatted" },
+         { RCODE_SERVFAIL,  "Server failure"                  },
+         { RCODE_NAMEERROR, "Requested name does not exist"   },
+         { RCODE_NOTIMPL,   "Request is not implemented"      },
+         { RCODE_REFUSED,   "Request was refused"             },
+         { RCODE_ACTIVE,    "Name is owned by another node"   },
+         { RCODE_CONFLICT,  "Name is in conflict"             },
+         { 0,               NULL                              }
+};
 
 /* Values for the "NB_FLAGS" field of RR data.  From RFC 1001 and 1002,
  * except for NB_FLAGS_ONT_H_NODE, which was discovered by looking at
@@ -123,17 +230,6 @@ static int proto_nbss = -1;
 
 #define        NAME_FLAGS_G            (1<<(15-0))     /* group name */
 
-static const value_string opcode_vals[] = {
-         { OPCODE_QUERY,          "Name query"                 },
-         { OPCODE_REGISTRATION,   "Registration"               },
-         { OPCODE_RELEASE,        "Release"                    },
-         { OPCODE_WACK,           "Wait for acknowledgment"    },
-         { OPCODE_REFRESH,        "Refresh"                    },
-         { OPCODE_REFRESHALT,     "Refresh (alternate opcode)" },
-         { OPCODE_MHREGISTRATION, "Multi-homed registration"   },
-         { 0,                     NULL                         }
-};
-
 static char *
 nbns_type_name (int type)
 {
@@ -147,18 +243,21 @@ nbns_type_name (int type)
        return "unknown";
 }
 
+#define NBNAME_BUF_LEN 128
+
 static int
-get_nbns_name(const u_char *nbns_data_ptr, const u_char *pd,
-    int offset, char *name_ret, int *name_type_ret)
+get_nbns_name(tvbuff_t *tvb, int offset, int nbns_data_offset,
+    char *name_ret, int *name_type_ret)
 {
        int name_len;
        char name[MAXDNAME];
-       char nbname[NETBIOS_NAME_LEN];
+       char nbname[NBNAME_BUF_LEN];
        char *pname, *pnbname, cname, cnbname;
        int name_type;
 
-       name_len = get_dns_name(nbns_data_ptr, pd + offset, name, sizeof(name));
-       
+       name_len = get_dns_name(tvb, offset, nbns_data_offset, name,
+           sizeof(name));
+
        /* OK, now undo the first-level encoding. */
        pname = &name[0];
        pnbname = &nbname[0];
@@ -240,21 +339,22 @@ bad:
 
 
 static int
-get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
-    int offset, char *name_ret, int *name_len_ret, int *name_type_ret,
-    int *type_ret, int *class_ret)
+get_nbns_name_type_class(tvbuff_t *tvb, int offset, int nbns_data_offset,
+    char *name_ret, int *name_len_ret, int *name_type_ret, int *type_ret,
+    int *class_ret)
 {
        int name_len;
        int type;
        int class;
 
-       name_len = get_nbns_name(nbns_data_ptr, pd, offset, name_ret,
+       name_len = get_nbns_name(tvb, offset, nbns_data_offset, name_ret,
           name_type_ret);
        offset += name_len;
        
-       type = pntohs(&pd[offset]);
+       type = tvb_get_ntohs(tvb, offset);
        offset += 2;
-       class = pntohs(&pd[offset]);
+
+       class = tvb_get_ntohs(tvb, offset);
 
        *type_ret = type;
        *class_ret = class;
@@ -264,21 +364,21 @@ get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
 }
 
 static void
-add_name_and_type(proto_tree *tree, int offset, int len, char *tag,
-    char *name, int name_type)
+add_name_and_type(proto_tree *tree, tvbuff_t *tvb, int offset, int len,
+    char *tag, char *name, int name_type)
 {
        if (name_type != -1) {
-               proto_tree_add_text(tree, offset, len, "%s: %s (%s)",
+               proto_tree_add_text(tree, tvb, offset, len, "%s: %s (%s)",
                    tag, name, netbios_name_type_descr(name_type));
        } else {
-               proto_tree_add_text(tree, offset, len, "%s: %s",
+               proto_tree_add_text(tree, tvb, offset, len, "%s: %s",
                    tag, name);
        }
 }
 
 static int
-dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
-    proto_tree *nbns_tree)
+dissect_nbns_query(tvbuff_t *tvb, int offset, int nbns_data_offset,
+    column_info *cinfo, proto_tree *nbns_tree)
 {
        int len;
        char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
@@ -288,114 +388,87 @@ dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
        int class;
        char *class_name;
        char *type_name;
-       const u_char *dptr;
-       const u_char *data_start;
+       int data_offset;
+       int data_start;
        proto_tree *q_tree;
        proto_item *tq;
 
-       data_start = dptr = pd + offset;
+       data_start = data_offset = offset;
 
-       len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
+       len = get_nbns_name_type_class(tvb, offset, nbns_data_offset, name,
            &name_len, &name_type, &type, &class);
-       dptr += len;
+       data_offset += len;
 
        type_name = nbns_type_name(type);
        class_name = dns_class_name(class);
 
-       tq = proto_tree_add_text(nbns_tree, offset, len, "%s: type %s, class %s", 
-           name, type_name, class_name);
-       q_tree = proto_item_add_subtree(tq, ETT_NBNS_QD);
+       if (cinfo != NULL)
+               col_append_fstr(cinfo, COL_INFO, " %s %s", type_name, name);
+       if (nbns_tree != NULL) {
+               tq = proto_tree_add_text(nbns_tree, tvb, offset, len,
+                   "%s: type %s, class %s",  name, type_name, class_name);
+               q_tree = proto_item_add_subtree(tq, ett_nbns_qd);
 
-       add_name_and_type(q_tree, offset, name_len, "Name", name, name_type);
-       offset += name_len;
+               add_name_and_type(q_tree, tvb, offset, name_len, "Name", name,
+                   name_type);
+               offset += name_len;
 
-       proto_tree_add_text(q_tree, offset, 2, "Type: %s", type_name);
-       offset += 2;
+               proto_tree_add_text(q_tree, tvb, offset, 2, "Type: %s", type_name);
+               offset += 2;
 
-       proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
-       offset += 2;
+               proto_tree_add_text(q_tree, tvb, offset, 2, "Class: %s", class_name);
+               offset += 2;
+       }
        
-       return dptr - data_start;
+       return data_offset - data_start;
 }
 
 static void
-nbns_add_nbns_flags(proto_tree *nbns_tree, int offset, u_short flags,
-    int is_wack)
+nbns_add_nbns_flags(proto_tree *nbns_tree, tvbuff_t *tvb, int offset,
+    gushort flags, int is_wack)
 {
        char buf[128+1];
+       guint16 opcode;
        proto_tree *field_tree;
        proto_item *tf;
-       static const value_string rcode_vals[] = {
-                 { RCODE_NOERROR,   "No error"                        },
-                 { RCODE_FMTERROR,  "Request was invalidly formatted" },
-                 { RCODE_SERVFAIL,  "Server failure"                  },
-                 { RCODE_NAMEERROR, "Requested name does not exist"   },
-                 { RCODE_NOTIMPL,   "Request is not implemented"      },
-                 { RCODE_REFUSED,   "Request was refused"             },
-                 { RCODE_ACTIVE,    "Name is owned by another node"   },
-                 { RCODE_CONFLICT,  "Name is in conflict"             },
-                 { 0,               NULL                              }
-       };
 
-       strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals,
-                               "Unknown operation"));
+       opcode = (flags & F_OPCODE) >> OPCODE_SHIFT;
+       strcpy(buf, val_to_str(opcode, opcode_vals, "Unknown operation"));
        if (flags & F_RESPONSE && !is_wack) {
                strcat(buf, " response");
                strcat(buf, ", ");
                strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
                    "Unknown error"));
        }
-       tf = proto_tree_add_text(nbns_tree, offset, 2,
-                       "Flags: 0x%04x (%s)", flags, buf);
-       field_tree = proto_item_add_subtree(tf, ETT_NBNS_FLAGS);
-       proto_tree_add_text(field_tree, offset, 2, "%s",
-                       decode_boolean_bitfield(flags, F_RESPONSE,
-                               2*8, "Response", "Query"));
-       proto_tree_add_text(field_tree, offset, 2, "%s",
-                       decode_enumerated_bitfield(flags, F_OPCODE,
-                               2*8, opcode_vals, "%s"));
+       tf = proto_tree_add_uint_format(nbns_tree, hf_nbns_flags,
+           tvb, offset, 2, flags, "Flags: 0x%04x (%s)", flags, buf);
+       field_tree = proto_item_add_subtree(tf, ett_nbns_flags);
+       proto_tree_add_item(field_tree, hf_nbns_flags_response,
+           tvb, offset, 2, FALSE);
+       proto_tree_add_item(field_tree, hf_nbns_flags_opcode,
+           tvb, offset, 2, FALSE);
        if (flags & F_RESPONSE) {
-               proto_tree_add_text(field_tree, offset, 2,
-                       "%s",
-                       decode_boolean_bitfield(flags, F_AUTHORITATIVE,
-                               2*8,
-                               "Server is an authority for domain",
-                               "Server isn't an authority for domain"));
+               proto_tree_add_item(field_tree, hf_nbns_flags_authoritative,
+                         tvb, offset, 2, FALSE);
        }
-       proto_tree_add_text(field_tree, offset, 2, "%s",
-                       decode_boolean_bitfield(flags, F_TRUNCATED,
-                               2*8,
-                               "Message is truncated",
-                               "Message is not truncated"));
-       proto_tree_add_text(field_tree, offset, 2, "%s",
-                       decode_boolean_bitfield(flags, F_RECDESIRED,
-                               2*8,
-                               "Do query recursively",
-                               "Don't do query recursively"));
+       proto_tree_add_item(field_tree, hf_nbns_flags_truncated,
+           tvb, offset, 2, FALSE);
+       proto_tree_add_item(field_tree, hf_nbns_flags_recdesired,
+           tvb, offset, 2, FALSE);
        if (flags & F_RESPONSE) {
-               proto_tree_add_text(field_tree, offset, 2,
-                       "%s",
-                       decode_boolean_bitfield(flags, F_RECAVAIL,
-                               2*8,
-                               "Server can do recursive queries",
-                               "Server can't do recursive queries"));
+               proto_tree_add_item(field_tree, hf_nbns_flags_recavail,
+                   tvb, offset, 2, FALSE);
        }
-       proto_tree_add_text(field_tree, offset, 2, "%s",
-                       decode_boolean_bitfield(flags, F_BROADCAST,
-                               2*8,
-                               "Broadcast packet",
-                               "Not a broadcast packet"));
+       proto_tree_add_item(field_tree, hf_nbns_flags_broadcast,
+           tvb, offset, 2, FALSE);
        if (flags & F_RESPONSE && !is_wack) {
-               proto_tree_add_text(field_tree, offset, 2,
-                       "%s",
-                       decode_enumerated_bitfield(flags, F_RCODE,
-                               2*8,
-                               rcode_vals, "%s"));
+               proto_tree_add_item(field_tree, hf_nbns_flags_rcode,
+                   tvb, offset, 2, FALSE);
        }
 }
 
 static void
-nbns_add_nb_flags(proto_tree *rr_tree, int offset, u_short flags)
+nbns_add_nb_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset, gushort flags)
 {
        char buf[128+1];
        proto_tree *field_tree;
@@ -415,21 +488,22 @@ nbns_add_nb_flags(proto_tree *rr_tree, int offset, u_short flags)
                strcat(buf, "group");
        else
                strcat(buf, "unique");
-       tf = proto_tree_add_text(rr_tree, offset, 2, "Flags: 0x%x (%s)", flags,
+       tf = proto_tree_add_text(rr_tree, tvb, offset, 2, "Flags: 0x%x (%s)", flags,
                        buf);
-       field_tree = proto_item_add_subtree(tf, ETT_NBNS_NB_FLAGS);
-       proto_tree_add_text(field_tree, offset, 2, "%s",
+       field_tree = proto_item_add_subtree(tf, ett_nbns_nb_flags);
+       proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NB_FLAGS_G,
                                2*8,
                                "Group name",
                                "Unique name"));
-       proto_tree_add_text(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
                        decode_enumerated_bitfield(flags, NB_FLAGS_ONT,
                                2*8, nb_flags_ont_vals, "%s"));
 }
 
 static void
-nbns_add_name_flags(proto_tree *rr_tree, int offset, u_short flags)
+nbns_add_name_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset,
+    gushort flags)
 {
        char buf[128+1];
        proto_item *field_tree;
@@ -456,33 +530,33 @@ nbns_add_name_flags(proto_tree *rr_tree, int offset, u_short flags)
                strcat(buf, ", active");
        if (flags & NAME_FLAGS_PRM)
                strcat(buf, ", permanent node name");
-       tf = proto_tree_add_text(rr_tree, offset, 2, "Name flags: 0x%x (%s)",
+       tf = proto_tree_add_text(rr_tree, tvb, offset, 2, "Name flags: 0x%x (%s)",
                        flags, buf);
-       field_tree = proto_item_add_subtree(tf, ETT_NBNS_NAME_FLAGS);
-       proto_tree_add_text(field_tree, offset, 2, "%s",
+       field_tree = proto_item_add_subtree(tf, ett_nbns_name_flags);
+       proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_G,
                                2*8,
                                "Group name",
                                "Unique name"));
-       proto_tree_add_text(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
                        decode_enumerated_bitfield(flags, NAME_FLAGS_ONT,
                                2*8, name_flags_ont_vals, "%s"));
-       proto_tree_add_text(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_DRG,
                                2*8,
                                "Name is being deregistered",
                                "Name is not being deregistered"));
-       proto_tree_add_text(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_CNF,
                                2*8,
                                "Name is in conflict",
                                "Name is not in conflict"));
-       proto_tree_add_text(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_ACT,
                                2*8,
                                "Name is active",
                                "Name is not active"));
-       proto_tree_add_text(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_PRM,
                                2*8,
                                "Permanent node name",
@@ -490,8 +564,8 @@ nbns_add_name_flags(proto_tree *rr_tree, int offset, u_short flags)
 }
 
 static int
-dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
-    proto_tree *nbns_tree, int opcode)
+dissect_nbns_answer(tvbuff_t *tvb, int offset, int nbns_data_offset,
+    column_info *cinfo, proto_tree *nbns_tree, int opcode)
 {
        int len;
        char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME + 64];
@@ -501,365 +575,382 @@ dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
        int class;
        char *class_name;
        char *type_name;
-       const u_char *dptr;
-       const u_char *data_start;
-       u_int ttl;
-       u_short data_len;
-       u_short flags;
+       int data_offset;
+       int cur_offset;
+       int data_start;
+       guint ttl;
+       gushort data_len;
+       gushort flags;
        proto_tree *rr_tree;
        proto_item *trr;
        char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
+       guint num_names;
+       char nbname[16+4+1];    /* 4 for [<last char>] */
+       gushort name_flags;
 
-       data_start = dptr = pd + offset;
+       data_start = data_offset = offset;
+       cur_offset = offset;
 
-       len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
+       len = get_nbns_name_type_class(tvb, offset, nbns_data_offset, name,
            &name_len, &name_type, &type, &class);
-       dptr += len;
+       data_offset += len;
+       cur_offset += len;
 
        type_name = nbns_type_name(type);
        class_name = dns_class_name(class);
 
-       ttl = pntohl(dptr);
-       dptr += 4;
+       ttl = tvb_get_ntohl(tvb, data_offset);
+       data_offset += 4;
+       cur_offset += 4;
 
-       data_len = pntohs(dptr);
-       dptr += 2;
+       data_len = tvb_get_ntohs(tvb, data_offset);
+       data_offset += 2;
+       cur_offset += 2;
 
        switch (type) {
        case T_NB:              /* "NB" record */
-               trr = proto_tree_add_text(nbns_tree, offset,
-                   (dptr - data_start) + data_len,
+               if (cinfo != NULL) {
+                       if (opcode != OPCODE_WACK) {
+                               col_append_fstr(cinfo, COL_INFO, " %s %s",
+                                   type_name,
+                                   ip_to_str(tvb_get_ptr(tvb, data_offset+2, 4)));
+                       }
+               }
+               if (nbns_tree == NULL)
+                       break;
+               trr = proto_tree_add_text(nbns_tree, tvb, offset,
+                   (data_offset - data_start) + data_len,
                    "%s: type %s, class %s",
                    name, type_name, class_name);
                strcat(name, " (");
                strcat(name, netbios_name_type_descr(name_type));
                strcat(name, ")");
-               rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
+               rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name,
                    name_len, type_name, class_name, ttl, data_len);
-               offset += (dptr - data_start);
                while (data_len > 0) {
                        if (opcode == OPCODE_WACK) {
                                /* WACK response.  This doesn't contain the
                                 * same type of RR data as other T_NB
                                 * responses.  */
                                if (data_len < 2) {
-                                       proto_tree_add_text(rr_tree, offset,
+                                       proto_tree_add_text(rr_tree, tvb, cur_offset,
                                            data_len, "(incomplete entry)");
                                        break;
                                }
-                               flags = pntohs(dptr);
-                               dptr += 2;
-                               nbns_add_nbns_flags(rr_tree, offset, flags, 1);
-                               offset += 2;
+                               flags = tvb_get_ntohs(tvb, cur_offset);
+                               nbns_add_nbns_flags(rr_tree, tvb, cur_offset,
+                                   flags, 1);
+                               cur_offset += 2;
                                data_len -= 2;
                        } else {
                                if (data_len < 2) {
-                                       proto_tree_add_text(rr_tree, offset,
+                                       proto_tree_add_text(rr_tree, tvb, cur_offset,
                                            data_len, "(incomplete entry)");
                                        break;
                                }
-                               flags = pntohs(dptr);
-                               dptr += 2;
-                               nbns_add_nb_flags(rr_tree, offset, flags);
-                               offset += 2;
+                               flags = tvb_get_ntohs(tvb, cur_offset);
+                               nbns_add_nb_flags(rr_tree, tvb, cur_offset,
+                                   flags);
+                               cur_offset += 2;
                                data_len -= 2;
 
                                if (data_len < 4) {
-                                       proto_tree_add_text(rr_tree, offset,
+                                       proto_tree_add_text(rr_tree, tvb, cur_offset,
                                            data_len, "(incomplete entry)");
                                        break;
                                }
-                               proto_tree_add_text(rr_tree, offset, 4,
+                               proto_tree_add_text(rr_tree, tvb, cur_offset, 4,
                                    "Addr: %s",
-                                   ip_to_str((guint8 *)dptr));
-                               dptr += 4;
-                               offset += 4;
+                                   ip_to_str(tvb_get_ptr(tvb, cur_offset, 4)));
+                               cur_offset += 4;
                                data_len -= 4;
                        }
                }
                break;
 
        case T_NBSTAT:  /* "NBSTAT" record */
-               {
-                       u_int num_names;
-                       char nbname[16+4+1];    /* 4 for [<last char>] */
-                       u_short name_flags;
-                       
-                       trr = proto_tree_add_text(nbns_tree, offset,
-                           (dptr - data_start) + data_len,
-                           "%s: type %s, class %s",
-                           name, type_name, class_name);
-                       rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
-                           name_len, type_name, class_name, ttl, data_len);
-                       offset += (dptr - data_start);
-                       if (data_len < 1) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       num_names = *dptr;
-                       dptr += 1;
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Number of names: %u", num_names);
-                       offset += 1;
-
-                       while (num_names != 0) {
-                               if (data_len < NETBIOS_NAME_LEN) {
-                                       proto_tree_add_text(rr_tree, offset,
-                                           data_len, "(incomplete entry)");
-                                       goto out;
-                               }
-                               memcpy(nbname, dptr, NETBIOS_NAME_LEN);
-                               dptr += NETBIOS_NAME_LEN;
-                               name_type = process_netbios_name(nbname,
-                                   name_str);
-                               proto_tree_add_text(rr_tree, offset,
-                                   NETBIOS_NAME_LEN, "Name: %s<%02x> (%s)",
-                                   name_str, name_type,
-                                   netbios_name_type_descr(name_type));
-                               offset += NETBIOS_NAME_LEN;
-                               data_len -= NETBIOS_NAME_LEN;
-
-                               if (data_len < 2) {
-                                       proto_tree_add_text(rr_tree, offset,
-                                           data_len, "(incomplete entry)");
-                                       goto out;
-                               }
-                               name_flags = pntohs(dptr);
-                               dptr += 2;
-                               nbns_add_name_flags(rr_tree, offset, name_flags);
-                               offset += 2;
-                               data_len -= 2;
-
-                               num_names--;
-                       }
-
-                       if (data_len < 6) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 6,
-                           "Unit ID: %s",
-                           ether_to_str((guint8 *)dptr));
-                       dptr += 6;
-                       offset += 6;
-                       data_len -= 6;
-
-                       if (data_len < 1) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 1,
-                           "Jumpers: 0x%x", *dptr);
-                       dptr += 1;
-                       offset += 1;
-                       data_len -= 1;
-
-                       if (data_len < 1) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 1,
-                           "Test result: 0x%x", *dptr);
-                       dptr += 1;
-                       offset += 1;
-                       data_len -= 1;
-
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Version number: 0x%x", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Period of statistics: 0x%x", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Number of CRCs: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Number of alignment errors: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Number of collisions: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Number of send aborts: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 4) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 4,
-                           "Number of good sends: %u", pntohl(dptr));
-                       dptr += 4;
-                       offset += 4;
-                       data_len -= 4;
-
-                       if (data_len < 4) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 4,
-                           "Number of good receives: %u", pntohl(dptr));
-                       dptr += 4;
-                       offset += 4;
-                       data_len -= 4;
-
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Number of retransmits: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Number of no resource conditions: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
+               if (cinfo != NULL)
+                       col_append_fstr(cinfo, COL_INFO, " %s", type_name);
+               if (nbns_tree == NULL)
+                       break;
+               trr = proto_tree_add_text(nbns_tree, tvb, offset,
+                   (data_offset - data_start) + data_len,
+                   "%s: type %s, class %s",
+                   name, type_name, class_name);
+               rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name,
+                   name_len, type_name, class_name, ttl, data_len);
+               if (data_len < 1) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               num_names = tvb_get_guint8(tvb, cur_offset);
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 1,
+                   "Number of names: %u", num_names);
+               cur_offset += 1;
+
+               while (num_names != 0) {
+                       if (data_len < NETBIOS_NAME_LEN) {
+                               proto_tree_add_text(rr_tree, tvb, cur_offset,
                                    data_len, "(incomplete entry)");
-                               break;
+                               goto out;
                        }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Number of command blocks: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
+                       tvb_memcpy(tvb, (guint8 *)nbname, cur_offset,
+                           NETBIOS_NAME_LEN);
+                       name_type = process_netbios_name(nbname,
+                           name_str);
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           NETBIOS_NAME_LEN, "Name: %s<%02x> (%s)",
+                           name_str, name_type,
+                           netbios_name_type_descr(name_type));
+                       cur_offset += NETBIOS_NAME_LEN;
+                       data_len -= NETBIOS_NAME_LEN;
 
                        if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
+                               proto_tree_add_text(rr_tree, tvb, cur_offset,
                                    data_len, "(incomplete entry)");
-                               break;
+                               goto out;
                        }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Number of pending sessions: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
+                       name_flags = tvb_get_ntohs(tvb, cur_offset);
+                       nbns_add_name_flags(rr_tree, tvb, cur_offset,
+                           name_flags);
+                       cur_offset += 2;
                        data_len -= 2;
 
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Max number of pending sessions: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Max total sessions possible: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
+                       num_names--;
+               }
 
-                       if (data_len < 2) {
-                               proto_tree_add_text(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_text(rr_tree, offset, 2,
-                           "Session data packet size: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
+               if (data_len < 6) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 6,
+                   "Unit ID: %s",
+                   ether_to_str(tvb_get_ptr(tvb, cur_offset, 6)));
+               cur_offset += 6;
+               data_len -= 6;
+
+               if (data_len < 1) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 1,
+                   "Jumpers: 0x%x", tvb_get_guint8(tvb, cur_offset));
+               cur_offset += 1;
+               data_len -= 1;
+
+               if (data_len < 1) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 1,
+                   "Test result: 0x%x", tvb_get_guint8(tvb, cur_offset));
+               cur_offset += 1;
+               data_len -= 1;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Version number: 0x%x", tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Period of statistics: 0x%x",
+                   tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Number of CRCs: %u", tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Number of alignment errors: %u",
+                   tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Number of collisions: %u", tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Number of send aborts: %u", tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 4) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 4,
+                   "Number of good sends: %u", tvb_get_ntohl(tvb, cur_offset));
+               cur_offset += 4;
+               data_len -= 4;
+
+               if (data_len < 4) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 4,
+                   "Number of good receives: %u",
+                   tvb_get_ntohl(tvb, cur_offset));
+               cur_offset += 4;
+               data_len -= 4;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Number of retransmits: %u", tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Number of no resource conditions: %u",
+                   tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Number of command blocks: %u",
+                   tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Number of pending sessions: %u",
+                   tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Max number of pending sessions: %u",
+                   tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Max total sessions possible: %u",
+                   tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, tvb, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
                }
+               proto_tree_add_text(rr_tree, tvb, cur_offset, 2,
+                   "Session data packet size: %u",
+                   tvb_get_ntohs(tvb, cur_offset));
+               cur_offset += 2;
+               data_len -= 2;
        out:
                break;
 
        default:
-               trr = proto_tree_add_text(nbns_tree, offset,
-                   (dptr - data_start) + data_len,
+               if (cinfo != NULL)
+                       col_append_fstr(cinfo, COL_INFO, " %s", type_name);
+               if (nbns_tree == NULL)
+                       break;
+               trr = proto_tree_add_text(nbns_tree, tvb, offset,
+                   (data_offset - data_start) + data_len,
                     "%s: type %s, class %s",
                    name, type_name, class_name);
-               rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
+               rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name,
                    name_len, type_name, class_name, ttl, data_len);
-               offset += (dptr - data_start);
-               proto_tree_add_text(rr_tree, offset, data_len, "Data");
+               proto_tree_add_text(rr_tree, tvb, cur_offset, data_len, "Data");
+               cur_offset += data_len;
                break;
        }
-       dptr += data_len;
        
-       return dptr - data_start;
+       return cur_offset - data_start;
 }
 
 static int
-dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd, 
-    int cur_off, proto_tree *nbns_tree)
+dissect_query_records(tvbuff_t *tvb, int cur_off, int nbns_data_offset,
+    int count, column_info *cinfo, proto_tree *nbns_tree)
 {
-       int start_off;
-       proto_tree *qatree;
-       proto_item *ti;
+       int start_off, add_off;
+       proto_tree *qatree = NULL;
+       proto_item *ti = NULL;
        
        start_off = cur_off;
-       ti = proto_tree_add_text(nbns_tree, start_off, 0, "Queries");
-       qatree = proto_item_add_subtree(ti, ETT_NBNS_QRY);
-       while (count-- > 0)
-               cur_off += dissect_nbns_query(nbns_data_ptr, pd, cur_off, qatree);
-       proto_item_set_len(ti, cur_off - start_off);
+       if (nbns_tree != NULL) {
+               ti = proto_tree_add_text(nbns_tree, tvb, start_off, -1, "Queries");
+               qatree = proto_item_add_subtree(ti, ett_nbns_qry);
+       }
+       while (count-- > 0) {
+               add_off = dissect_nbns_query(tvb, cur_off, nbns_data_offset,
+                   cinfo, qatree);
+               cur_off += add_off;
+       }
+       if (ti != NULL)
+               proto_item_set_len(ti, cur_off - start_off);
 
        return cur_off - start_off;
 }
@@ -867,94 +958,133 @@ dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd,
 
 
 static int
-dissect_answer_records(const u_char *nbns_data_ptr, int count,
-    const u_char *pd, int cur_off, proto_tree *nbns_tree, int opcode, char *name)
+dissect_answer_records(tvbuff_t *tvb, int cur_off, int nbns_data_offset,
+    int count, column_info *cinfo, proto_tree *nbns_tree, int opcode,
+    char *name)
 {
-       int start_off;
-       proto_tree *qatree;
-       proto_item *ti;
+       int start_off, add_off;
+       proto_tree *qatree = NULL;
+       proto_item *ti = NULL;
        
        start_off = cur_off;
-       ti = proto_tree_add_text(nbns_tree, start_off, 0, name);
-       qatree = proto_item_add_subtree(ti, ETT_NBNS_ANS);
-       while (count-- > 0)
-               cur_off += dissect_nbns_answer(nbns_data_ptr, pd, cur_off,
-                                       qatree, opcode);
-       proto_item_set_len(ti, cur_off - start_off);
+       if (nbns_tree != NULL) {
+               ti = proto_tree_add_text(nbns_tree, tvb, start_off, -1, name);
+               qatree = proto_item_add_subtree(ti, ett_nbns_ans);
+       }
+       while (count-- > 0) {
+               add_off = dissect_nbns_answer(tvb, cur_off, nbns_data_offset,
+                                       cinfo, qatree, opcode);
+               cur_off += add_off;
+       }
+       if (ti != NULL)
+               proto_item_set_len(ti, cur_off - start_off);
        return cur_off - start_off;
 }
 
-void
-dissect_nbns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+static void
+dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       const u_char            *nbns_data_ptr;
-       proto_tree              *nbns_tree;
+       int                     offset = 0;
+       int                     nbns_data_offset;
+       column_info             *cinfo;
+       proto_tree              *nbns_tree = NULL;
        proto_item              *ti;
-       guint16                 id, flags, quest, ans, auth, add;
+       guint16                 id, flags, opcode, rcode, quest, ans, auth, add;
        int                     cur_off;
 
-       nbns_data_ptr = &pd[offset];
+       nbns_data_offset = offset;
+
+       if (check_col(pinfo->cinfo, COL_PROTOCOL))
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBNS");
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_clear(pinfo->cinfo, COL_INFO);
 
        /* To do: check for runts, errs, etc. */
-       id    = pntohs(&pd[offset + NBNS_ID]);
-       flags = pntohs(&pd[offset + NBNS_FLAGS]);
-       quest = pntohs(&pd[offset + NBNS_QUEST]);
-       ans   = pntohs(&pd[offset + NBNS_ANS]);
-       auth  = pntohs(&pd[offset + NBNS_AUTH]);
-       add   = pntohs(&pd[offset + NBNS_ADD]);
-
-       if (check_col(fd, COL_PROTOCOL))
-               col_add_str(fd, COL_PROTOCOL, "NBNS (UDP)");
-       if (check_col(fd, COL_INFO)) {
-               col_add_fstr(fd, COL_INFO, "%s%s",
-                   val_to_str(flags & F_OPCODE, opcode_vals,
-                     "Unknown operation (%x)"),
+       id    = tvb_get_ntohs(tvb, offset + NBNS_ID);
+       flags = tvb_get_ntohs(tvb, offset + NBNS_FLAGS);
+       opcode = (flags & F_OPCODE) >> OPCODE_SHIFT;
+       rcode = (flags & F_RCODE);
+
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_add_fstr(pinfo->cinfo, COL_INFO, "%s%s",
+                   val_to_str(opcode, opcode_vals, "Unknown operation (%u)"),
                    (flags & F_RESPONSE) ? " response" : "");
+               cinfo = pinfo->cinfo;
+       } else {
+               /* Set "cinfo" to NULL; we pass a NULL "cinfo" to the query
+                  and answer dissectors, as a way of saying that they
+                  shouldn't add stuff to the COL_INFO column (a call to
+                  "check_col(cinfo, COL_INFO)" is more expensive than
+                  a check that a pointer isn't NULL). */
+               cinfo = NULL;
        }
 
        if (tree) {
-               ti = proto_tree_add_item(tree, proto_nbns, offset, END_OF_FRAME, NULL);
-               nbns_tree = proto_item_add_subtree(ti, ETT_NBNS);
-
-               proto_tree_add_text(nbns_tree, offset + NBNS_ID, 2,
-                               "Transaction ID: 0x%04X", id);
-
-               nbns_add_nbns_flags(nbns_tree, offset + NBNS_FLAGS, flags, 0);
-               proto_tree_add_text(nbns_tree, offset + NBNS_QUEST, 2,
-                                       "Questions: %d",
-                                       quest);
-               proto_tree_add_text(nbns_tree, offset + NBNS_ANS, 2,
-                                       "Answer RRs: %d",
-                                       ans);
-               proto_tree_add_text(nbns_tree, offset + NBNS_AUTH, 2,
-                                       "Authority RRs: %d",
-                                       auth);
-               proto_tree_add_text(nbns_tree, offset + NBNS_ADD, 2,
-                                       "Additional RRs: %d",
-                                       add);
-
-               cur_off = offset + NBNS_HDRLEN;
+               ti = proto_tree_add_item(tree, proto_nbns, tvb, offset, -1,
+                   FALSE);
+               nbns_tree = proto_item_add_subtree(ti, ett_nbns);
+
+               proto_tree_add_uint(nbns_tree, hf_nbns_transaction_id, tvb,
+                                   offset + NBNS_ID, 2, id);
+
+               nbns_add_nbns_flags(nbns_tree, tvb, offset + NBNS_FLAGS,
+                                   flags, 0);
+       }
+       quest = tvb_get_ntohs(tvb, offset + NBNS_QUEST);
+       if (tree) {
+               proto_tree_add_uint(nbns_tree, hf_nbns_count_questions, tvb,
+                                   offset + NBNS_QUEST, 2, quest);
+       }
+       ans = tvb_get_ntohs(tvb, offset + NBNS_ANS);
+       if (tree) {
+               proto_tree_add_uint(nbns_tree, hf_nbns_count_answers, tvb,
+                                   offset + NBNS_ANS, 2, ans);
+       }
+       auth = tvb_get_ntohs(tvb, offset + NBNS_AUTH);
+       if (tree) {
+               proto_tree_add_uint(nbns_tree, hf_nbns_count_auth_rr, tvb,
+                                   offset + NBNS_AUTH, 2, auth);
+       }
+       add = tvb_get_ntohs(tvb, offset + NBNS_ADD);
+       if (tree) {
+               proto_tree_add_uint(nbns_tree, hf_nbns_count_add_rr, tvb,
+                                   offset + NBNS_ADD, 2, add);
+       }
+
+       cur_off = offset + NBNS_HDRLEN;
     
-               if (quest > 0)
-                       cur_off += dissect_query_records(nbns_data_ptr,
-                                       quest, pd, cur_off, nbns_tree);
+       if (quest > 0) {
+               /* If this is a response, don't add information about the
+                  queries to the summary, just add information about the
+                  answers. */
+               cur_off += dissect_query_records(tvb, cur_off,
+                   nbns_data_offset, quest,
+                   (!(flags & F_RESPONSE) ? cinfo : NULL), nbns_tree);
+       }
 
-               if (ans > 0)
-                       cur_off += dissect_answer_records(nbns_data_ptr,
-                                       ans, pd, cur_off, nbns_tree,
-                                       flags & F_OPCODE,
-                                       "Answers");
+       if (ans > 0) {
+               /* If this is a request, don't add information about the
+                  answers to the summary, just add information about the
+                  queries. */
+               cur_off += dissect_answer_records(tvb, cur_off,
+                       nbns_data_offset, ans,
+                       ((flags & F_RESPONSE) ? cinfo : NULL), nbns_tree,
+                       opcode, "Answers");
+       }
 
+       if (tree) {
+               /* Don't add information about the authoritative name
+                  servers, or the additional records, to the summary. */
                if (auth > 0)
-                       cur_off += dissect_answer_records(nbns_data_ptr,
-                                       auth, pd, cur_off, nbns_tree, 
-                                       flags & F_OPCODE,
+                       cur_off += dissect_answer_records(tvb, cur_off,
+                                       nbns_data_offset,
+                                       auth, NULL, nbns_tree, opcode,
                                        "Authoritative nameservers");
 
                if (add > 0)
-                       cur_off += dissect_answer_records(nbns_data_ptr,
-                                       add, pd, cur_off, nbns_tree, 
-                                       flags & F_OPCODE,
+                       cur_off += dissect_answer_records(tvb, cur_off,
+                                       nbns_data_offset,
+                                       add, NULL, nbns_tree, opcode,
                                        "Additional records");
        }
 }
@@ -979,65 +1109,91 @@ struct nbdgm_header {
        guint8          error_code;
 };
 
-void
-dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+/*
+ * NBDS message types.
+ */
+#define NBDS_DIRECT_UNIQUE     0x10
+#define NBDS_DIRECT_GROUP      0x11
+#define NBDS_BROADCAST         0x12
+#define NBDS_ERROR             0x13
+#define NBDS_QUERY_REQUEST     0x14
+#define NBDS_POS_QUERY_RESPONSE        0x15
+#define NBDS_NEG_QUERY_RESPONSE        0x16
+
+static const value_string nbds_msgtype_vals[] = {
+       { NBDS_DIRECT_UNIQUE,      "Direct_unique datagram" },
+       { NBDS_DIRECT_GROUP,       "Direct_group datagram" },
+       { NBDS_BROADCAST,          "Broadcast datagram" },
+       { NBDS_ERROR,              "Datagram error" },
+       { NBDS_QUERY_REQUEST,      "Datagram query request" },
+       { NBDS_POS_QUERY_RESPONSE, "Datagram positive query response" },
+       { NBDS_NEG_QUERY_RESPONSE, "Datagram negative query response" },
+       { 0,                       NULL }
+};
+
+static const true_false_string yesno = {  
+       "Yes",
+       "No"
+};
+
+static const value_string node_type_vals[] = {
+       { 0, "B node" },
+       { 1, "P node" },
+       { 2, "M node" },
+       { 3, "NBDD" },
+       { 0, NULL }
+};
+
+static void
+dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
+       int                     offset = 0;
        proto_tree              *nbdgm_tree = NULL;
-       proto_item              *ti;
+       proto_item              *ti = NULL;
        struct nbdgm_header     header;
        int                     flags;
        int                     message_index;
-       int                     max_data = pi.captured_len - offset;
-
-       char *message[] = {
-               "Unknown",
-               "Direct_unique datagram",
-               "Direct_group datagram",
-               "Broadcast datagram",
-               "Datagram error",
-               "Datagram query request",
-               "Datagram positive query response",
-               "Datagram negative query response"
-       };
-
-       char *node[] = {
-               "B node",
-               "P node",
-               "M node",
-               "NBDD"
-       };
+       tvbuff_t                *next_tvb;
 
-       static value_string error_codes[] = {
+       static const value_string error_codes[] = {
                { 0x82, "Destination name not present" },
                { 0x83, "Invalid source name format" },
                { 0x84, "Invalid destination name format" },
                { 0x00, NULL }
        };
 
-       char *yesno[] = { "No", "Yes" };
-
        char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
        int name_type;
        int len;
 
-       header.msg_type = pd[offset];
+       if (check_col(pinfo->cinfo, COL_PROTOCOL))
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBDS");
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_clear(pinfo->cinfo, COL_INFO);
+
+       header.msg_type = tvb_get_guint8(tvb, offset);
        
-       flags = pd[offset+1];
+       flags = tvb_get_guint8(tvb, offset+1);
        header.flags.more = flags & 1;
        header.flags.first = (flags & 2) >> 1;
        header.flags.node_type = (flags & 12) >> 2;
 
-       header.dgm_id = pntohs(&pd[offset+2]);
-       memcpy(&header.src_ip, &pd[offset+4], 4);
-       header.src_port = pntohs(&pd[offset+8]);
+       header.dgm_id = tvb_get_ntohs(tvb, offset+2);
+       tvb_memcpy(tvb, (guint8 *)&header.src_ip, offset+4, 4);
+       header.src_port = tvb_get_ntohs(tvb, offset+8);
 
-       if (header.msg_type == 0x10 ||
-                       header.msg_type == 0x11 || header.msg_type == 0x12) {
-               header.dgm_length = pntohs(&pd[offset+10]);
-               header.pkt_offset = pntohs(&pd[offset+12]);
-       }
-       else if (header.msg_type == 0x13) {
-               header.error_code = pntohs(&pd[offset+10]);
+       switch (header.msg_type) {
+
+       case NBDS_DIRECT_UNIQUE:
+       case NBDS_DIRECT_GROUP:
+       case NBDS_BROADCAST:
+               header.dgm_length = tvb_get_ntohs(tvb, offset+10);
+               header.pkt_offset = tvb_get_ntohs(tvb, offset+12);
+               break;
+
+       case NBDS_ERROR:
+               header.error_code = tvb_get_ntohs(tvb, offset+10);
+               break;
        }
 
        message_index = header.msg_type - 0x0f;
@@ -1045,87 +1201,107 @@ dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
                message_index = 0;
        }
 
-       if (check_col(fd, COL_PROTOCOL))
-               col_add_str(fd, COL_PROTOCOL, "NBDS (UDP)");
-       if (check_col(fd, COL_INFO)) {
-               col_add_fstr(fd, COL_INFO, "%s", message[message_index]);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_add_str(pinfo->cinfo, COL_INFO,
+                   val_to_str(header.msg_type, nbds_msgtype_vals,
+                     "Unknown message type (0x%02X)"));
        }
 
        if (tree) {
-               ti = proto_tree_add_item(tree, proto_nbdgm, offset, header.dgm_length, NULL);
-               nbdgm_tree = proto_item_add_subtree(ti, ETT_NBDGM);
-
-               proto_tree_add_text(nbdgm_tree, offset, 1, "Message Type: %s",
-                               message[message_index]);
-               proto_tree_add_text(nbdgm_tree, offset+1, 1, "More fragments follow: %s",
-                               yesno[header.flags.more]);
-               proto_tree_add_text(nbdgm_tree, offset+1, 1, "This is first fragment: %s",
-                               yesno[header.flags.first]);
-               proto_tree_add_text(nbdgm_tree, offset+1, 1, "Node Type: %s",
-                               node[header.flags.node_type]);
-
-               proto_tree_add_text(nbdgm_tree, offset+2, 2, "Datagram ID: 0x%04X",
-                               header.dgm_id);
-               proto_tree_add_text(nbdgm_tree, offset+4, 4, "Source IP: %s",
-                               ip_to_str((guint8 *)&header.src_ip));
-               proto_tree_add_text(nbdgm_tree, offset+8, 2, "Source Port: %d",
-                               header.src_port);
+               ti = proto_tree_add_item(tree, proto_nbdgm, tvb, offset, -1,
+                   FALSE);
+               nbdgm_tree = proto_item_add_subtree(ti, ett_nbdgm);
+
+               proto_tree_add_uint(nbdgm_tree, hf_nbdgm_type, tvb,
+                                    offset, 1, 
+                                    header.msg_type);
+               proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_fragment, tvb,
+                                      offset+1, 1, 
+                                      header.flags.more);
+               proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_first, tvb,
+                                      offset+1, 1, 
+                                      header.flags.first);
+               proto_tree_add_uint(nbdgm_tree, hf_nbdgm_node_type, tvb,
+                                    offset+1, 1, 
+                                    header.flags.node_type);
+
+               proto_tree_add_uint(nbdgm_tree, hf_nbdgm_datagram_id, tvb,
+                                   offset+2, 2, header.dgm_id);
+               proto_tree_add_ipv4(nbdgm_tree, hf_nbdgm_src_ip, tvb,
+                                   offset+4, 4, header.src_ip);
+               proto_tree_add_uint(nbdgm_tree, hf_nbdgm_src_port, tvb,
+                                   offset+8, 2, header.src_port);
+
        }
 
        offset += 10;
-       max_data -= 10;
 
-       if (header.msg_type == 0x10 ||
-                       header.msg_type == 0x11 || header.msg_type == 0x12) {
+       switch (header.msg_type) {
 
+       case NBDS_DIRECT_UNIQUE:
+       case NBDS_DIRECT_GROUP:
+       case NBDS_BROADCAST:
                if (tree) {
-                       proto_tree_add_text(nbdgm_tree, offset, 2,
+                       proto_tree_add_text(nbdgm_tree, tvb, offset, 2,
                                        "Datagram length: %d bytes", header.dgm_length);
-                       proto_tree_add_text(nbdgm_tree, offset+2, 2,
+                       proto_tree_add_text(nbdgm_tree, tvb, offset+2, 2,
                                        "Packet offset: %d bytes", header.pkt_offset);
                }
 
                offset += 4;
-               max_data -= 4;
 
                /* Source name */
-               len = get_nbns_name(&pd[offset], pd, offset, name, &name_type);
+               len = get_nbns_name(tvb, offset, offset, name, &name_type);
 
                if (tree) {
-                       add_name_and_type(nbdgm_tree, offset, len,
+                       add_name_and_type(nbdgm_tree, tvb, offset, len,
                            "Source name", name, name_type);
                }
                offset += len;
-               max_data -= len;
 
                /* Destination name */
-               len = get_nbns_name(&pd[offset], pd, offset, name, &name_type);
+               len = get_nbns_name(tvb, offset, offset, name, &name_type);
 
                if (tree) {
-                       add_name_and_type(nbdgm_tree, offset, len,
+                       add_name_and_type(nbdgm_tree, tvb, offset, len,
                            "Destination name", name, name_type);
                }
                offset += len;
-               max_data -= len;
 
-               /* here we can pass the packet off to the next protocol */
-               dissect_smb(pd, offset, fd, tree, max_data);
-       }
-       else if (header.msg_type == 0x13) {
+               /*
+                * Here we can pass the packet off to the next protocol.
+                * Set the length of our top-level tree item to include
+                * only our stuff.
+                *
+                * XXX - take the datagram length into account?
+                */
+               proto_item_set_len(ti, offset);
+               next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+               dissect_netbios_payload(next_tvb, pinfo, tree);
+               break;
+
+       case NBDS_ERROR:
                if (tree) {
-                       proto_tree_add_text(nbdgm_tree, offset, 1, "Error code: %s",
+                       proto_tree_add_text(nbdgm_tree, tvb, offset, 1, "Error code: %s",
                                val_to_str(header.error_code, error_codes, "Unknown (0x%x)"));
                }
-       }
-       else if (header.msg_type == 0x14 ||
-                       header.msg_type == 0x15 || header.msg_type == 0x16) {
+               offset += 1;
+               proto_item_set_len(ti, offset);
+               break;
+
+       case NBDS_QUERY_REQUEST:
+       case NBDS_POS_QUERY_RESPONSE:
+       case NBDS_NEG_QUERY_RESPONSE:
                /* Destination name */
-               len = get_nbns_name(&pd[offset], pd, offset, name, &name_type);
+               len = get_nbns_name(tvb, offset, offset, name, &name_type);
 
                if (tree) {
-                       add_name_and_type(nbdgm_tree, offset, len,
+                       add_name_and_type(nbdgm_tree, tvb, offset, len,
                            "Destination name", name, name_type);
                }
+               offset += len;
+               proto_item_set_len(ti, offset);
+               break;
        }
 }
 
@@ -1164,179 +1340,571 @@ static const value_string error_codes[] = {
 };
 
 /*
- * Dissect a single NBSS packet (there may be more than one in a given TCP
- * segment). Hmmm, in my experience, I have never seen more than one NBSS
- * in a single segment, since they mostly contain SMBs which are essentially
- * a request response type protocol (RJS). Also, a single session message 
- * may be split over multiple segments.
+ * Dissect a single NBSS packet (there may be more than one in a given
+ * TCP segment).
+ *
+ * [ Hmmm, in my experience, I have never seen more than one NBSS in a
+ * single segment, since they mostly contain SMBs which are essentially
+ * a request response type protocol (RJS). ]
+ *
+ * [ However, under heavy load with many requests multiplexed on one
+ * session it is not unusual to see multiple requests in one TCP
+ * segment. Unfortunately, in this case a single session message is
+ * frequently split over multiple segments, which frustrates decoding
+ * (MMM). ]
  */
 static int
-dissect_nbss_packet(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
+dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, int is_cifs)
 {
        proto_tree      *nbss_tree = NULL;
-       proto_item      *ti;
+       proto_item      *ti = NULL;
        proto_tree      *field_tree;
        proto_item      *tf;
        guint8          msg_type;
        guint8          flags;
-       guint16         length;
+       volatile int    length;
+       int             length_remaining;
        int             len;
        char            name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
        int             name_type;
+       gint            reported_len;
+       tvbuff_t        *next_tvb;
+       const char      *saved_proto;
+
+       /* Desegmentation */
+       length_remaining = tvb_length_remaining(tvb, offset);
+
+       /*
+        * Can we do reassembly?
+        */
+       if (nbss_desegment && pinfo->can_desegment) {
+               /*
+                * Yes - is the NBSS header split across segment boundaries?
+                */
+               if (length_remaining < 4) {
+                       /*
+                        * Yes.  Tell our caller how many more bytes
+                        * we need.
+                        */
+                       return -(4 - length_remaining);
+               }
+       }
+
+       /*
+        * Get the length of the NBSS message.
+        */
+       if (is_cifs) {
+               flags = 0;
+               length = tvb_get_ntoh24(tvb, offset + 1);
+       } else {
+               flags = tvb_get_guint8(tvb, offset + 1);
+               length = tvb_get_ntohs(tvb, offset + 2);
+               if (flags & NBSS_FLAGS_E)
+                       length += 65536;
+       }
+
+       /*
+        * Can we do reassembly?
+        */
+       if (nbss_desegment && pinfo->can_desegment) {
+               /*
+                * Yes - is the NBSS message split across segment boundaries?
+                */
+               if (length_remaining < length + 4) {
+                       /*
+                        * Yes.  Tell our caller how many more bytes
+                        * we need.
+                        */
+                       return -((length + 4) - length_remaining);
+               }
+       }
 
-       msg_type = pd[offset];
-       flags = pd[offset + 1];
-       length = pntohs(&pd[offset + 2]);
-       if (flags & NBSS_FLAGS_E)
-               length += 65536;
+       msg_type = tvb_get_guint8(tvb, offset);
 
        if (tree) {
-         ti = proto_tree_add_item(tree, proto_nbss, offset, length + 4, NULL);
-         nbss_tree = proto_item_add_subtree(ti, ETT_NBSS);
+         ti = proto_tree_add_item(tree, proto_nbss, tvb, offset, length + 4, FALSE);
+         nbss_tree = proto_item_add_subtree(ti, ett_nbss);
          
-         proto_tree_add_text(nbss_tree, offset, 1, "Message Type: %s",
-                             val_to_str(msg_type, message_types, "Unknown (%x)"));
+         proto_tree_add_uint_format(nbss_tree, hf_nbss_type, tvb,
+                                    offset, 1, 
+                                    msg_type,
+                                    "Message Type: %s",
+                                    val_to_str(msg_type, message_types, 
+                                               "Unknown (%x)"));
        }
 
        offset += 1;
 
-       if (tree) {
-         tf = proto_tree_add_text(nbss_tree, offset, 1, "Flags: 0x%04x", flags);
-         field_tree = proto_item_add_subtree(tf, ETT_NBSS_FLAGS);
-         proto_tree_add_text(field_tree, offset, 1, "%s",
+       if (is_cifs) {
+               if (tree) {
+                 proto_tree_add_text(nbss_tree, tvb, offset, 3, "Length: %u", length);
+               }
+               offset += 3;
+       } else {
+               if (tree) {
+                 tf = proto_tree_add_uint(nbss_tree, hf_nbss_flags, tvb, offset, 1, flags);
+                 field_tree = proto_item_add_subtree(tf, ett_nbss_flags);
+                 proto_tree_add_text(field_tree, tvb, offset, 1, "%s",
                              decode_boolean_bitfield(flags, NBSS_FLAGS_E,
-                                                     8, "Add 65536 to length", "Add 0 to length"));
-       }
+                                                             8, "Add 65536 to length", "Add 0 to length"));
+               }
+               offset += 1;
 
-       offset += 1;
+               if (tree) {
+                 proto_tree_add_text(nbss_tree, tvb, offset, 2, "Length: %u", length);
+               }
 
-       if (tree) {
-         proto_tree_add_text(nbss_tree, offset, 2, "Length: %u", length);
+               offset += 2;
        }
 
-       offset += 2;
-
        switch (msg_type) {
 
        case SESSION_REQUEST:
-         len = get_nbns_name(&pd[offset], pd, offset, name, &name_type);
+         len = get_nbns_name(tvb, offset, offset, name, &name_type);
          if (tree)
-           add_name_and_type(nbss_tree, offset, len,
+           add_name_and_type(nbss_tree, tvb, offset, len,
                                "Called name", name, name_type);
          offset += len;
 
-         len = get_nbns_name(&pd[offset], pd, offset, name, &name_type);
+         if (check_col(pinfo->cinfo, COL_INFO))
+                 col_append_fstr(pinfo->cinfo, COL_INFO, ", to %s ", name);
+                                 
+         len = get_nbns_name(tvb, offset, offset, name, &name_type);
          
          if (tree)
-           add_name_and_type(nbss_tree, offset, len,
+           add_name_and_type(nbss_tree, tvb, offset, len,
                                "Calling name", name, name_type);
 
+         if (check_col(pinfo->cinfo, COL_INFO))
+                 col_append_fstr(pinfo->cinfo, COL_INFO, "from %s", name);
+
          break;
 
        case NEGATIVE_SESSION_RESPONSE:
          if (tree) 
-           proto_tree_add_text(nbss_tree, offset, 1,
+           proto_tree_add_text(nbss_tree, tvb, offset, 1,
                                "Error code: %s",
-                               val_to_str(pd[offset], error_codes, "Unknown (%x)"));
+                               val_to_str(tvb_get_guint8(tvb, offset),
+                                          error_codes, "Unknown (%x)"));
+
+         if (check_col(pinfo->cinfo, COL_INFO))
+                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+                                 val_to_str(tvb_get_guint8(tvb, offset),
+                                            error_codes, "Unknown (%x)"));
+
          break;
 
        case RETARGET_SESSION_RESPONSE:
          if (tree)
-           proto_tree_add_text(nbss_tree, offset, 4,
+           proto_tree_add_text(nbss_tree, tvb, offset, 4,
                                "Retarget IP address: %s",
-                               ip_to_str((guint8 *)&pd[offset]));
+                               ip_to_str(tvb_get_ptr(tvb, offset, 4)));
          
          offset += 4;
 
          if (tree)
-           proto_tree_add_text(nbss_tree, offset, 2,
-                               "Retarget port: %u", pntohs(&pd[offset]));
+           proto_tree_add_text(nbss_tree, tvb, offset, 2,
+                               "Retarget port: %u",
+                               tvb_get_ntohs(tvb, offset));
 
          break;
 
        case SESSION_MESSAGE:
          /*
-          * Here we can pass the packet off to the next protocol.
+          * Here we can pass the message off to the next protocol.
+          * Set the length of our top-level tree item to include
+          * only our stuff.
           */
+         proto_item_set_len(ti, offset);
+         len = tvb_length_remaining(tvb, offset);
+         reported_len = tvb_reported_length_remaining(tvb, offset);
+         if (len > length)
+           len = length;
+         if (reported_len > length)
+           reported_len = length;
 
-         dissect_smb(pd, offset, fd, tree, max_data - 4);
+         next_tvb = tvb_new_subset(tvb, offset, len, reported_len);
 
+         /*
+          * Catch the ReportedBoundsError exception; if this
+          * particular message happens to get a ReportedBoundsError
+          * exception, that doesn't mean that we should stop
+          * dissecting NetBIOS messages within this frame or chunk
+          * of reassembled data.
+          *
+          * If it gets a BoundsError, we can stop, as there's nothing
+          * more to see, so we just re-throw it.
+          */
+         saved_proto = pinfo->current_proto;
+         TRY {
+           dissect_netbios_payload(next_tvb, pinfo, tree);
+         }
+         CATCH(BoundsError) {
+           RETHROW;
+         }
+         CATCH(ReportedBoundsError) {
+           show_reported_bounds_error(tvb, pinfo, tree);
+           pinfo->current_proto = saved_proto;
+         }
+         ENDTRY;
          break;
 
        }
        return length + 4;
 }
 
-void
-dissect_nbss(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+static void
+dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
+       struct tcpinfo  *tcpinfo = pinfo->private_data;
+       int             offset = 0;
+       int             max_data;
        guint8          msg_type;
        guint8          flags;
-       guint16         length;
+       guint32         length;
        int             len;
-       int             max_data;
+       gboolean        is_cifs;
+       proto_tree      *nbss_tree;
+       proto_item      *ti;
 
-       msg_type = pd[offset];
-       flags = pd[offset + 1];
-       length = pntohs(&pd[offset + 2]);
-       if (flags & NBSS_FLAGS_E)
-               length += 65536;
+       if (check_col(pinfo->cinfo, COL_PROTOCOL))
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBSS");
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_clear(pinfo->cinfo, COL_INFO);
+
+       max_data = tvb_length(tvb);
+
+       msg_type = tvb_get_guint8(tvb, offset);
+
+       if (pinfo->match_port == TCP_PORT_CIFS) {
+               /*
+                * Windows 2000 CIFS clients can dispense completely
+                * with the NETBIOS encapsulation and directly use CIFS
+                * over TCP. As would be expected, the framing is
+                * identical, except that the length is 24 bits instead
+                * of 17. The only message types used are
+                * SESSION_MESSAGE and SESSION_KEEP_ALIVE.
+                */
+               is_cifs = TRUE;
+       } else {
+               is_cifs = FALSE;
+       }
 
        /*
-        * XXX - we should set this based on both "pi.captured_len"
-        * and "length"....
+        * This might be a continuation of an earlier message.
+        * (Yes, that might be true even if we're doing TCP reassembly,
+        * as the first TCP segment in the capture might start in the
+        * middle of an NBNS message.)
         */
-       max_data = pi.captured_len - offset;
-
-       /* Hmmm, it may be a continuation message ... */
-
-#define RJSHACK 1
-#ifdef RJSHACK
-       if (((msg_type != SESSION_REQUEST) && 
-            (msg_type != NEGATIVE_SESSION_RESPONSE) &&
-            (msg_type != RETARGET_SESSION_RESPONSE) &&
-            (msg_type != SESSION_MESSAGE)) ||
-           ((msg_type == SESSION_MESSAGE) &&
-           (memcmp(pd + offset + 4, "\377SMB", 4) != 0))) {
-         if (check_col(fd, COL_PROTOCOL))
-           col_add_str(fd, COL_PROTOCOL, "NBSS (TCP)");
-         if (check_col(fd, COL_INFO)) {
-           col_add_fstr(fd, COL_INFO, "NBSS (TCP) Continuation Message");
-         }
 
-         if (tree)
-           proto_tree_add_text(tree, offset, max_data, "Continuation data");
+       /*
+        * If this isn't reassembled data, check to see whether it
+        * looks like a continuation of a message.
+        * (If it is reassembled data, it shouldn't be a continuation,
+        * as reassembly should've gathered the continuations together
+        * into a message.)
+        */
+       if (!tcpinfo->is_reassembled) {
+               if (max_data < 4) {
+                       /*
+                        * Not enough data for an NBSS header; assume
+                        * it's a continuation of a message.
+                        *
+                        * XXX - if there's not enough data, we should
+                        * attempt to reassemble the data, if the first byte
+                        * is a valid message type.
+                        */
+                       goto continuation;
+               }
 
-         return;
-       }
-#endif
+               /*
+                * We have enough data for an NBSS header.
+                * Get the flags and length of the message,
+                * and see if they're sane.
+                */
+               if (is_cifs) {
+                       flags = 0;
+                       length = tvb_get_ntoh24(tvb, offset + 1);
+               } else {
+                       flags = tvb_get_guint8(tvb, offset + 1);
+                       length = tvb_get_ntohs(tvb, offset + 2);
+                       if (flags & NBSS_FLAGS_E)
+                               length += 65536;
+               }
+               if ((flags & (~NBSS_FLAGS_E)) != 0) {
+                       /*
+                        * A bogus flag was set; assume it's a continuation.
+                        */
+                       goto continuation;
+               }
 
-       if (check_col(fd, COL_PROTOCOL))
-               col_add_str(fd, COL_PROTOCOL, "NBSS (TCP)");
-       if (check_col(fd, COL_INFO)) {
-               col_add_fstr(fd, COL_INFO,
-                   val_to_str(msg_type, message_types, "Unknown (%x)"));
+               switch (msg_type) {
+
+               case SESSION_MESSAGE:
+                       /*
+                        * This is variable-length.
+                        * All we know is that it shouldn't be zero.
+                        * (XXX - can we get zero-length messages?
+                        * Not with SMB, but perhaps other NetBIOS-based
+                        * protocols have them.)
+                        */
+                       if (length == 0)
+                               goto continuation;
+                       break;
+
+               case SESSION_REQUEST:
+                       /*
+                        * This is variable-length.
+                        * The names are DNS-encoded 32-byte values;
+                        * we need at least 2 bytes (one for each name;
+                        * actually, we should have more for the first
+                        * name, as there's no name preceding it so
+                        * there should be no compression), and we
+                        * shouldn't have more than 128 bytes (actually,
+                        * we shouldn't have that many).
+                        *
+                        * XXX - actually, MacOS X 10.1 (yes, that's
+                        * redundant, but that's what Apple calls it,
+                        * not MacOS X.1) puts names longer than 16
+                        * characters into session request messages,
+                        * so we can have more than 32 bytes of
+                        * name value, so we can have more than 128
+                        * bytes of data.
+                        */
+                       if (length < 2 || length > 256)
+                               goto continuation;
+                       break;
+
+               case POSITIVE_SESSION_RESPONSE:
+                       /*
+                        * This has no data, so the length must be zero.
+                        */
+                       if (length != 0)
+                               goto continuation;
+                       break;
+
+               case NEGATIVE_SESSION_RESPONSE:
+                       /*
+                        * This has 1 byte of data.
+                        */
+                       if (length != 1)
+                               goto continuation;
+                       break;
+
+               case RETARGET_SESSION_RESPONSE:
+                       /*
+                        * This has 6 bytes of data.
+                        */
+                       if (length != 6)
+                               goto continuation;
+                       break;
+
+               case SESSION_KEEP_ALIVE:
+                       /*
+                        * This has no data, so the length must be zero.
+                        */
+                       if (length != 0)
+                               goto continuation;
+                       break;
+
+               default:
+                       /*
+                        * Unknown message type; assume it's a continuation.
+                        */
+                       goto continuation;
+               }
+       }
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_add_fstr(pinfo->cinfo, COL_INFO,
+                   val_to_str(msg_type, message_types, "Unknown (%02x)"));
        }
 
-       while (max_data > 0) {
-               len = dissect_nbss_packet(pd, offset, fd, tree, max_data);
+       while (tvb_reported_length_remaining(tvb, offset) > 0) {
+               len = dissect_nbss_packet(tvb, offset, pinfo, tree, is_cifs);
+               if (len < 0) {
+                       /*
+                        * We need more data to dissect this, and
+                        * desegmentation is enabled.  "-len" is the
+                        * number of additional bytes of data we need.
+                        *
+                        * 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 = -len;
+                       return;
+               }
                offset += len;
-               max_data -= len;
        }
 
+       return;
+
+continuation:
+       /*
+        * It looks like a continuation.
+        */
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_add_fstr(pinfo->cinfo, COL_INFO, "NBSS Continuation Message");
+
+       if (tree) {
+               ti = proto_tree_add_item(tree, proto_nbss, tvb, 0, -1, FALSE);
+               nbss_tree = proto_item_add_subtree(ti, ett_nbss);
+               proto_tree_add_text(nbss_tree, tvb, 0, -1, "Continuation data");
+       }
 }
 
 void
 proto_register_nbt(void)
 {
-/*        static hf_register_info hf[] = {
-                { &variable,
-                { "Name",           "nbipx.abbreviation", TYPE, VALS_POINTER }},
-        };*/
-
-        proto_nbns = proto_register_protocol("NetBIOS Name Service", "nbns");
-        proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service", "nbdgm");
-        proto_nbss = proto_register_protocol("NetBIOS Session Service", "nbss");
- /*       proto_register_field_array(proto_nbipx, hf, array_length(hf));*/
+
+  static hf_register_info hf_nbns[] = {
+    { &hf_nbns_flags,
+      { "Flags",               "nbns.flags",
+       FT_UINT16, BASE_HEX, NULL, 0x0,
+       "", HFILL }},
+    { &hf_nbns_flags_response,
+      { "Response",            "nbns.flags.response",
+       FT_BOOLEAN, 16, TFS(&tfs_flags_response), F_RESPONSE,
+       "Is the message a response?", HFILL }},
+    { &hf_nbns_flags_opcode,
+      { "Opcode",              "nbns.flags.opcode",
+       FT_UINT16, BASE_DEC, VALS(opcode_vals), F_OPCODE,
+       "Operation code", HFILL }},
+    { &hf_nbns_flags_authoritative,
+      { "Authoritative",       "nbns.flags.authoritative",
+       FT_BOOLEAN, 16, TFS(&tfs_flags_authoritative), F_AUTHORITATIVE,
+       "Is the server is an authority for the domain?", HFILL }},
+    { &hf_nbns_flags_truncated,
+      { "Truncated",   "nbns.flags.truncated",
+       FT_BOOLEAN, 16, TFS(&tfs_flags_truncated), F_TRUNCATED,
+       "Is the message truncated?", HFILL }},
+    { &hf_nbns_flags_recdesired,
+      { "Recursion desired",   "nbns.flags.recdesired",
+       FT_BOOLEAN, 16, TFS(&tfs_flags_recdesired), F_RECDESIRED,
+       "Do query recursively?", HFILL }},
+    { &hf_nbns_flags_recavail,
+      { "Recursion available", "nbns.flags.recavail",
+       FT_BOOLEAN, 16, TFS(&tfs_flags_recavail), F_RECAVAIL,
+       "Can the server do recursive queries?", HFILL }},
+    { &hf_nbns_flags_broadcast,
+      { "Broadcast",           "nbns.flags.broadcast",
+       FT_BOOLEAN, 16, TFS(&tfs_flags_broadcast), F_BROADCAST,
+       "Is this a broadcast packet?", HFILL }},
+    { &hf_nbns_flags_rcode,
+      { "Reply code",          "nbns.flags.rcode",
+       FT_UINT16, BASE_DEC, VALS(rcode_vals), F_RCODE,
+       "Reply code", HFILL }},
+    { &hf_nbns_transaction_id,
+      { "Transaction ID",              "nbns.id",  
+       FT_UINT16, BASE_HEX, NULL, 0x0,
+       "Identification of transaction", HFILL }},
+    { &hf_nbns_count_questions,
+      { "Questions",           "nbns.count.queries",  
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Number of queries in packet", HFILL }},
+    { &hf_nbns_count_answers,
+      { "Answer RRs",          "nbns.count.answers",  
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Number of answers in packet", HFILL }},
+    { &hf_nbns_count_auth_rr,
+      { "Authority RRs",               "nbns.count.auth_rr",  
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Number of authoritative records in packet", HFILL }},
+    { &hf_nbns_count_add_rr,
+      { "Additional RRs",              "nbns.count.add_rr",  
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Number of additional records in packet", HFILL }}
+  };
+
+  static hf_register_info hf_nbdgm[] = {
+    { &hf_nbdgm_type,
+      { "Message Type",                "nbdgm.type",  
+       FT_UINT8, BASE_DEC, VALS(nbds_msgtype_vals), 0x0,
+       "NBDGM message type", HFILL }},
+    { &hf_nbdgm_fragment,
+      { "More fragments follow",       "nbdgm.next",  
+       FT_BOOLEAN, BASE_NONE, TFS(&yesno), 0x0,
+       "TRUE if more fragments follow", HFILL }},
+    { &hf_nbdgm_first,
+      { "This is first fragment",      "nbdgm.first",  
+       FT_BOOLEAN, BASE_NONE, TFS(&yesno), 0x0,
+       "TRUE if first fragment", HFILL }},
+    { &hf_nbdgm_node_type,
+      { "Node Type",           "nbdgm.node_type",  
+       FT_UINT8, BASE_DEC, VALS(node_type_vals), 0x0,
+       "Node type", HFILL }},
+    { &hf_nbdgm_datagram_id,
+      { "Datagram ID",         "nbdgm.dgram_id",  
+       FT_UINT16, BASE_HEX, NULL, 0x0,
+       "Datagram identifier", HFILL }},
+    { &hf_nbdgm_src_ip,
+      { "Source IP",           "nbdgm.src.ip",  
+       FT_IPv4, BASE_NONE, NULL, 0x0,
+       "Source IPv4 address", HFILL }},
+    { &hf_nbdgm_src_port,
+      { "Source Port",         "nbdgm.src.port",
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Source port", HFILL }}
+  };
+
+  static hf_register_info hf_nbss[] = {
+    { &hf_nbss_type,
+      { "Message Type",                "nbss.type",  
+       FT_UINT8, BASE_DEC, NULL, 0x0,
+       "NBSS message type", HFILL }},
+    { &hf_nbss_flags,
+      { "Flags",               "nbss.flags",  
+       FT_UINT8, BASE_HEX, NULL, 0x0,
+       "NBSS message flags", HFILL }}
+  };
+  static gint *ett[] = {
+    &ett_nbns,
+    &ett_nbns_qd,
+    &ett_nbns_flags,
+    &ett_nbns_nb_flags,
+    &ett_nbns_name_flags,
+    &ett_nbns_rr,
+    &ett_nbns_qry,
+    &ett_nbns_ans,
+    &ett_nbdgm,
+    &ett_nbss,
+    &ett_nbss_flags,
+  };
+  module_t *nbss_module;
+
+  proto_nbns = proto_register_protocol("NetBIOS Name Service", "NBNS", "nbns");
+  proto_register_field_array(proto_nbns, hf_nbns, array_length(hf_nbns));
+  
+  proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service",
+                                       "NBDS", "nbdgm");
+  proto_register_field_array(proto_nbdgm, hf_nbdgm, array_length(hf_nbdgm));
+
+  proto_nbss = proto_register_protocol("NetBIOS Session Service",
+                                      "NBSS", "nbss");
+  proto_register_field_array(proto_nbss, hf_nbss, array_length(hf_nbss));
+
+  proto_register_subtree_array(ett, array_length(ett));
+
+  nbss_module = prefs_register_protocol(proto_nbss, NULL);
+  prefs_register_bool_preference(nbss_module, "desegment_nbss_commands",
+    "Desegment all NBSS packets spanning multiple TCP segments",
+    "Whether NBSS dissector should desegment all packets spanning multiple TCP segments",
+    &nbss_desegment);
+}
+
+void
+proto_reg_handoff_nbt(void)
+{
+  dissector_handle_t nbns_handle, nbdgm_handle, nbss_handle;
+
+  nbns_handle = create_dissector_handle(dissect_nbns, proto_nbns);
+  dissector_add("udp.port", UDP_PORT_NBNS, nbns_handle);
+  nbdgm_handle = create_dissector_handle(dissect_nbdgm, proto_nbdgm);
+  dissector_add("udp.port", UDP_PORT_NBDGM, nbdgm_handle);
+  nbss_handle = create_dissector_handle(dissect_nbss, proto_nbss);
+  dissector_add("tcp.port", TCP_PORT_NBSS, nbss_handle);
+  dissector_add("tcp.port", TCP_PORT_CIFS, nbss_handle);
 }