There's no need to keep a "FILE *" for the file being printed to in a
[obnox/wireshark/wip.git] / packet-nbns.c
index eae3224087e225bb7f70af6a2ea80258eb99475a..39ef694a19d5022bdb3b60c74b8286e1d1ef5162 100644 (file)
@@ -3,22 +3,22 @@
  * to when it had only NBNS)
  * Guy Harris <guy@alum.mit.edu>
  *
- * $Id: packet-nbns.c,v 1.74 2002/02/28 23:09:03 guy Exp $
+ * $Id: packet-nbns.c,v 1.82 2004/01/06 02:42:50 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * 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
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
 #include <stdio.h>
 #include <string.h>
 #include <glib.h>
 #include "prefs.h"
 
 static int proto_nbns = -1;
-static int hf_nbns_response = -1;
-static int hf_nbns_query = -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;
@@ -118,6 +121,7 @@ static gboolean nbss_desegment = TRUE;
 /* 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 */
@@ -125,24 +129,77 @@ static gboolean nbss_desegment = TRUE;
 #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
@@ -173,17 +230,6 @@ static gboolean nbss_desegment = TRUE;
 
 #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)
 {
@@ -193,7 +239,7 @@ nbns_type_name (int type)
        case T_NBSTAT:
                return "NBSTAT";
        }
-       
+
        return "unknown";
 }
 
@@ -304,7 +350,7 @@ get_nbns_name_type_class(tvbuff_t *tvb, int offset, int nbns_data_offset,
        name_len = get_nbns_name(tvb, offset, nbns_data_offset, name_ret,
           name_type_ret);
        offset += name_len;
-       
+
        type = tvb_get_ntohs(tvb, offset);
        offset += 2;
 
@@ -373,88 +419,61 @@ dissect_nbns_query(tvbuff_t *tvb, int offset, int nbns_data_offset,
                proto_tree_add_text(q_tree, tvb, offset, 2, "Class: %s", class_name);
                offset += 2;
        }
-       
+
        return data_offset - data_start;
 }
 
 static void
-nbns_add_nbns_flags(proto_tree *nbns_tree, tvbuff_t *tvb, int offset,
-    u_short flags, int is_wack)
+nbns_add_nbns_flags(column_info *cinfo, 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 = (guint16) ((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"));
+
+               if ((flags & F_RCODE) && check_col(cinfo, COL_INFO))
+                       col_append_fstr(cinfo, COL_INFO, ", %s",
+                                       val_to_str(flags & F_RCODE, rcode_vals,
+                                                  "Unknown error"));
        }
-       tf = proto_tree_add_text(nbns_tree, tvb, offset, 2,
-                       "Flags: 0x%04x (%s)", flags, buf);
+       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_text(field_tree, tvb, offset, 2, "%s",
-                       decode_boolean_bitfield(flags, F_RESPONSE,
-                               2*8, "Response", "Query"));
-       proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
-                       decode_enumerated_bitfield(flags, F_OPCODE,
-                               2*8, opcode_vals, "%s"));
+       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, tvb, 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, tvb, offset, 2, "%s",
-                       decode_boolean_bitfield(flags, F_TRUNCATED,
-                               2*8,
-                               "Message is truncated",
-                               "Message is not truncated"));
-       proto_tree_add_text(field_tree, tvb, 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, tvb, 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, tvb, 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, tvb, 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, tvbuff_t *tvb, 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;
@@ -489,7 +508,7 @@ nbns_add_nb_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset, u_short flags)
 
 static void
 nbns_add_name_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset,
