Change dissect_ppp() to accept offset.
[obnox/wireshark/wip.git] / packet-nbns.c
index f37c082aee6a5a8a494ab450059d2cc7573ec717..c9ad53dc5f2159fc48b48415862fd605b596e443 100644 (file)
@@ -1,10 +1,10 @@
 /* packet-nbns.c
- * Routines for NetBIOS Name Service, Datagram Service, and Session Service
- * 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>
+ * Routines for NetBIOS-over-TCP packet disassembly (the name dates back
+ * to when it had only NBNS)
+ * Gilbert Ramirez <gram@xiexie.org>
+ * Much stuff added by Guy Harris <guy@alum.mit.edu>
  *
- * $Id: packet-nbns.c,v 1.17 1999/05/10 20:02:57 guy Exp $
+ * $Id: packet-nbns.c,v 1.38 2000/03/12 04:47:42 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
 #include <stdio.h>
 #include <string.h>
 #include <glib.h>
+
 #include "packet.h"
 #include "packet-dns.h"
-#include "util.h"
+#include "packet-netbios.h"
+#include "packet-smb.h"
+
+static int proto_nbns = -1;
+static int hf_nbns_response = -1;
+static int hf_nbns_query = -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;
 
 /* Packet structure taken from RFC 1002. See also RFC 1001.
  * Opcode, flags, and rcode treated as "flags", similarly to DNS,
@@ -142,51 +180,19 @@ nbns_type_name (int type)
        return "unknown";
 }
 
-/* "Canonicalize" a 16-character NetBIOS name by:
- *
- *     removing and saving the last byte;
- *
- *     stripping trailing blanks;
- *
- *     appending the trailing byte, as a hex number, in square brackets. */
-static char *
-canonicalize_netbios_name(char *nbname)
-{
-       char *pnbname;
-       u_char lastchar;
-
-       /* Get the last character of the name, as it's a special number
-        * indicating the type of the name, rather than part of the name
-        * *per se*. */
-       pnbname = nbname + 15;  /* point to the 16th character */
-       lastchar = *(unsigned char *)pnbname;
-
-       /* Now strip off any trailing blanks used to pad it to
-        * 16 bytes. */
-       while (pnbname > &nbname[0]) {
-               if (*(pnbname - 1) != ' ')
-                       break;          /* found non-blank character */
-               pnbname--;              /* blank - skip over it */
-       }
-
-       /* Replace the last character with its hex value, in square
-        * brackets, to make it easier to tell what it is. */
-       sprintf(pnbname, "[%02X]", lastchar);
-       pnbname += 4;
-       return pnbname;
-}
-
 static int
-get_nbns_name(const u_char *nbns_data_ptr, const u_char *pd,
-    int offset, char *name_ret)
+get_nbns_name(const u_char *pd, int offset, int nbns_data_offset,
+    char *name_ret, int *name_type_ret)
 {
        int name_len;
        char name[MAXDNAME];
-       char nbname[MAXDNAME+4];        /* 4 for [<last char>] */
+       char nbname[NETBIOS_NAME_LEN];
        char *pname, *pnbname, cname, cnbname;
+       int name_type;
+
+       name_len = get_dns_name(pd, offset, nbns_data_offset, name,
+           sizeof(name));
 
-       name_len = get_dns_name(nbns_data_ptr, pd, offset, name, sizeof(name));
-       
        /* OK, now undo the first-level encoding. */
        pname = &name[0];
        pnbname = &nbname[0];
@@ -226,48 +232,71 @@ get_nbns_name(const u_char *nbns_data_ptr, const u_char *pd,
                cnbname |= cname;
                pname++;
 
-               /* Store the character. */
-               *pnbname++ = cnbname;
+               /* Do we have room to store the character? */
+               if (pnbname < &nbname[NETBIOS_NAME_LEN]) {
+                       /* Yes - store the character. */
+                       *pnbname = cnbname;
+               }
+
+               /* We bump the pointer even if it's past the end of the
+                  name, so we keep track of how long the name is. */
+               pnbname++;
        }
 
        /* NetBIOS names are supposed to be exactly 16 bytes long. */
-       if (pnbname - nbname == 16) {
-               /* This one is; canonicalize its name. */
-               pnbname = canonicalize_netbios_name(nbname);
-       } else {
+       if (pnbname - nbname != NETBIOS_NAME_LEN) {
+               /* It's not. */
                sprintf(nbname, "Illegal NetBIOS name (%ld bytes long)",
                    (long)(pnbname - nbname));
                goto bad;
        }
+
+       /* This one is; make its name printable. */
+       name_type = process_netbios_name(nbname, name_ret);
+       name_ret += strlen(name_ret);
+       sprintf(name_ret, "<%02x>", name_type);
+       name_ret += 4;
        if (cname == '.') {
                /* We have a scope ID, starting at "pname"; append that to
                 * the decoded host name. */
-               strcpy(pnbname, pname);
-       } else {
-               /* Terminate the decoded host name. */
-               *pnbname = '\0';
+               strcpy(name_ret, pname);
        }
+       if (name_type_ret != NULL)
+               *name_type_ret = name_type;
+       return name_len;
 
 bad:
+       if (name_type_ret != NULL)
+               *name_type_ret = -1;
        strcpy (name_ret, nbname);
        return name_len;
 }
 
 
 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 *type_ret,
+get_nbns_name_type_class(const u_char *pd, 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(pd, offset, nbns_data_offset, name_ret,
+          name_type_ret);
        offset += name_len;
        
+       if (!BYTES_ARE_IN_FRAME(offset, 2)) {
+               /* We ran past the end of the captured data in the packet. */
+               return -1;
+       }
        type = pntohs(&pd[offset]);
        offset += 2;
+
+       if (!BYTES_ARE_IN_FRAME(offset, 2)) {
+               /* We ran past the end of the captured data in the packet. */
+               return -1;
+       }
        class = pntohs(&pd[offset]);
 
        *type_ret = type;
@@ -277,14 +306,27 @@ get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
        return name_len + 4;
 }
 
+static void
+add_name_and_type(proto_tree *tree, 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)",
+                   tag, name, netbios_name_type_descr(name_type));
+       } else {
+               proto_tree_add_text(tree, 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(const u_char *pd, int offset, int nbns_data_offset,
+    frame_data *fd, proto_tree *nbns_tree)
 {
        int len;
-       char name[MAXDNAME];
+       char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
        int name_len;
+       int name_type;
        int type;
        int class;
        char *class_name;
@@ -296,26 +338,34 @@ dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
 
        data_start = dptr = pd + offset;
 
-       len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
-           &name_len, &type, &class);
+       len = get_nbns_name_type_class(pd, offset, nbns_data_offset, name,
+           &name_len, &name_type, &type, &class);
+       if (len < 0) {
+               /* We ran past the end of the data in the packet. */
+               return 0;
+       }
        dptr += len;
 
        type_name = nbns_type_name(type);
        class_name = dns_class_name(class);
 
-       tq = proto_tree_add_item(nbns_tree, offset, len, "%s: type %s, class %s", 
-           name, type_name, class_name);
-       q_tree = proto_tree_new();
-       proto_item_add_subtree(tq, q_tree, ETT_NBNS_QD);
+       if (fd != NULL)
+               col_append_fstr(fd, COL_INFO, " %s %s", type_name, name);
+       if (nbns_tree != NULL) {
+               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);
 
-       proto_tree_add_item(q_tree, offset, name_len, "Name: %s", name);
-       offset += name_len;
+               add_name_and_type(q_tree, offset, name_len, "Name", name,
+                   name_type);
+               offset += name_len;
 
-       proto_tree_add_item(q_tree, offset, 2, "Type: %s", type_name);
-       offset += 2;
+               proto_tree_add_text(q_tree, offset, 2, "Type: %s", type_name);
+               offset += 2;
 
-       proto_tree_add_item(q_tree, offset, 2, "Class: %s", class_name);
-       offset += 2;
+               proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
+               offset += 2;
+       }
        
        return dptr - data_start;
 }