-    u_short flags)
+    gushort flags)
 {
        char buf[128+1];
        proto_item *field_tree;
@@ -564,15 +583,15 @@ dissect_nbns_answer(tvbuff_t *tvb, int offset, int nbns_data_offset,
        int data_offset;
        int cur_offset;
        int data_start;
-       u_int ttl;
-       u_short data_len;
-       u_short flags;
+       guint ttl;
+       gushort data_len;
+       gushort flags;
        proto_tree *rr_tree;
        proto_item *trr;
        char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
-       u_int num_names;
+       guint num_names;
        char nbname[16+4+1];    /* 4 for [<last char>] */
-       u_short name_flags;
+       gushort name_flags;
 
        data_start = data_offset = offset;
        cur_offset = offset;
@@ -624,7 +643,7 @@ dissect_nbns_answer(tvbuff_t *tvb, int offset, int nbns_data_offset,
                                        break;
                                }
                                flags = tvb_get_ntohs(tvb, cur_offset);
-                               nbns_add_nbns_flags(rr_tree, tvb, cur_offset,
+                               nbns_add_nbns_flags(cinfo, rr_tree, tvb, cur_offset,
                                    flags, 1);
                                cur_offset += 2;
                                data_len -= 2;
@@ -913,7 +932,7 @@ dissect_nbns_answer(tvbuff_t *tvb, int offset, int nbns_data_offset,
                cur_offset += data_len;
                break;
        }
-       
+
        return cur_offset - data_start;
 }
 
@@ -924,7 +943,7 @@ dissect_query_records(tvbuff_t *tvb, int cur_off, int nbns_data_offset,
        int start_off, add_off;
        proto_tree *qatree = NULL;
        proto_item *ti = NULL;
-       
+
        start_off = cur_off;
        if (nbns_tree != NULL) {
                ti = proto_tree_add_text(nbns_tree, tvb, start_off, -1, "Queries");
@@ -951,7 +970,7 @@ dissect_answer_records(tvbuff_t *tvb, int cur_off, int nbns_data_offset,
        int start_off, add_off;
        proto_tree *qatree = NULL;
        proto_item *ti = NULL;
-       
+
        start_off = cur_off;
        if (nbns_tree != NULL) {
                ti = proto_tree_add_text(nbns_tree, tvb, start_off, -1, name);
@@ -975,7 +994,7 @@ dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        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_offset = offset;
@@ -988,11 +1007,12 @@ dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        /* To do: check for runts, errs, etc. */
        id    = tvb_get_ntohs(tvb, offset + NBNS_ID);
        flags = tvb_get_ntohs(tvb, offset + NBNS_FLAGS);
+       opcode = (guint16) ((flags & F_OPCODE) >> OPCODE_SHIFT);
+       rcode  = (guint16)  (flags & F_RCODE);
 
        if (check_col(pinfo->cinfo, COL_INFO)) {
                col_add_fstr(pinfo->cinfo, COL_INFO, "%s%s",
-                   val_to_str(flags & F_OPCODE, opcode_vals,
-                     "Unknown operation (%x)"),
+                   val_to_str(opcode, opcode_vals, "Unknown operation (%u)"),
                    (flags & F_RESPONSE) ? " response" : "");
                cinfo = pinfo->cinfo;
        } else {
@@ -1009,18 +1029,10 @@ dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                    FALSE);
                nbns_tree = proto_item_add_subtree(ti, ett_nbns);
 
-               if (flags & F_RESPONSE) {
-                       proto_tree_add_boolean_hidden(nbns_tree, hf_nbns_response, tvb, 
-                                            0, 0, TRUE);
-               } else {
-                       proto_tree_add_boolean_hidden(nbns_tree, hf_nbns_query, tvb, 
-                                            0, 0, TRUE);
-               }
-
                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,
+               nbns_add_nbns_flags(pinfo->cinfo, nbns_tree, tvb, offset + NBNS_FLAGS,
                                    flags, 0);
        }
        quest = tvb_get_ntohs(tvb, offset + NBNS_QUEST);
@@ -1045,7 +1057,7 @@ dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        }
 
        cur_off = offset + NBNS_HDRLEN;
-    
+
        if (quest > 0) {
                /* If this is a response, don't add information about the
                   queries to the summary, just add information about the
@@ -1062,7 +1074,7 @@ dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                cur_off += dissect_answer_records(tvb, cur_off,
                        nbns_data_offset, ans,
                        ((flags & F_RESPONSE) ? cinfo : NULL), nbns_tree,
-                       flags & F_OPCODE, "Answers");
+                       opcode, "Answers");
        }
 
        if (tree) {
@@ -1071,15 +1083,13 @@ dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                if (auth > 0)
                        cur_off += dissect_answer_records(tvb, cur_off,
                                        nbns_data_offset,
-                                       auth, NULL, nbns_tree,
-                                       flags & F_OPCODE,
+                                       auth, NULL, nbns_tree, opcode,
                                        "Authoritative nameservers");
 
                if (add > 0)
                        cur_off += dissect_answer_records(tvb, cur_off,
                                        nbns_data_offset,
-                                       add, NULL, nbns_tree,
-                                       flags & F_OPCODE,
+                                       add, NULL, nbns_tree, opcode,
                                        "Additional records");
        }
 }
@@ -1126,7 +1136,7 @@ static const value_string nbds_msgtype_vals[] = {
        { 0,                       NULL }
 };
 
-static const true_false_string yesno = {  
+static const true_false_string yesno = {
        "Yes",
        "No"
 };
@@ -1167,7 +1177,7 @@ dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                col_clear(pinfo->cinfo, COL_INFO);
 
        header.msg_type = tvb_get_guint8(tvb, offset);
-       
+
        flags = tvb_get_guint8(tvb, offset+1);
        header.flags.more = flags & 1;
        header.flags.first = (flags & 2) >> 1;
@@ -1187,7 +1197,7 @@ dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                break;
 
        case NBDS_ERROR:
-               header.error_code = tvb_get_ntohs(tvb, offset+10);
+               header.error_code = tvb_get_guint8(tvb, offset+10);
                break;
        }
 
@@ -1208,16 +1218,16 @@ dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                nbdgm_tree = proto_item_add_subtree(ti, ett_nbdgm);
 
                proto_tree_add_uint(nbdgm_tree, hf_nbdgm_type, tvb,
-                                    offset, 1, 
+                                    offset, 1,
                                     header.msg_type);
                proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_fragment, tvb,
-                                      offset+1, 1, 
+                                      offset+1, 1,
                                       header.flags.more);
                proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_first, tvb,
-                                      offset+1, 1, 
+                                      offset+1, 1,
                                       header.flags.first);
                proto_tree_add_uint(nbdgm_tree, hf_nbdgm_node_type, tvb,
-                                    offset+1, 1, 
+                                    offset+1, 1,
                                     header.flags.node_type);
 
                proto_tree_add_uint(nbdgm_tree, hf_nbdgm_datagram_id, tvb,
@@ -1350,7 +1360,7 @@ static const value_string error_codes[] = {
  */
 static int
 dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo,
-    proto_tree *tree, int max_data, int is_cifs)
+    proto_tree *tree, int is_cifs)
 {
        proto_tree      *nbss_tree = NULL;
        proto_item      *ti = NULL;
@@ -1420,12 +1430,12 @@ dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo,
        if (tree) {
          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_uint_format(nbss_tree, hf_nbss_type, tvb,
-                                    offset, 1, 
+                                    offset, 1,
                                     msg_type,
                                     "Message Type: %s",
-                                    val_to_str(msg_type, message_types, 
+                                    val_to_str(msg_type, message_types,
                                                "Unknown (%x)"));
        }
 
@@ -1462,20 +1472,32 @@ dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo,
                                "Called name", name, name_type);
          offset += len;
 
+         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, 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) 
+         if (tree)
            proto_tree_add_text(nbss_tree, tvb, offset, 1,
                                "Error code: %s",
                                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:
@@ -1483,7 +1505,7 @@ dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo,
            proto_tree_add_text(nbss_tree, tvb, offset, 4,
                                "Retarget IP address: %s",
                                ip_to_str(tvb_get_ptr(tvb, offset, 4)));
-         
+
          offset += 4;
 
          if (tree)
@@ -1698,15 +1720,14 @@ dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        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(tvb, offset, pinfo, tree, max_data,
-                   is_cifs);
+       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
@@ -1722,7 +1743,6 @@ dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        return;
                }
                offset += len;
-               max_data -= len;
        }
 
        return;
@@ -1735,11 +1755,9 @@ continuation:
                col_add_fstr(pinfo->cinfo, COL_INFO, "NBSS Continuation Message");
 
        if (tree) {
-               ti = proto_tree_add_item(tree, proto_nbss, tvb, 0,
-                   max_data, FALSE);
+               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, max_data,
-                   "Continuation data");
+               proto_tree_add_text(nbss_tree, tvb, 0, -1, "Continuation data");
        }
 }
 
@@ -1748,59 +1766,87 @@ 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", HFILL }},
-    { &hf_nbns_query,
-      { "Query",               "nbns.query",  
-       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
-       "TRUE if NBNS query", HFILL }},
+    { &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",  
+      { "Transaction ID",              "nbns.id",
        FT_UINT16, BASE_HEX, NULL, 0x0,
        "Identification of transaction", HFILL }},
     { &hf_nbns_count_questions,
-      { "Questions",           "nbns.count.queries",  
+      { "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",  
+      { "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",  
+      { "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",  
+      { "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",  
+      { "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",  
+      { "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",  
+      { "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",  
+      { "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",  
+      { "Datagram ID",         "nbdgm.dgram_id",
        FT_UINT16, BASE_HEX, NULL, 0x0,
        "Datagram identifier", HFILL }},
     { &hf_nbdgm_src_ip,
-      { "Source IP",           "nbdgm.src.ip",  
+      { "Source IP",           "nbdgm.src.ip",
        FT_IPv4, BASE_NONE, NULL, 0x0,
        "Source IPv4 address", HFILL }},
     { &hf_nbdgm_src_port,
@@ -1811,11 +1857,11 @@ proto_register_nbt(void)
 
   static hf_register_info hf_nbss[] = {
     { &hf_nbss_type,
-      { "Message Type",                "nbss.type",  
+      { "Message Type",                "nbss.type",
        FT_UINT8, BASE_DEC, NULL, 0x0,
        "NBSS message type", HFILL }},
     { &hf_nbss_flags,
-      { "Flags",               "nbss.flags",  
+      { "Flags",               "nbss.flags",
        FT_UINT8, BASE_HEX, NULL, 0x0,
        "NBSS message flags", HFILL }}
   };
@@ -1836,7 +1882,7 @@ proto_register_nbt(void)
 
   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));