@@ -347,49 +397,48 @@ nbns_add_nbns_flags(proto_tree *nbns_tree, int offset, u_short flags,
                strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
                    "Unknown error"));
        }
-       tf = proto_tree_add_item(nbns_tree, offset, 2,
+       tf = proto_tree_add_text(nbns_tree, offset, 2,
                        "Flags: 0x%04x (%s)", flags, buf);
-       field_tree = proto_tree_new();
-       proto_item_add_subtree(tf, field_tree, ETT_NBNS_FLAGS);
-       proto_tree_add_item(field_tree, offset, 2, "%s",
+       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_item(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_enumerated_bitfield(flags, F_OPCODE,
                                2*8, opcode_vals, "%s"));
        if (flags & F_RESPONSE) {
-               proto_tree_add_item(field_tree, offset, 2,
+               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, offset, 2, "%s",
+       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_item(field_tree, offset, 2, "%s",
+       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"));
        if (flags & F_RESPONSE) {
-               proto_tree_add_item(field_tree, offset, 2,
+               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, offset, 2, "%s",
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_boolean_bitfield(flags, F_BROADCAST,
                                2*8,
                                "Broadcast packet",
                                "Not a broadcast packet"));
        if (flags & F_RESPONSE && !is_wack) {
-               proto_tree_add_item(field_tree, offset, 2,
+               proto_tree_add_text(field_tree, offset, 2,
                        "%s",
                        decode_enumerated_bitfield(flags, F_RCODE,
                                2*8,
@@ -418,16 +467,15 @@ nbns_add_nb_flags(proto_tree *rr_tree, int offset, u_short flags)
                strcat(buf, "group");
        else
                strcat(buf, "unique");
-       tf = proto_tree_add_item(rr_tree, offset, 2, "Flags: 0x%x (%s)", flags,
+       tf = proto_tree_add_text(rr_tree, offset, 2, "Flags: 0x%x (%s)", flags,
                        buf);
-       field_tree = proto_tree_new();
-       proto_item_add_subtree(tf, field_tree, ETT_NBNS_NB_FLAGS);
-       proto_tree_add_item(field_tree, offset, 2, "%s",
+       field_tree = proto_item_add_subtree(tf, ett_nbns_nb_flags);
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NB_FLAGS_G,
                                2*8,
                                "Group name",
                                "Unique name"));
-       proto_tree_add_item(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_enumerated_bitfield(flags, NB_FLAGS_ONT,
                                2*8, nb_flags_ont_vals, "%s"));
 }
@@ -460,34 +508,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_item(rr_tree, offset, 2, "Name flags: 0x%x (%s)",
+       tf = proto_tree_add_text(rr_tree, offset, 2, "Name flags: 0x%x (%s)",
                        flags, buf);
-       field_tree = proto_tree_new();
-       proto_item_add_subtree(tf, field_tree, ETT_NBNS_NAME_FLAGS);
-       proto_tree_add_item(field_tree, offset, 2, "%s",
+       field_tree = proto_item_add_subtree(tf, ett_nbns_name_flags);
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_G,
                                2*8,
                                "Group name",
                                "Unique name"));
-       proto_tree_add_item(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_enumerated_bitfield(flags, NAME_FLAGS_ONT,
                                2*8, name_flags_ont_vals, "%s"));
-       proto_tree_add_item(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_DRG,
                                2*8,
                                "Name is being deregistered",
                                "Name is not being deregistered"));
-       proto_tree_add_item(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_CNF,
                                2*8,
                                "Name is in conflict",
                                "Name is not in conflict"));
-       proto_tree_add_item(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_ACT,
                                2*8,
                                "Name is active",
                                "Name is not active"));
-       proto_tree_add_item(field_tree, offset, 2, "%s",
+       proto_tree_add_text(field_tree, offset, 2, "%s",
                        decode_boolean_bitfield(flags, NAME_FLAGS_PRM,
                                2*8,
                                "Permanent node name",
@@ -495,347 +542,508 @@ 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(const u_char *pd, int offset, int nbns_data_offset,
+    frame_data *fd, proto_tree *nbns_tree, int opcode)
 {
        int len;
-       char name[MAXDNAME];
+       char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME + 64];
        int name_len;
+       int name_type;
        int type;
        int class;
        char *class_name;
        char *type_name;
        const u_char *dptr;
+       int cur_offset;
        const u_char *data_start;
        u_int ttl;
        u_short data_len;
        u_short flags;
        proto_tree *rr_tree;
        proto_item *trr;
+       char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
+       u_int num_names;
+       char nbname[16+4+1];    /* 4 for [<last char>] */
+       u_short name_flags;
 
        data_start = dptr = pd + offset;
+       cur_offset = offset;
 
-       len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
-           &name_len, &type, &class);
+       len = get_nbns_name_type_class(pd, offset, nbns_data_offset, name,
+           &name_len, &name_type, &type, &class);
+       if (len < 0) {
+               /* We ran past the end of the data in the packet. */
+               return 0;
+       }
        dptr += len;
+       cur_offset += len;
 
        type_name = nbns_type_name(type);
        class_name = dns_class_name(class);
 
+       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+               /* We ran past the end of the captured data in the packet. */
+               return 0;
+       }
        ttl = pntohl(dptr);
        dptr += 4;
+       cur_offset += 4;
 
+       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+               /* We ran past the end of the captured data in the packet. */
+               return 0;
+       }
        data_len = pntohs(dptr);
        dptr += 2;
+       cur_offset += 2;
 
        switch (type) {
        case T_NB:              /* "NB" record */
-               trr = proto_tree_add_item(nbns_tree, offset,
+               if (fd != NULL) {
+                       if (opcode != OPCODE_WACK) {
+                               col_append_fstr(fd, COL_INFO, " %s %s",
+                                   type_name, ip_to_str((guint8 *)(dptr + 2)));
+                       }
+               }
+               if (nbns_tree == NULL)
+                       break;
+               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,
+               strcat(name, " (");
+               strcat(name, netbios_name_type_descr(name_type));
+               strcat(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);
                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 (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                                       /* We ran past the end of the captured
+                                          data in the packet. */
+                                       return 0;
+                               }
                                if (data_len < 2) {
-                                       proto_tree_add_item(rr_tree, offset,
+                                       proto_tree_add_text(rr_tree, cur_offset,
                                            data_len, "(incomplete entry)");
                                        break;
                                }
                                flags = pntohs(dptr);
                                dptr += 2;
-                               nbns_add_nbns_flags(rr_tree, offset, flags, 1);
-                               offset += 2;
+                               nbns_add_nbns_flags(rr_tree, cur_offset,
+                                   flags, 1);
+                               cur_offset += 2;
                                data_len -= 2;
                        } else {
+                               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                                       /* We ran past the end of the captured
+                                          data in the packet. */
+                                       return 0;
+                               }
                                if (data_len < 2) {
-                                       proto_tree_add_item(rr_tree, offset,
+                                       proto_tree_add_text(rr_tree, cur_offset,
                                            data_len, "(incomplete entry)");
                                        break;
                                }
                                flags = pntohs(dptr);
                                dptr += 2;
-                               nbns_add_nb_flags(rr_tree, offset, flags);
-                               offset += 2;
+                               nbns_add_nb_flags(rr_tree, cur_offset, flags);
+                               cur_offset += 2;
                                data_len -= 2;
 
+                               if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+                                       /* We ran past the end of the captured
+                                          data in the packet. */
+                                       return 0;
+                               }
                                if (data_len < 4) {
-                                       proto_tree_add_item(rr_tree, offset,
+                                       proto_tree_add_text(rr_tree, cur_offset,
                                            data_len, "(incomplete entry)");
                                        break;
                                }
-                               proto_tree_add_item(rr_tree, offset, 4,
+                               proto_tree_add_text(rr_tree, cur_offset, 4,
                                    "Addr: %s",
                                    ip_to_str((guint8 *)dptr));
                                dptr += 4;
-                               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_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       num_names = *dptr;
-                       dptr += 1;
-                       proto_tree_add_item(rr_tree, offset, 2,
-                           "Number of names: %u", num_names);
-                       offset += 1;
-
-                       while (num_names != 0) {
-                               if (data_len < 16) {
-                                       proto_tree_add_item(rr_tree, offset,
-                                           data_len, "(incomplete entry)");
-                                       goto out;
-                               }
-                               memcpy(nbname, dptr, 16);
-                               dptr += 16;
-                               canonicalize_netbios_name(nbname);
-                               proto_tree_add_item(rr_tree, offset, 16,
-                                   "Name: %s", nbname);
-                               offset += 16;
-                               data_len -= 16;
-
-                               if (data_len < 2) {
-                                       proto_tree_add_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(rr_tree, offset, 1,
-                           "Jumpers: 0x%x", *dptr);
-                       dptr += 1;
-                       offset += 1;
-                       data_len -= 1;
-
-                       if (data_len < 1) {
-                               proto_tree_add_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(rr_tree, offset, 1,
-                           "Test result: 0x%x", *dptr);
-                       dptr += 1;
-                       offset += 1;
-                       data_len -= 1;
-
-                       if (data_len < 2) {
-                               proto_tree_add_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(rr_tree, offset, 2,
-                           "Version number: 0x%x", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(rr_tree, offset, 2,
-                           "Number of CRCs: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(rr_tree, offset, 2,
-                           "Number of collisions: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
+               if (fd != NULL)
+                       col_append_fstr(fd, COL_INFO, " %s", type_name);
+               if (nbns_tree == NULL)
+                       break;
+               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);
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 1) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               num_names = *dptr;
+               dptr += 1;
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Number of names: %u", num_names);
+               cur_offset += 1;
+
+               while (num_names != 0) {
+                       if (!BYTES_ARE_IN_FRAME(cur_offset, NETBIOS_NAME_LEN)) {
+                               /* We ran past the end of the captured
+                                  data in the packet. */
+                               return 0;
                        }
-                       proto_tree_add_item(rr_tree, offset, 2,
-                           "Number of retransmits: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
-                       if (data_len < 2) {
-                               proto_tree_add_item(rr_tree, offset,
+                       if (data_len < NETBIOS_NAME_LEN) {
+                               proto_tree_add_text(rr_tree, cur_offset,
                                    data_len, "(incomplete entry)");
-                               break;
+                               goto out;
                        }
-                       proto_tree_add_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
+                       memcpy(nbname, dptr, NETBIOS_NAME_LEN);
+                       dptr += NETBIOS_NAME_LEN;
+                       name_type = process_netbios_name(nbname,
+                           name_str);
+                       proto_tree_add_text(rr_tree, 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 (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                               /* We ran past the end of the captured
+                                  data in the packet. */
+                               return 0;
                        }
-                       proto_tree_add_item(rr_tree, offset, 2,
-                           "Number of command blocks: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
-
                        if (data_len < 2) {
-                               proto_tree_add_item(rr_tree, offset,
+                               proto_tree_add_text(rr_tree, cur_offset,
                                    data_len, "(incomplete entry)");
-                               break;
+                               goto out;
                        }
-                       proto_tree_add_item(rr_tree, offset, 2,
-                           "Number of pending sessions: %u", pntohs(dptr));
+                       name_flags = pntohs(dptr);
                        dptr += 2;
-                       offset += 2;
+                       nbns_add_name_flags(rr_tree, cur_offset, name_flags);
+                       cur_offset += 2;
                        data_len -= 2;
 
-                       if (data_len < 2) {
-                               proto_tree_add_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(rr_tree, offset, 2,
-                           "Max number of pending sessions: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-
-                       proto_tree_add_item(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_item(rr_tree, offset,
-                                   data_len, "(incomplete entry)");
-                               break;
-                       }
-                       proto_tree_add_item(rr_tree, offset, 2,
-                           "Session data packet size: %u", pntohs(dptr));
-                       dptr += 2;
-                       offset += 2;
-                       data_len -= 2;
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 6)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 6) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 6,
+                   "Unit ID: %s",
+                   ether_to_str((guint8 *)dptr));
+               dptr += 6;
+               cur_offset += 6;
+               data_len -= 6;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 1) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 1,
+                   "Jumpers: 0x%x", *dptr);
+               dptr += 1;
+               cur_offset += 1;
+               data_len -= 1;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 1) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 1,
+                   "Test result: 0x%x", *dptr);
+               dptr += 1;
+               cur_offset += 1;
+               data_len -= 1;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Version number: 0x%x", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Period of statistics: 0x%x", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Number of CRCs: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Number of alignment errors: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Number of collisions: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Number of send aborts: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 4) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 4,
+                   "Number of good sends: %u", pntohl(dptr));
+               dptr += 4;
+               cur_offset += 4;
+               data_len -= 4;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 4) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 4,
+                   "Number of good receives: %u", pntohl(dptr));
+               dptr += 4;
+               cur_offset += 4;
+               data_len -= 4;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Number of retransmits: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Number of no resource conditions: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
                }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Number of command blocks: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Number of pending sessions: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Max number of pending sessions: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Max total sessions possible: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
+
+               if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+                       /* We ran past the end of the captured
+                          data in the packet. */
+                       return 0;
+               }
+               if (data_len < 2) {
+                       proto_tree_add_text(rr_tree, cur_offset,
+                           data_len, "(incomplete entry)");
+                       break;
+               }
+               proto_tree_add_text(rr_tree, cur_offset, 2,
+                   "Session data packet size: %u", pntohs(dptr));
+               dptr += 2;
+               cur_offset += 2;
+               data_len -= 2;
        out:
                break;
 
        default:
-               trr = proto_tree_add_item(nbns_tree, offset,
+               if (fd != NULL)
+                       col_append_fstr(fd, COL_INFO, " %s", type_name);
+               if (nbns_tree == NULL)
+                       break;
+               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,
+               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);
-               proto_tree_add_item(rr_tree, offset, data_len, "Data");
+               proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
                break;
        }
        dptr += data_len;
@@ -844,20 +1052,30 @@ dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
 }
 
 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(const u_char *pd, int cur_off, int nbns_data_offset,
+    int count, frame_data *fd, 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_item(nbns_tree, start_off, 0, "Queries");
-       qatree = proto_tree_new();
-       proto_item_add_subtree(ti, qatree, 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, start_off, 0, "Queries");
+               qatree = proto_item_add_subtree(ti, ett_nbns_qry);
+       }
+       while (count-- > 0) {
+               add_off = dissect_nbns_query(pd, cur_off, nbns_data_offset,
+                   fd, qatree);
+               if (add_off <= 0) {
+                       /* We ran past the end of the captured data in the
+                          packet. */
+                       break;
+               }
+               cur_off += add_off;
+       }
+       if (ti != NULL)
+               proto_item_set_len(ti, cur_off - start_off);
 
        return cur_off - start_off;
 }
@@ -865,34 +1083,52 @@ 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(const u_char *pd, int cur_off, int nbns_data_offset,
+    int count, frame_data *fd, 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_item(nbns_tree, start_off, 0, name);
-       qatree = proto_tree_new();
-       proto_item_add_subtree(ti, qatree, 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, start_off, 0, name);
+               qatree = proto_item_add_subtree(ti, ett_nbns_ans);
+       }
+       while (count-- > 0) {
+               add_off = dissect_nbns_answer(pd, cur_off, nbns_data_offset,
+                                       fd, qatree, opcode);
+               if (add_off <= 0) {
+                       /* We ran past the end of the captured data in the
+                          packet. */
+                       break;
+               }
+               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)
 {
-       const u_char            *nbns_data_ptr;
-       proto_tree              *nbns_tree;
+       int                     nbns_data_offset;
+       proto_tree              *nbns_tree = NULL;
        proto_item              *ti;
        guint16                 id, flags, quest, ans, auth, add;
        int                     cur_off;
 
-       nbns_data_ptr = &pd[offset];
+       nbns_data_offset = offset;
+
+       if (check_col(fd, COL_PROTOCOL))
+               col_add_str(fd, COL_PROTOCOL, "NBNS");
+
+       if (pi.captured_len < NBNS_HDRLEN) {
+               col_add_str(fd, COL_INFO, "Short NBNS packet");
+               dissect_data(pd, offset, fd, tree);
+               return;
+       }
 
        /* To do: check for runts, errs, etc. */
        id    = pntohs(&pd[offset + NBNS_ID]);
@@ -902,59 +1138,81 @@ dissect_nbns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
        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)"),
                    (flags & F_RESPONSE) ? " response" : "");
+       } else {
+               /* Set "fd" to NULL; we pass a NULL "fd" 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(fd, COL_INFO)" is more expensive than a check
+                  that a pointer isn't NULL). */
+               fd = NULL;
        }
 
        if (tree) {
-               ti = proto_tree_add_item(tree, offset, END_OF_FRAME,
-                               "NetBIOS Name Service");
-               nbns_tree = proto_tree_new();
-               proto_item_add_subtree(ti, nbns_tree, ETT_NBNS);
+               ti = proto_tree_add_item(tree, proto_nbns, offset, END_OF_FRAME, NULL);
+               nbns_tree = proto_item_add_subtree(ti, ett_nbns);
+
+               if (flags & F_RESPONSE) {
+                       proto_tree_add_item_hidden(nbns_tree, hf_nbns_response, 
+                                            0, 0, TRUE);
+               } else {
+                       proto_tree_add_item_hidden(nbns_tree, hf_nbns_query, 
+                                            0, 0, TRUE);
+               }
 
-               proto_tree_add_item(nbns_tree, offset + NBNS_ID, 2,
-                               "Transaction ID: 0x%04X", id);
+               proto_tree_add_item(nbns_tree, hf_nbns_transaction_id,
+                                   offset + NBNS_ID, 2, id);
 
                nbns_add_nbns_flags(nbns_tree, offset + NBNS_FLAGS, flags, 0);
-               proto_tree_add_item(nbns_tree, offset + NBNS_QUEST, 2,
-                                       "Questions: %d",
-                                       quest);
-               proto_tree_add_item(nbns_tree, offset + NBNS_ANS, 2,
-                                       "Answer RRs: %d",
-                                       ans);
-               proto_tree_add_item(nbns_tree, offset + NBNS_AUTH, 2,
-                                       "Authority RRs: %d",
-                                       auth);
-               proto_tree_add_item(nbns_tree, offset + NBNS_ADD, 2,
-                                       "Additional RRs: %d",
-                                       add);
-
-               cur_off = offset + NBNS_HDRLEN;
+               proto_tree_add_item(nbns_tree, hf_nbns_count_questions,
+                                   offset + NBNS_QUEST, 2, quest);
+               proto_tree_add_item(nbns_tree, hf_nbns_count_answers,
+                                   offset + NBNS_ANS, 2, ans);
+               proto_tree_add_item(nbns_tree, hf_nbns_count_auth_rr,
+                                   offset + NBNS_AUTH, 2, auth);
+               proto_tree_add_item(nbns_tree, hf_nbns_count_add_rr,
+                                   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(pd, cur_off,
+                   nbns_data_offset, quest,
+                   (!(flags & F_RESPONSE) ? fd : 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(pd, cur_off,
+                       nbns_data_offset, ans,
+                       ((flags & F_RESPONSE) ? fd : NULL), nbns_tree,
+                       flags & F_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, 
+                       cur_off += dissect_answer_records(pd, cur_off,
+                                       nbns_data_offset,
+                                       auth, NULL, nbns_tree,
                                        flags & F_OPCODE,
                                        "Authoritative nameservers");
 
                if (add > 0)
-                       cur_off += dissect_answer_records(nbns_data_ptr,
-                                       add, pd, cur_off, nbns_tree, 
+                       cur_off += dissect_answer_records(pd, cur_off,
+                                       nbns_data_offset,
+                                       add, NULL, nbns_tree,
                                        flags & F_OPCODE,
                                        "Additional records");
        }
@@ -983,11 +1241,12 @@ struct nbdgm_header {
 void
 dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
 {
-       proto_tree              *nbdgm_tree;
+       proto_tree              *nbdgm_tree = NULL;
        proto_item              *ti;
        struct nbdgm_header     header;
        int                     flags;
        int                     message_index;
+       int                     max_data = pi.captured_len - offset;
 
        char *message[] = {
                "Unknown",
@@ -1016,7 +1275,8 @@ dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
 
        char *yesno[] = { "No", "Yes" };
 
-       char name[32];
+       char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
+       int name_type;
        int len;
 
        header.msg_type = pd[offset];
@@ -1045,73 +1305,98 @@ dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
        }
 
        if (check_col(fd, COL_PROTOCOL))
-               col_add_str(fd, COL_PROTOCOL, "NBDS (UDP)");
+               col_add_str(fd, COL_PROTOCOL, "NBDS");
        if (check_col(fd, COL_INFO)) {
                col_add_fstr(fd, COL_INFO, "%s", message[message_index]);
        }
 
        if (tree) {
-               ti = proto_tree_add_item(tree, offset, header.dgm_length,
-                               "NetBIOS Datagram Service");
-               nbdgm_tree = proto_tree_new();
-               proto_item_add_subtree(ti, nbdgm_tree, ETT_NBDGM);
-
-               proto_tree_add_item(nbdgm_tree, offset, 1, "Message Type: %s",
-                               message[message_index]);
-               proto_tree_add_item(nbdgm_tree, offset+1, 1, "More fragments follow: %s",
-                               yesno[header.flags.more]);
-               proto_tree_add_item(nbdgm_tree, offset+1, 1, "This is first fragment: %s",
-                               yesno[header.flags.first]);
-               proto_tree_add_item(nbdgm_tree, offset+1, 1, "Node Type: %s",
-                               node[header.flags.node_type]);
-
-               proto_tree_add_item(nbdgm_tree, offset+2, 2, "Datagram ID: 0x%04X",
-                               header.dgm_id);
-               proto_tree_add_item(nbdgm_tree, offset+4, 4, "Source IP: %s",
-                               ip_to_str((guint8 *)&header.src_ip));
-               proto_tree_add_item(nbdgm_tree, offset+8, 2, "Source Port: %d",
-                               header.src_port);
-
-               offset += 10;
-
-               if (header.msg_type == 0x10 ||
-                               header.msg_type == 0x11 || header.msg_type == 0x12) {
-
-                       proto_tree_add_item(nbdgm_tree, offset, 2,
+               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_uint_format(nbdgm_tree, hf_nbdgm_type,
+                                          offset, 1, 
+                                          header.msg_type,   
+                                          "Message Type: %s",
+                                          message[message_index]);
+               proto_tree_add_boolean_format(nbdgm_tree, hf_nbdgm_fragment,
+                                          offset+1, 1, 
+                                          header.flags.more,
+                                          "More fragments follow: %s",
+                                          yesno[header.flags.more]);
+               proto_tree_add_boolean_format(nbdgm_tree, hf_nbdgm_first,
+                                          offset+1, 1, 
+                                          header.flags.first,
+                                          "This is first fragment: %s",
+                                          yesno[header.flags.first]);
+               proto_tree_add_uint_format(nbdgm_tree, hf_nbdgm_node_type,
+                                          offset+1, 1, 
+                                          header.flags.node_type,
+                                          "Node Type: %s",
+                                          node[header.flags.node_type]);
+
+               proto_tree_add_item(nbdgm_tree, hf_nbdgm_datagram_id,
+                                   offset+2, 2, header.dgm_id);
+               proto_tree_add_item(nbdgm_tree, hf_nbdgm_src_ip,
+                                   offset+4, 4, header.src_ip);
+               proto_tree_add_item(nbdgm_tree, hf_nbdgm_src_port,
+                                   offset+8, 2, header.src_port);
+
+       }
+
+       offset += 10;
+       max_data -= 10;
+
+       if (header.msg_type == 0x10 ||
+                       header.msg_type == 0x11 || header.msg_type == 0x12) {
+
+               if (tree) {
+                       proto_tree_add_text(nbdgm_tree, offset, 2,
                                        "Datagram length: %d bytes", header.dgm_length);
-                       proto_tree_add_item(nbdgm_tree, offset+2, 2,
+                       proto_tree_add_text(nbdgm_tree, offset+2, 2,
                                        "Packet offset: %d bytes", header.pkt_offset);
+               }
 
-                       offset += 4;
-
-                       /* Source name */
-                       len = get_nbns_name(&pd[offset], pd, offset, name);
+               offset += 4;
+               max_data -= 4;
 
-                       proto_tree_add_item(nbdgm_tree, offset, len, "Source name: %s",
-                                       name);
-                       offset += len;
+               /* Source name */
+               len = get_nbns_name(pd, offset, offset, name, &name_type);
 
-                       /* Destination name */
-                       len = get_nbns_name(&pd[offset], pd, offset, name);
+               if (tree) {
+                       add_name_and_type(nbdgm_tree, offset, len,
+                           "Source name", name, name_type);
+               }
+               offset += len;
+               max_data -= len;
 
-                       proto_tree_add_item(nbdgm_tree, offset, len, "Destination name: %s",
-                                       name);
-                       offset += len;
+               /* Destination name */
+               len = get_nbns_name(pd, offset, offset, name, &name_type);
 
-                       /* here we can pass the packet off to the next protocol */
-                       dissect_data(pd, offset, fd, nbdgm_tree);
+               if (tree) {
+                       add_name_and_type(nbdgm_tree, offset, len,
+                           "Destination name", name, name_type);
                }
-               else if (header.msg_type == 0x13) {
-                       proto_tree_add_item(nbdgm_tree, offset, 1, "Error code: %s",
+               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) {
+               if (tree) {
+                       proto_tree_add_text(nbdgm_tree, 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) {
-                       /* Destination name */
-                       len = get_nbns_name(&pd[offset], pd, offset, name);
-
-                       proto_tree_add_item(nbdgm_tree, offset, len, "Destination name: %s",
-                                       name);
+       }
+       else if (header.msg_type == 0x14 ||
+                       header.msg_type == 0x15 || header.msg_type == 0x16) {
+               /* Destination name */
+               len = get_nbns_name(pd, offset, offset, name, &name_type);
+
+               if (tree) {
+                       add_name_and_type(nbdgm_tree, offset, len,
+                           "Destination name", name, name_type);
                }
        }
 }
@@ -1168,7 +1453,8 @@ dissect_nbss_packet(const u_char *pd, int offset, frame_data *fd, proto_tree *tr
        guint8          flags;
        guint16         length;
        int             len;
-       char            name[32];
+       char            name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
+       int             name_type;
 
        msg_type = pd[offset];
        flags = pd[offset + 1];
@@ -1177,22 +1463,23 @@ dissect_nbss_packet(const u_char *pd, int offset, frame_data *fd, proto_tree *tr
                length += 65536;
 
        if (tree) {
-         ti = proto_tree_add_item(tree, offset, length + 4,
-                                  "NetBIOS Session Service");
-         nbss_tree = proto_tree_new();
-         proto_item_add_subtree(ti, nbss_tree, ETT_NBSS);
+         ti = proto_tree_add_item(tree, proto_nbss, offset, length + 4, NULL);
+         nbss_tree = proto_item_add_subtree(ti, ett_nbss);
          
-         proto_tree_add_item(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,
+                                    offset, 1, 
+                                    msg_type,
+                                    "Message Type: %s",
+                                    val_to_str(msg_type, message_types, 
+                                               "Unknown (%x)"));
        }
 
        offset += 1;
 
        if (tree) {
-         tf = proto_tree_add_item(nbss_tree, offset, 1, "Flags: 0x%04x", flags);
-         field_tree = proto_tree_new();
-         proto_item_add_subtree(tf, field_tree, ETT_NBSS_FLAGS);
-         proto_tree_add_item(field_tree, offset, 1, "%s",
+         tf = proto_tree_add_item(nbss_tree, hf_nbss_flags, offset, 1, flags);
+         field_tree = proto_item_add_subtree(tf, ett_nbss_flags);
+         proto_tree_add_text(field_tree, offset, 1, "%s",
                              decode_boolean_bitfield(flags, NBSS_FLAGS_E,
                                                      8, "Add 65536 to length", "Add 0 to length"));
        }
@@ -1200,7 +1487,7 @@ dissect_nbss_packet(const u_char *pd, int offset, frame_data *fd, proto_tree *tr
        offset += 1;
 
        if (tree) {
-         proto_tree_add_item(nbss_tree, offset, 2, "Length: %u", length);
+         proto_tree_add_text(nbss_tree, offset, 2, "Length: %u", length);
        }
 
        offset += 2;
@@ -1208,37 +1495,37 @@ dissect_nbss_packet(const u_char *pd, int offset, frame_data *fd, proto_tree *tr
        switch (msg_type) {
 
        case SESSION_REQUEST:
-         len = get_nbns_name(&pd[offset], pd, offset, name);
+         len = get_nbns_name(pd, offset, offset, name, &name_type);
          if (tree)
-           proto_tree_add_item(nbss_tree, offset, len,
-                               "Called name: %s", name);
+           add_name_and_type(nbss_tree, offset, len,
+                               "Called name", name, name_type);
          offset += len;
 
-         len = get_nbns_name(&pd[offset], pd, offset, name);
+         len = get_nbns_name(pd, offset, offset, name, &name_type);
          
          if (tree)
-           proto_tree_add_item(nbss_tree, offset, len,
-                               "Calling name: %s", name);
+           add_name_and_type(nbss_tree, offset, len,
+                               "Calling name", name, name_type);
 
          break;
 
        case NEGATIVE_SESSION_RESPONSE:
          if (tree) 
-           proto_tree_add_item(nbss_tree, offset, 1,
+           proto_tree_add_text(nbss_tree, offset, 1,
                                "Error code: %s",
                                val_to_str(pd[offset], error_codes, "Unknown (%x)"));
          break;
 
        case RETARGET_SESSION_RESPONSE:
          if (tree)
-           proto_tree_add_item(nbss_tree, offset, 4,
+           proto_tree_add_text(nbss_tree, offset, 4,
                                "Retarget IP address: %s",
                                ip_to_str((guint8 *)&pd[offset]));
          
          offset += 4;
 
          if (tree)
-           proto_tree_add_item(nbss_tree, offset, 2,
+           proto_tree_add_text(nbss_tree, offset, 2,
                                "Retarget port: %u", pntohs(&pd[offset]));
 
          break;
@@ -1257,12 +1544,13 @@ dissect_nbss_packet(const u_char *pd, int offset, frame_data *fd, proto_tree *tr
 }
 
 void
-dissect_nbss(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
+dissect_nbss(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
 {
        guint8          msg_type;
        guint8          flags;
        guint16         length;
        int             len;
+       int             max_data;
 
        msg_type = pd[offset];
        flags = pd[offset + 1];
@@ -1270,17 +1558,150 @@ dissect_nbss(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int
        if (flags & NBSS_FLAGS_E)
                length += 65536;
 
+       /*
+        * XXX - we should set this based on both "pi.captured_len"
+        * and "length"....
+        */
+       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 != POSITIVE_SESSION_RESPONSE) &&
+            (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");
+         if (check_col(fd, COL_INFO)) {
+           col_add_fstr(fd, COL_INFO, "NBSS Continuation Message");
+         }
+
+         if (tree)
+           proto_tree_add_text(tree, offset, max_data, "Continuation data");
+
+         return;
+       }
+#endif
+
        if (check_col(fd, COL_PROTOCOL))
-               col_add_str(fd, COL_PROTOCOL, "NBSS (TCP)");
+               col_add_str(fd, COL_PROTOCOL, "NBSS");
        if (check_col(fd, COL_INFO)) {
                col_add_fstr(fd, COL_INFO,
                    val_to_str(msg_type, message_types, "Unknown (%x)"));
        }
 
-       while (max_data > 0) { 
-         len = dissect_nbss_packet(pd, offset, fd, tree, max_data);
-         offset += len;
-         max_data -= len;
+       while (max_data > 0) {
+               len = dissect_nbss_packet(pd, offset, fd, tree, max_data);
+               offset += len;
+               max_data -= len;
        }
 
 }
+
+void
+proto_register_nbt(void)
+{
+
+  static hf_register_info hf_nbns[] = {
+    { &hf_nbns_response,
+      { "Response",            "nbns.response",  
+       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+       "TRUE if NBNS response" }},
+    { &hf_nbns_query,
+      { "Query",               "nbns.query",  
+       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+       "TRUE if NBNS query" }},
+    { &hf_nbns_transaction_id,
+      { "Transaction ID",              "nbns.id",  
+       FT_UINT16, BASE_HEX, NULL, 0x0,
+       "Identification of transaction" }},
+    { &hf_nbns_count_questions,
+      { "Questions",           "nbns.count.queries",  
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Number of queries in packet" }},
+    { &hf_nbns_count_answers,
+      { "Answer RRs",          "nbns.count.answers",  
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Number of answers in packet" }},
+    { &hf_nbns_count_auth_rr,
+      { "Authority RRs",               "nbns.count.auth_rr",  
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Number of authoritative records in packet" }},
+    { &hf_nbns_count_add_rr,
+      { "Additional RRs",              "nbns.count.add_rr",  
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Number of additional records in packet" }}
+  };
+
+  static hf_register_info hf_nbdgm[] = {
+    { &hf_nbdgm_type,
+      { "Message Type",                "nbdgm.type",  
+       FT_UINT8, BASE_DEC, NULL, 0x0,
+       "NBDGM message type" }},
+    { &hf_nbdgm_fragment,
+      { "Fragmented",          "nbdgm.next",  
+       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+       "TRUE if more fragments follow" }},
+    { &hf_nbdgm_first,
+      { "First fragment",      "nbdgm.first",  
+       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+       "TRUE if first fragment" }},
+    { &hf_nbdgm_node_type,
+      { "Node Type",           "nbdgm.node_type",  
+       FT_UINT8, BASE_DEC, NULL, 0x0,
+       "Node type" }},
+    { &hf_nbdgm_datagram_id,
+      { "Datagram ID",         "nbdgm.dgram_id",  
+       FT_UINT16, BASE_HEX, NULL, 0x0,
+       "Datagram identifier" }},
+    { &hf_nbdgm_src_ip,
+      { "Source IP",           "nbdgm.src.ip",  
+       FT_IPv4, BASE_NONE, NULL, 0x0,
+       "Source IPv4 address" }},
+    { &hf_nbdgm_src_port,
+      { "Source Port",         "nbdgm.src.port",
+       FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Source port" }}
+  };
+
+  static hf_register_info hf_nbss[] = {
+    { &hf_nbss_type,
+      { "Message Type",                "nbss.type",  
+       FT_UINT8, BASE_DEC, NULL, 0x0,
+       "NBSS message type" }},
+    { &hf_nbss_flags,
+      { "Flags",               "nbss.flags",  
+       FT_UINT8, BASE_HEX, NULL, 0x0,
+       "NBSS message flags" }}
+  };
+  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,
+  };
+
+  proto_nbns = proto_register_protocol("NetBIOS Name Service", "nbns");
+  proto_register_field_array(proto_nbns, hf_nbns, array_length(hf_nbns));
+  
+  proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service", "nbdgm");
+  proto_register_field_array(proto_nbdgm, hf_nbdgm, array_length(hf_nbdgm));
+
+  proto_nbss = proto_register_protocol("NetBIOS Session Service", "nbss");
+  proto_register_field_array(proto_nbss, hf_nbss, array_length(hf_nbss));
+
+  proto_register_subtree_array(ett, array_length(ett));
+}