diff options
author | Bill Meier <wmeier@newsguy.com> | 2012-08-16 23:52:27 +0000 |
---|---|---|
committer | Bill Meier <wmeier@newsguy.com> | 2012-08-16 23:52:27 +0000 |
commit | 98eab94319d0145aa133e2b005f7b9756df222bc (patch) | |
tree | f95221e794c9d72ab80133a3b54daf6313d9569a /epan/dissectors/packet-nbns.c | |
parent | a9bb084310150b123b2300ad09cbf50e9442bfde (diff) |
Cleanup:
- remove/rework some 'if (tree)' usage so that:
. col_...() not called under same;
. dissection doesn't change depending upon same;
- simplify some code;
- use consistent indentation & whitespace formatting.
svn path=/trunk/; revision=44546
Diffstat (limited to 'epan/dissectors/packet-nbns.c')
-rw-r--r-- | epan/dissectors/packet-nbns.c | 3176 |
1 files changed, 1618 insertions, 1558 deletions
diff --git a/epan/dissectors/packet-nbns.c b/epan/dissectors/packet-nbns.c index 68a70b15bd..7c21a97dbd 100644 --- a/epan/dissectors/packet-nbns.c +++ b/epan/dissectors/packet-nbns.c @@ -90,11 +90,11 @@ static gboolean nbss_desegment = TRUE; /* See RFC 1001 and 1002 for information on the first three, and see - http://www.cifs.com/specs/draft-leach-cifs-v1-spec-01.txt + http://www.cifs.com/specs/draft-leach-cifs-v1-spec-01.txt Appendix B, and various messages on the CIFS mailing list such as - http://discuss.microsoft.com/SCRIPTS/WA-MSD.EXE?A2=ind9811A&L=cifs&P=R386 + http://discuss.microsoft.com/SCRIPTS/WA-MSD.EXE?A2=ind9811A&L=cifs&P=R386 for information on the fourth. */ #define UDP_PORT_NBNS 137 @@ -133,33 +133,33 @@ static gboolean nbss_desegment = TRUE; #define F_RCODE (0xF<<0) /* reply code */ static const true_false_string tfs_flags_response = { - "Message is a response", - "Message is a query" + "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" + "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" + "Message is truncated", + "Message is not truncated" }; static const true_false_string tfs_flags_recdesired = { - "Do query recursively", - "Don't do query recursively" + "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" + "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" + "Broadcast packet", + "Not a broadcast packet" }; /* Opcodes */ @@ -172,14 +172,14 @@ static const true_false_string tfs_flags_broadcast = { #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 } + { 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 */ @@ -193,15 +193,15 @@ static const value_string opcode_vals[] = { #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 } + { 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, @@ -238,14 +238,14 @@ static const value_string rcode_vals[] = { static const char * nbns_type_name (int type) { - switch (type) { - case T_NB: - return "NB"; - case T_NBSTAT: - return "NBSTAT"; - } - - return "unknown"; + switch (type) { + case T_NB: + return "NB"; + case T_NBSTAT: + return "NBSTAT"; + } + + return "unknown"; } #define NBNAME_BUF_LEN 128 @@ -256,114 +256,114 @@ add_rr_to_tree(proto_item *trr, int rr_type, tvbuff_t *tvb, int offset, const char *type_name, const char *class_description, guint ttl, gushort data_len) { - proto_tree *rr_tree; - - rr_tree = proto_item_add_subtree(trr, rr_type); - proto_tree_add_text(rr_tree, tvb, offset+1, namelen-1, "Name: %s", name); - offset += namelen; - proto_tree_add_text(rr_tree, tvb, offset, 2, "Type: %s", type_name); - offset += 2; - proto_tree_add_text(rr_tree, tvb, offset, 2, "Class: %s", class_description); - offset += 2; - proto_tree_add_text(rr_tree, tvb, offset, 4, "Time to live: %s", - time_secs_to_str(ttl)); - offset += 4; - proto_tree_add_text(rr_tree, tvb, offset, 2, "Data length: %u", data_len); - return rr_tree; + proto_tree *rr_tree; + + rr_tree = proto_item_add_subtree(trr, rr_type); + proto_tree_add_text(rr_tree, tvb, offset+1, namelen-1, "Name: %s", name); + offset += namelen; + proto_tree_add_text(rr_tree, tvb, offset, 2, "Type: %s", type_name); + offset += 2; + proto_tree_add_text(rr_tree, tvb, offset, 2, "Class: %s", class_description); + offset += 2; + proto_tree_add_text(rr_tree, tvb, offset, 4, "Time to live: %s", + time_secs_to_str(ttl)); + offset += 4; + proto_tree_add_text(rr_tree, tvb, offset, 2, "Data length: %u", data_len); + return rr_tree; } static int get_nbns_name(tvbuff_t *tvb, int offset, int nbns_data_offset, char *name_ret, int name_ret_len, int *name_type_ret) { - int name_len; - const guchar *name; - const guchar *nbname; - char *nbname_buf; - const guchar *pname; - char cname, cnbname; - int name_type; - char *pname_ret; - size_t idx = 0; - - nbname_buf=ep_alloc(NBNAME_BUF_LEN); - nbname = nbname_buf; - /* XXX Fix data len */ - name_len = get_dns_name(tvb, offset, 0, nbns_data_offset, &name); - - /* OK, now undo the first-level encoding. */ - pname = &name[0]; - pname_ret=name_ret; - - for (;;) { - /* Every two characters of the first level-encoded name - * turn into one character in the decoded name. */ - cname = *pname; - if (cname == '\0') - break; /* no more characters */ - if (cname == '.') - break; /* scope ID follows */ - if (cname < 'A' || cname > 'Z') { - /* Not legal. */ - nbname="Illegal NetBIOS name (1st character not between A and Z in first-level encoding)"; - goto bad; - } - cname -= 'A'; - cnbname = cname << 4; - pname++; - - cname = *pname; - if (cname == '\0' || cname == '.') { - /* No more characters in the name - but we're in - * the middle of a pair. Not legal. */ - nbname="Illegal NetBIOS name (odd number of bytes)"; - goto bad; - } - if (cname < 'A' || cname > 'Z') { - /* Not legal. */ - nbname="Illegal NetBIOS name (2nd character not between A and Z in first-level encoding)"; - goto bad; - } - cname -= 'A'; - cnbname |= cname; - pname++; - - /* Do we have room to store the character? */ - if (idx < NETBIOS_NAME_LEN) { - /* Yes - store the character. */ - nbname_buf[idx++] = cnbname; - } - } - - /* NetBIOS names are supposed to be exactly 16 bytes long. */ - if (idx != NETBIOS_NAME_LEN) { - /* It's not. */ - g_snprintf(nbname_buf, NBNAME_BUF_LEN, "Illegal NetBIOS name (%lu bytes long)", - (unsigned long)idx); - goto bad; - } - - /* This one is; make its name printable. */ - name_type = process_netbios_name(nbname, name_ret, name_ret_len); - pname_ret += MIN(strlen(name_ret), (size_t) name_ret_len); - pname_ret += MIN(name_ret_len-(pname_ret-name_ret), - g_snprintf(pname_ret, name_ret_len-(gulong)(pname_ret-name_ret), "<%02x>", name_type)); - if (cname == '.') { - /* We have a scope ID, starting at "pname"; append that to - * the decoded host name. */ - g_snprintf(pname_ret, name_ret_len-(gulong)(pname_ret-name_ret), "%s", pname); - } - if (name_type_ret != NULL) - *name_type_ret = name_type; - return name_len; + int name_len; + const guchar *name; + const guchar *nbname; + char *nbname_buf; + const guchar *pname; + char cname, cnbname; + int name_type; + char *pname_ret; + size_t idx = 0; + + nbname_buf = ep_alloc(NBNAME_BUF_LEN); + nbname = nbname_buf; + /* XXX Fix data len */ + name_len = get_dns_name(tvb, offset, 0, nbns_data_offset, &name); + + /* OK, now undo the first-level encoding. */ + pname = &name[0]; + pname_ret = name_ret; + + for (;;) { + /* Every two characters of the first level-encoded name + * turn into one character in the decoded name. */ + cname = *pname; + if (cname == '\0') + break; /* no more characters */ + if (cname == '.') + break; /* scope ID follows */ + if (cname < 'A' || cname > 'Z') { + /* Not legal. */ + nbname = "Illegal NetBIOS name (1st character not between A and Z in first-level encoding)"; + goto bad; + } + cname -= 'A'; + cnbname = cname << 4; + pname++; + + cname = *pname; + if (cname == '\0' || cname == '.') { + /* No more characters in the name - but we're in + * the middle of a pair. Not legal. */ + nbname = "Illegal NetBIOS name (odd number of bytes)"; + goto bad; + } + if (cname < 'A' || cname > 'Z') { + /* Not legal. */ + nbname = "Illegal NetBIOS name (2nd character not between A and Z in first-level encoding)"; + goto bad; + } + cname -= 'A'; + cnbname |= cname; + pname++; + + /* Do we have room to store the character? */ + if (idx < NETBIOS_NAME_LEN) { + /* Yes - store the character. */ + nbname_buf[idx++] = cnbname; + } + } + + /* NetBIOS names are supposed to be exactly 16 bytes long. */ + if (idx != NETBIOS_NAME_LEN) { + /* It's not. */ + g_snprintf(nbname_buf, NBNAME_BUF_LEN, "Illegal NetBIOS name (%lu bytes long)", + (unsigned long)idx); + goto bad; + } + + /* This one is; make its name printable. */ + name_type = process_netbios_name(nbname, name_ret, name_ret_len); + pname_ret += MIN(strlen(name_ret), (size_t) name_ret_len); + pname_ret += MIN(name_ret_len-(pname_ret-name_ret), + g_snprintf(pname_ret, name_ret_len-(gulong)(pname_ret-name_ret), "<%02x>", name_type)); + if (cname == '.') { + /* We have a scope ID, starting at "pname"; append that to + * the decoded host name. */ + g_snprintf(pname_ret, name_ret_len-(gulong)(pname_ret-name_ret), "%s", pname); + } + if (name_type_ret != NULL) + *name_type_ret = name_type; + return name_len; bad: - if (name_type_ret != NULL) - *name_type_ret = -1; - /* This is only valid because nbname is always assigned an error string - * before jumping to bad: Otherwise nbname wouldn't be \0 terminated */ - g_snprintf(pname_ret, name_ret_len-(gulong)(pname_ret-name_ret), "%s", nbname); - return name_len; + if (name_type_ret != NULL) + *name_type_ret = -1; + /* This is only valid because nbname is always assigned an error string + * before jumping to bad: Otherwise nbname wouldn't be \0 terminated */ + g_snprintf(pname_ret, name_ret_len-(gulong)(pname_ret-name_ret), "%s", nbname); + return name_len; } @@ -372,37 +372,37 @@ get_nbns_name_type_class(tvbuff_t *tvb, int offset, int nbns_data_offset, char *name_ret, int *name_len_ret, int *name_type_ret, int *type_ret, int *class_ret) { - int name_len; - int type; - int class; + int name_len; + int type; + int class; - name_len = get_nbns_name(tvb, offset, nbns_data_offset, name_ret, - *name_len_ret, name_type_ret); - offset += name_len; + name_len = get_nbns_name(tvb, offset, nbns_data_offset, name_ret, + *name_len_ret, name_type_ret); + offset += name_len; - type = tvb_get_ntohs(tvb, offset); - offset += 2; + type = tvb_get_ntohs(tvb, offset); + offset += 2; - class = tvb_get_ntohs(tvb, offset); + class = tvb_get_ntohs(tvb, offset); - *type_ret = type; - *class_ret = class; - *name_len_ret = name_len; + *type_ret = type; + *class_ret = class; + *name_len_ret = name_len; - return name_len + 4; + return name_len + 4; } static void add_name_and_type(proto_tree *tree, tvbuff_t *tvb, int offset, int len, const char *tag, const char *name, int name_type) { - if (name_type != -1) { - proto_tree_add_text(tree, tvb, offset, len, "%s: %s (%s)", - tag, name, netbios_name_type_descr(name_type)); - } else { - proto_tree_add_text(tree, tvb, offset, len, "%s: %s", - tag, name); - } + if (name_type != -1) { + proto_tree_add_text(tree, tvb, offset, len, "%s: %s (%s)", + tag, name, netbios_name_type_descr(name_type)); + } else { + proto_tree_add_text(tree, tvb, offset, len, "%s: %s", + tag, name); + } } #define MAX_NAME_LEN (NETBIOS_NAME_LEN - 1)*4 + MAXDNAME + 64 @@ -411,747 +411,804 @@ static int dissect_nbns_query(tvbuff_t *tvb, int offset, int nbns_data_offset, column_info *cinfo, proto_tree *nbns_tree) { - int len; - char *name; - int name_len; - int name_type; - int type; - int class; - const char *type_name; - int data_offset; - int data_start; - proto_tree *q_tree; - proto_item *tq; - - name=ep_alloc(MAX_NAME_LEN); - data_start = data_offset = offset; - - name_len=MAX_NAME_LEN; - len = get_nbns_name_type_class(tvb, offset, nbns_data_offset, name, - &name_len, &name_type, &type, &class); - data_offset += len; - - type_name = nbns_type_name(type); - - if (cinfo != NULL) - col_append_fstr(cinfo, COL_INFO, " %s %s", type_name, name); - if (nbns_tree != NULL) { - tq = proto_tree_add_text(nbns_tree, tvb, offset, len, - "%s: type %s, class %s", name, type_name, - dns_class_name(class)); - q_tree = proto_item_add_subtree(tq, ett_nbns_qd); - - add_name_and_type(q_tree, tvb, offset, name_len, "Name", name, - name_type); - offset += name_len; - - proto_tree_add_text(q_tree, tvb, offset, 2, "Type: %s", type_name); - offset += 2; - - proto_tree_add_text(q_tree, tvb, offset, 2, "Class: %s", - dns_class_name(class)); - /*offset += 2;*/ - } - - return data_offset - data_start; + int len; + char *name; + int name_len; + int name_type; + int type; + int class; + const char *type_name; + int data_offset; + int data_start; + proto_tree *q_tree; + proto_item *tq; + + name = ep_alloc(MAX_NAME_LEN); + data_start = data_offset = offset; + + name_len = MAX_NAME_LEN; + len = get_nbns_name_type_class(tvb, offset, nbns_data_offset, name, + &name_len, &name_type, &type, &class); + data_offset += len; + + type_name = nbns_type_name(type); + + if (cinfo != NULL) + col_append_fstr(cinfo, COL_INFO, " %s %s", type_name, name); + + if (nbns_tree != NULL) { + tq = proto_tree_add_text(nbns_tree, tvb, offset, len, + "%s: type %s, class %s", name, type_name, + dns_class_name(class)); + q_tree = proto_item_add_subtree(tq, ett_nbns_qd); + + add_name_and_type(q_tree, tvb, offset, name_len, "Name", name, + name_type); + offset += name_len; + + proto_tree_add_text(q_tree, tvb, offset, 2, "Type: %s", type_name); + offset += 2; + + proto_tree_add_text(q_tree, tvb, offset, 2, "Class: %s", + dns_class_name(class)); + /*offset += 2;*/ + } + + return data_offset - data_start; } static void nbns_add_nbns_flags(column_info *cinfo, proto_tree *nbns_tree, tvbuff_t *tvb, int offset, gushort flags, int is_wack) { - char *buf; - guint16 opcode; - proto_tree *field_tree; - proto_item *tf; + char *buf; + guint16 opcode; + proto_tree *field_tree; + proto_item *tf; #define MAX_BUF_SIZE (128+1) - buf=ep_alloc(MAX_BUF_SIZE); - opcode = (guint16) ((flags & F_OPCODE) >> OPCODE_SHIFT); - g_snprintf(buf, MAX_BUF_SIZE, "%s", val_to_str_const(opcode, opcode_vals, "Unknown operation")); - if (flags & F_RESPONSE && !is_wack) { - g_strlcat(buf, " response", MAX_BUF_SIZE); - g_strlcat(buf, ", ", MAX_BUF_SIZE); - g_strlcat(buf, val_to_str_const(flags & F_RCODE, rcode_vals, "Unknown error"), MAX_BUF_SIZE); - buf[MAX_BUF_SIZE-1] = '\0'; - if ((flags & F_RCODE)) - col_append_fstr(cinfo, COL_INFO, ", %s", - val_to_str_const(flags & F_RCODE, rcode_vals, - "Unknown error")); - } - tf = proto_tree_add_uint_format(nbns_tree, hf_nbns_flags, - tvb, offset, 2, flags, "Flags: 0x%04x (%s)", flags, buf); - field_tree = proto_item_add_subtree(tf, ett_nbns_flags); - proto_tree_add_item(field_tree, hf_nbns_flags_response, - tvb, offset, 2, ENC_BIG_ENDIAN); - proto_tree_add_item(field_tree, hf_nbns_flags_opcode, - tvb, offset, 2, ENC_BIG_ENDIAN); - if (flags & F_RESPONSE) { - proto_tree_add_item(field_tree, hf_nbns_flags_authoritative, - tvb, offset, 2, ENC_BIG_ENDIAN); - } - proto_tree_add_item(field_tree, hf_nbns_flags_truncated, - tvb, offset, 2, ENC_BIG_ENDIAN); - proto_tree_add_item(field_tree, hf_nbns_flags_recdesired, - tvb, offset, 2, ENC_BIG_ENDIAN); - if (flags & F_RESPONSE) { - proto_tree_add_item(field_tree, hf_nbns_flags_recavail, - tvb, offset, 2, ENC_BIG_ENDIAN); - } - proto_tree_add_item(field_tree, hf_nbns_flags_broadcast, - tvb, offset, 2, ENC_BIG_ENDIAN); - if (flags & F_RESPONSE && !is_wack) { - proto_tree_add_item(field_tree, hf_nbns_flags_rcode, - tvb, offset, 2, ENC_BIG_ENDIAN); - } + + if (cinfo) { + if (flags & F_RESPONSE && !is_wack) { + if ((flags & F_RCODE)) + col_append_fstr(cinfo, COL_INFO, ", %s", + val_to_str_const(flags & F_RCODE, rcode_vals, + "Unknown error")); + } + } + + if (!nbns_tree) + return; + + buf = ep_alloc(MAX_BUF_SIZE); + opcode = (guint16) ((flags & F_OPCODE) >> OPCODE_SHIFT); + g_snprintf(buf, MAX_BUF_SIZE, "%s", val_to_str_const(opcode, opcode_vals, "Unknown operation")); + if (flags & F_RESPONSE && !is_wack) { + g_strlcat(buf, " response", MAX_BUF_SIZE); + g_strlcat(buf, ", ", MAX_BUF_SIZE); + g_strlcat(buf, val_to_str_const(flags & F_RCODE, rcode_vals, "Unknown error"), MAX_BUF_SIZE); + buf[MAX_BUF_SIZE-1] = '\0'; + } + tf = proto_tree_add_uint_format(nbns_tree, hf_nbns_flags, + tvb, offset, 2, flags, "Flags: 0x%04x (%s)", flags, buf); + field_tree = proto_item_add_subtree(tf, ett_nbns_flags); + proto_tree_add_item(field_tree, hf_nbns_flags_response, + tvb, offset, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(field_tree, hf_nbns_flags_opcode, + tvb, offset, 2, ENC_BIG_ENDIAN); + if (flags & F_RESPONSE) { + proto_tree_add_item(field_tree, hf_nbns_flags_authoritative, + tvb, offset, 2, ENC_BIG_ENDIAN); + } + proto_tree_add_item(field_tree, hf_nbns_flags_truncated, + tvb, offset, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(field_tree, hf_nbns_flags_recdesired, + tvb, offset, 2, ENC_BIG_ENDIAN); + if (flags & F_RESPONSE) { + proto_tree_add_item(field_tree, hf_nbns_flags_recavail, + tvb, offset, 2, ENC_BIG_ENDIAN); + } + proto_tree_add_item(field_tree, hf_nbns_flags_broadcast, + tvb, offset, 2, ENC_BIG_ENDIAN); + if (flags & F_RESPONSE && !is_wack) { + proto_tree_add_item(field_tree, hf_nbns_flags_rcode, + tvb, offset, 2, ENC_BIG_ENDIAN); + } } static void nbns_add_nb_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset, gushort flags) { - char *buf; - proto_tree *field_tree; - proto_item *tf; - static const value_string nb_flags_ont_vals[] = { - { NB_FLAGS_ONT_B_NODE, "B-node" }, - { NB_FLAGS_ONT_P_NODE, "P-node" }, - { NB_FLAGS_ONT_M_NODE, "M-node" }, - { NB_FLAGS_ONT_H_NODE, "H-node" }, - { 0, NULL } - }; - - buf=ep_alloc(MAX_BUF_SIZE); - g_snprintf(buf, MAX_BUF_SIZE, "%s", val_to_str_const(flags & NB_FLAGS_ONT, nb_flags_ont_vals, - "Unknown")); - g_strlcat(buf, ", ", MAX_BUF_SIZE); - if (flags & NB_FLAGS_G) - g_strlcat(buf, "group", MAX_BUF_SIZE); - else - g_strlcat(buf, "unique", MAX_BUF_SIZE); - buf[MAX_BUF_SIZE-1] = '\0'; - tf = proto_tree_add_text(rr_tree, tvb, offset, 2, "Flags: 0x%x (%s)", flags, - buf); - field_tree = proto_item_add_subtree(tf, ett_nbns_nb_flags); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", + char *buf; + proto_tree *field_tree; + proto_item *tf; + + static const value_string nb_flags_ont_vals[] = { + { NB_FLAGS_ONT_B_NODE, "B-node" }, + { NB_FLAGS_ONT_P_NODE, "P-node" }, + { NB_FLAGS_ONT_M_NODE, "M-node" }, + { NB_FLAGS_ONT_H_NODE, "H-node" }, + { 0, NULL } + }; + + if (!rr_tree) + return; + + buf = ep_alloc(MAX_BUF_SIZE); + g_snprintf(buf, MAX_BUF_SIZE, "%s", val_to_str_const(flags & NB_FLAGS_ONT, nb_flags_ont_vals, + "Unknown")); + g_strlcat(buf, ", ", MAX_BUF_SIZE); + if (flags & NB_FLAGS_G) + g_strlcat(buf, "group", MAX_BUF_SIZE); + else + g_strlcat(buf, "unique", MAX_BUF_SIZE); + buf[MAX_BUF_SIZE-1] = '\0'; + tf = proto_tree_add_text(rr_tree, tvb, offset, 2, "Flags: 0x%x (%s)", flags, + buf); + field_tree = proto_item_add_subtree(tf, ett_nbns_nb_flags); + proto_tree_add_text(field_tree, tvb, offset, 2, "%s", decode_boolean_bitfield(flags, NB_FLAGS_G, - 2*8, - "Group name", - "Unique name")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", + 2*8, + "Group name", + "Unique name")); + proto_tree_add_text(field_tree, tvb, offset, 2, "%s", decode_enumerated_bitfield(flags, NB_FLAGS_ONT, - 2*8, nb_flags_ont_vals, "%s")); + 2*8, nb_flags_ont_vals, "%s")); } static void nbns_add_name_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset, gushort flags) { - char *buf; - proto_item *field_tree; - proto_item *tf; - static const value_string name_flags_ont_vals[] = { - { NAME_FLAGS_ONT_B_NODE, "B-node" }, - { NAME_FLAGS_ONT_P_NODE, "P-node" }, - { NAME_FLAGS_ONT_M_NODE, "M-node" }, - { 0, NULL } - }; - - buf=ep_alloc(MAX_BUF_SIZE); - g_snprintf(buf, MAX_BUF_SIZE, "%s", val_to_str_const(flags & NAME_FLAGS_ONT, name_flags_ont_vals, - "Unknown")); - g_strlcat(buf, ", ", MAX_BUF_SIZE); - if (flags & NAME_FLAGS_G) - g_strlcat(buf, "group", MAX_BUF_SIZE); - else - g_strlcat(buf, "unique", MAX_BUF_SIZE); - if (flags & NAME_FLAGS_DRG) - g_strlcat(buf, ", being deregistered", MAX_BUF_SIZE); - if (flags & NAME_FLAGS_CNF) - g_strlcat(buf, ", in conflict", MAX_BUF_SIZE); - if (flags & NAME_FLAGS_ACT) - g_strlcat(buf, ", active", MAX_BUF_SIZE); - if (flags & NAME_FLAGS_PRM) - g_strlcat(buf, ", permanent node name", MAX_BUF_SIZE); - buf[MAX_BUF_SIZE-1] = '\0'; - tf = proto_tree_add_text(rr_tree, tvb, offset, 2, "Name flags: 0x%x (%s)", - flags, buf); - field_tree = proto_item_add_subtree(tf, ett_nbns_name_flags); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", + char *buf; + proto_item *field_tree; + proto_item *tf; + + static const value_string name_flags_ont_vals[] = { + { NAME_FLAGS_ONT_B_NODE, "B-node" }, + { NAME_FLAGS_ONT_P_NODE, "P-node" }, + { NAME_FLAGS_ONT_M_NODE, "M-node" }, + { 0, NULL } + }; + + if (!rr_tree) + return; + + buf = ep_alloc(MAX_BUF_SIZE); + g_snprintf(buf, MAX_BUF_SIZE, "%s", val_to_str_const(flags & NAME_FLAGS_ONT, name_flags_ont_vals, + "Unknown")); + g_strlcat(buf, ", ", MAX_BUF_SIZE); + if (flags & NAME_FLAGS_G) + g_strlcat(buf, "group", MAX_BUF_SIZE); + else + g_strlcat(buf, "unique", MAX_BUF_SIZE); + if (flags & NAME_FLAGS_DRG) + g_strlcat(buf, ", being deregistered", MAX_BUF_SIZE); + if (flags & NAME_FLAGS_CNF) + g_strlcat(buf, ", in conflict", MAX_BUF_SIZE); + if (flags & NAME_FLAGS_ACT) + g_strlcat(buf, ", active", MAX_BUF_SIZE); + if (flags & NAME_FLAGS_PRM) + g_strlcat(buf, ", permanent node name", MAX_BUF_SIZE); + buf[MAX_BUF_SIZE-1] = '\0'; + tf = proto_tree_add_text(rr_tree, tvb, offset, 2, "Name flags: 0x%x (%s)", + flags, buf); + field_tree = proto_item_add_subtree(tf, ett_nbns_name_flags); + proto_tree_add_text(field_tree, tvb, offset, 2, "%s", decode_boolean_bitfield(flags, NAME_FLAGS_G, - 2*8, - "Group name", - "Unique name")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", + 2*8, + "Group name", + "Unique name")); + proto_tree_add_text(field_tree, tvb, offset, 2, "%s", decode_enumerated_bitfield(flags, NAME_FLAGS_ONT, - 2*8, name_flags_ont_vals, "%s")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", + 2*8, name_flags_ont_vals, "%s")); + proto_tree_add_text(field_tree, tvb, offset, 2, "%s", decode_boolean_bitfield(flags, NAME_FLAGS_DRG, - 2*8, - "Name is being deregistered", - "Name is not being deregistered")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", + 2*8, + "Name is being deregistered", + "Name is not being deregistered")); + proto_tree_add_text(field_tree, tvb, offset, 2, "%s", decode_boolean_bitfield(flags, NAME_FLAGS_CNF, - 2*8, - "Name is in conflict", - "Name is not in conflict")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", + 2*8, + "Name is in conflict", + "Name is not in conflict")); + proto_tree_add_text(field_tree, tvb, offset, 2, "%s", decode_boolean_bitfield(flags, NAME_FLAGS_ACT, - 2*8, - "Name is active", - "Name is not active")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", + 2*8, + "Name is active", + "Name is not active")); + proto_tree_add_text(field_tree, tvb, offset, 2, "%s", decode_boolean_bitfield(flags, NAME_FLAGS_PRM, - 2*8, - "Permanent node name", - "Not permanent node name")); + 2*8, + "Permanent node name", + "Not permanent node name")); } static int dissect_nbns_answer(tvbuff_t *tvb, int offset, int nbns_data_offset, column_info *cinfo, proto_tree *nbns_tree, int opcode) { - int len; - char *name; - int name_len; - int name_type; - int type; - int class; - const char *class_name; - const char *type_name; - int data_offset; - int cur_offset; - int data_start; - guint ttl; - gushort data_len; - gushort flags; - proto_tree *rr_tree; - proto_item *trr; - char *name_str; - guint num_names; - char *nbname; - gushort name_flags; - - data_start = data_offset = offset; - cur_offset = offset; - - name=ep_alloc(MAX_NAME_LEN); - name_str=ep_alloc(MAX_NAME_LEN); - nbname=ep_alloc(16+4+1); /* 4 for [<last char>] */ - - name_len=MAX_NAME_LEN; - len = get_nbns_name_type_class(tvb, offset, nbns_data_offset, name, - &name_len, &name_type, &type, &class); - data_offset += len; - cur_offset += len; - - type_name = nbns_type_name(type); - class_name = dns_class_name(class); - - ttl = tvb_get_ntohl(tvb, data_offset); - data_offset += 4; - cur_offset += 4; - - data_len = tvb_get_ntohs(tvb, data_offset); - data_offset += 2; - cur_offset += 2; - - switch (type) { - case T_NB: /* "NB" record */ - if (cinfo != NULL) { - if (opcode != OPCODE_WACK) { - col_append_fstr(cinfo, COL_INFO, " %s %s", - type_name, - tvb_ip_to_str(tvb, data_offset+2)); - } - } - if (nbns_tree == NULL) - break; - trr = proto_tree_add_text(nbns_tree, tvb, offset, - (data_offset - data_start) + data_len, - "%s: type %s, class %s", - name, type_name, class_name); - g_strlcat(name, " (", MAX_NAME_LEN); - g_strlcat(name, netbios_name_type_descr(name_type), MAX_NAME_LEN); - g_strlcat(name, ")", MAX_NAME_LEN); - rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name, - name_len, type_name, dns_class_name(class), ttl, data_len); - while (data_len > 0) { - if (opcode == OPCODE_WACK) { - /* WACK response. This doesn't contain the - * same type of RR data as other T_NB - * responses. */ - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - flags = tvb_get_ntohs(tvb, cur_offset); - nbns_add_nbns_flags(cinfo, rr_tree, tvb, cur_offset, + int len; + char *name; + int name_len; + int name_type; + int type; + int class; + const char *class_name; + const char *type_name; + int cur_offset; + guint ttl; + gushort data_len; + gushort flags; + proto_tree *rr_tree = NULL; + proto_item *trr; + char *name_str; + guint num_names; + char *nbname; + gushort name_flags; + + cur_offset = offset; + + name = ep_alloc(MAX_NAME_LEN); + name_str = ep_alloc(MAX_NAME_LEN); + nbname = ep_alloc(16+4+1); /* 4 for [<last char>] */ + + name_len = MAX_NAME_LEN; + len = get_nbns_name_type_class(tvb, offset, nbns_data_offset, name, + &name_len, &name_type, &type, &class); + cur_offset += len; + + type_name = nbns_type_name(type); + class_name = dns_class_name(class); + + ttl = tvb_get_ntohl(tvb, cur_offset); + cur_offset += 4; + + data_len = tvb_get_ntohs(tvb, cur_offset); + cur_offset += 2; + + /* XXX: This code should be simplified */ + switch (type) { + case T_NB: /* "NB" record */ + if (cinfo != NULL) { + if (opcode != OPCODE_WACK) { + col_append_fstr(cinfo, COL_INFO, " %s %s", + type_name, + tvb_ip_to_str(tvb, cur_offset+2)); + } + } + + if (nbns_tree) { + trr = proto_tree_add_text(nbns_tree, tvb, offset, + (cur_offset - offset) + data_len, + "%s: type %s, class %s", + name, type_name, class_name); + g_strlcat(name, " (", MAX_NAME_LEN); + g_strlcat(name, netbios_name_type_descr(name_type), MAX_NAME_LEN); + g_strlcat(name, ")", MAX_NAME_LEN); + rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name, + name_len, type_name, dns_class_name(class), ttl, data_len); + } + while (data_len > 0) { + if (opcode == OPCODE_WACK) { + /* WACK response. This doesn't contain the + * same type of RR data as other T_NB + * responses. */ + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + flags = tvb_get_ntohs(tvb, cur_offset); + nbns_add_nbns_flags(cinfo, rr_tree, tvb, cur_offset, flags, 1); - cur_offset += 2; - data_len -= 2; - } else { - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - flags = tvb_get_ntohs(tvb, cur_offset); - nbns_add_nb_flags(rr_tree, tvb, cur_offset, - flags); - cur_offset += 2; - data_len -= 2; - - if (data_len < 4) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 4, + cur_offset += 2; + data_len -= 2; + } else { + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + flags = tvb_get_ntohs(tvb, cur_offset); + nbns_add_nb_flags(rr_tree, tvb, cur_offset, + flags); + cur_offset += 2; + data_len -= 2; + + if (data_len < 4) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + proto_tree_add_text(rr_tree, tvb, cur_offset, 4, "Addr: %s", tvb_ip_to_str(tvb, cur_offset)); - cur_offset += 4; - data_len -= 4; - } - } - break; - - case T_NBSTAT: /* "NBSTAT" record */ - if (cinfo != NULL) - col_append_fstr(cinfo, COL_INFO, " %s", type_name); - if (nbns_tree == NULL) - break; - trr = proto_tree_add_text(nbns_tree, tvb, offset, - (data_offset - data_start) + data_len, - "%s: type %s, class %s", - name, type_name, class_name); - rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name, - name_len, type_name, dns_class_name(class), ttl, data_len); - if (data_len < 1) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - num_names = tvb_get_guint8(tvb, cur_offset); - proto_tree_add_text(rr_tree, tvb, cur_offset, 1, - "Number of names: %u", num_names); - cur_offset += 1; - - while (num_names != 0) { - if (data_len < NETBIOS_NAME_LEN) { - proto_tree_add_text(rr_tree, tvb, cur_offset, + cur_offset += 4; + data_len -= 4; + } + } + break; + + case T_NBSTAT: /* "NBSTAT" record */ + if (cinfo != NULL) + col_append_fstr(cinfo, COL_INFO, " %s", type_name); + + if (nbns_tree) { + trr = proto_tree_add_text(nbns_tree, tvb, offset, + (cur_offset - offset) + data_len, + "%s: type %s, class %s", + name, type_name, class_name); + rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name, + name_len, type_name, dns_class_name(class), ttl, data_len); + } + + if (data_len < 1) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + + num_names = tvb_get_guint8(tvb, cur_offset); + proto_tree_add_text(rr_tree, tvb, cur_offset, 1, + "Number of names: %u", num_names); + cur_offset += 1; + + while (num_names != 0) { + if (data_len < NETBIOS_NAME_LEN) { + proto_tree_add_text(rr_tree, tvb, cur_offset, data_len, "(incomplete entry)"); - goto out; - } - tvb_memcpy(tvb, (guint8 *)nbname, cur_offset, - NETBIOS_NAME_LEN); - name_type = process_netbios_name(nbname, - name_str, name_len); - proto_tree_add_text(rr_tree, tvb, cur_offset, - NETBIOS_NAME_LEN, "Name: %s<%02x> (%s)", - name_str, name_type, - netbios_name_type_descr(name_type)); - cur_offset += NETBIOS_NAME_LEN; - data_len -= NETBIOS_NAME_LEN; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, + goto out; + } + if (rr_tree) { + tvb_memcpy(tvb, (guint8 *)nbname, cur_offset, + NETBIOS_NAME_LEN); + name_type = process_netbios_name(nbname, + name_str, name_len); + proto_tree_add_text(rr_tree, tvb, cur_offset, + NETBIOS_NAME_LEN, "Name: %s<%02x> (%s)", + name_str, name_type, + netbios_name_type_descr(name_type)); + } + cur_offset += NETBIOS_NAME_LEN; + data_len -= NETBIOS_NAME_LEN; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, data_len, "(incomplete entry)"); - goto out; - } - name_flags = tvb_get_ntohs(tvb, cur_offset); - nbns_add_name_flags(rr_tree, tvb, cur_offset, - name_flags); - cur_offset += 2; - data_len -= 2; - - num_names--; - } - - if (data_len < 6) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 6, - "Unit ID: %s", - tvb_ether_to_str(tvb, cur_offset)); - cur_offset += 6; - data_len -= 6; - - if (data_len < 1) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 1, - "Jumpers: 0x%x", tvb_get_guint8(tvb, cur_offset)); - cur_offset += 1; - data_len -= 1; - - if (data_len < 1) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 1, - "Test result: 0x%x", tvb_get_guint8(tvb, cur_offset)); - cur_offset += 1; - data_len -= 1; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Version number: 0x%x", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Period of statistics: 0x%x", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of CRCs: %u", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of alignment errors: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of collisions: %u", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of send aborts: %u", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 4) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 4, - "Number of good sends: %u", tvb_get_ntohl(tvb, cur_offset)); - cur_offset += 4; - data_len -= 4; - - if (data_len < 4) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 4, - "Number of good receives: %u", - tvb_get_ntohl(tvb, cur_offset)); - cur_offset += 4; - data_len -= 4; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of retransmits: %u", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of no resource conditions: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of command blocks: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of pending sessions: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Max number of pending sessions: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Max total sessions possible: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Session data packet size: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - /*data_len -= 2;*/ - out: - break; - - default: - if (cinfo != NULL) - col_append_fstr(cinfo, COL_INFO, " %s", type_name); - if (nbns_tree == NULL) - break; - trr = proto_tree_add_text(nbns_tree, tvb, offset, - (data_offset - data_start) + data_len, - "%s: type %s, class %s", - name, type_name, class_name); - rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name, - name_len, type_name, dns_class_name(class), ttl, data_len); - proto_tree_add_text(rr_tree, tvb, cur_offset, data_len, "Data"); - cur_offset += data_len; - break; - } - - return cur_offset - data_start; + goto out; + } + if (rr_tree) { + name_flags = tvb_get_ntohs(tvb, cur_offset); + nbns_add_name_flags(rr_tree, tvb, cur_offset, + name_flags); + } + cur_offset += 2; + data_len -= 2; + + num_names--; + } + + if (data_len < 6) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 6, + "Unit ID: %s", + tvb_ether_to_str(tvb, cur_offset)); + } + cur_offset += 6; + data_len -= 6; + + if (data_len < 1) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 1, + "Jumpers: 0x%x", tvb_get_guint8(tvb, cur_offset)); + } + cur_offset += 1; + data_len -= 1; + + if (data_len < 1) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 1, + "Test result: 0x%x", tvb_get_guint8(tvb, cur_offset)); + } + cur_offset += 1; + data_len -= 1; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Version number: 0x%x", tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Period of statistics: 0x%x", + tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Number of CRCs: %u", tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Number of alignment errors: %u", + tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Number of collisions: %u", tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Number of send aborts: %u", tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 4) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 4, + "Number of good sends: %u", tvb_get_ntohl(tvb, cur_offset)); + } + cur_offset += 4; + data_len -= 4; + + if (data_len < 4) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 4, + "Number of good receives: %u", + tvb_get_ntohl(tvb, cur_offset)); + } + cur_offset += 4; + data_len -= 4; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Number of retransmits: %u", tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Number of no resource conditions: %u", + tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Number of command blocks: %u", + tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Number of pending sessions: %u", + tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Max number of pending sessions: %u", + tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Max total sessions possible: %u", + tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + data_len -= 2; + + if (data_len < 2) { + proto_tree_add_text(rr_tree, tvb, cur_offset, + data_len, "(incomplete entry)"); + break; + } + if (rr_tree) { + proto_tree_add_text(rr_tree, tvb, cur_offset, 2, + "Session data packet size: %u", + tvb_get_ntohs(tvb, cur_offset)); + } + cur_offset += 2; + /*data_len -= 2;*/ + out: + break; + + default: + if (cinfo != NULL) + col_append_fstr(cinfo, COL_INFO, " %s", type_name); + + if (nbns_tree) { + trr = proto_tree_add_text(nbns_tree, tvb, offset, + (cur_offset - offset) + data_len, + "%s: type %s, class %s", + name, type_name, class_name); + rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name, + name_len, type_name, dns_class_name(class), ttl, data_len); + proto_tree_add_text(rr_tree, tvb, cur_offset, data_len, "Data"); + } + cur_offset += data_len; + break; + } + + return cur_offset - offset; } static int dissect_query_records(tvbuff_t *tvb, int cur_off, int nbns_data_offset, int count, column_info *cinfo, proto_tree *nbns_tree) { - int start_off, 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"); - qatree = proto_item_add_subtree(ti, ett_nbns_qry); - } - while (count-- > 0) { - add_off = dissect_nbns_query(tvb, cur_off, nbns_data_offset, - cinfo, qatree); - cur_off += add_off; - } - if (ti != NULL) - proto_item_set_len(ti, cur_off - start_off); - - return cur_off - start_off; + 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"); + qatree = proto_item_add_subtree(ti, ett_nbns_qry); + } + while (count-- > 0) { + add_off = dissect_nbns_query(tvb, cur_off, nbns_data_offset, + cinfo, qatree); + cur_off += add_off; + } + if (ti != NULL) + proto_item_set_len(ti, cur_off - start_off); + + return cur_off - start_off; } - - static int dissect_answer_records(tvbuff_t *tvb, int cur_off, int nbns_data_offset, int count, column_info *cinfo, proto_tree *nbns_tree, int opcode, const char *name) { - 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, "%s", name); - qatree = proto_item_add_subtree(ti, ett_nbns_ans); - } - while (count-- > 0) { - add_off = dissect_nbns_answer(tvb, cur_off, nbns_data_offset, - cinfo, qatree, opcode); - cur_off += add_off; - } - if (ti != NULL) - proto_item_set_len(ti, cur_off - start_off); - return cur_off - start_off; + 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, "%s", name); + qatree = proto_item_add_subtree(ti, ett_nbns_ans); + } + while (count-- > 0) { + add_off = dissect_nbns_answer(tvb, cur_off, nbns_data_offset, + cinfo, qatree, opcode); + cur_off += add_off; + } + if (ti != NULL) + proto_item_set_len(ti, cur_off - start_off); + return cur_off - start_off; } static void dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - int offset = 0; - int nbns_data_offset; - column_info *cinfo; - proto_tree *nbns_tree = NULL; - proto_item *ti; - guint16 id, flags, opcode, quest, ans, auth, add; - int cur_off; - - nbns_data_offset = offset; - - col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBNS"); - col_clear(pinfo->cinfo, COL_INFO); - - /* 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); - - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "%s%s", - val_to_str(opcode, opcode_vals, "Unknown operation (%u)"), - (flags & F_RESPONSE) ? " response" : ""); - cinfo = pinfo->cinfo; - } else { - /* Set "cinfo" to NULL; we pass a NULL "cinfo" to the query - and answer dissectors, as a way of saying that they - shouldn't add stuff to the COL_INFO column (a call to - "check_col(cinfo, COL_INFO)" is more expensive than - a check that a pointer isn't NULL). */ - cinfo = NULL; - } - - if (tree) { - ti = proto_tree_add_item(tree, proto_nbns, tvb, offset, -1, - ENC_NA); - nbns_tree = proto_item_add_subtree(ti, ett_nbns); - - proto_tree_add_uint(nbns_tree, hf_nbns_transaction_id, tvb, - offset + NBNS_ID, 2, id); - - nbns_add_nbns_flags(pinfo->cinfo, nbns_tree, tvb, offset + NBNS_FLAGS, - flags, 0); - } - quest = tvb_get_ntohs(tvb, offset + NBNS_QUEST); - if (tree) { - proto_tree_add_uint(nbns_tree, hf_nbns_count_questions, tvb, - offset + NBNS_QUEST, 2, quest); - } - ans = tvb_get_ntohs(tvb, offset + NBNS_ANS); - if (tree) { - proto_tree_add_uint(nbns_tree, hf_nbns_count_answers, tvb, - offset + NBNS_ANS, 2, ans); - } - auth = tvb_get_ntohs(tvb, offset + NBNS_AUTH); - if (tree) { - proto_tree_add_uint(nbns_tree, hf_nbns_count_auth_rr, tvb, - offset + NBNS_AUTH, 2, auth); - } - add = tvb_get_ntohs(tvb, offset + NBNS_ADD); - if (tree) { - proto_tree_add_uint(nbns_tree, hf_nbns_count_add_rr, tvb, - offset + NBNS_ADD, 2, add); - } - - cur_off = offset + NBNS_HDRLEN; - - if (quest > 0) { - /* If this is a response, don't add information about the - queries to the summary, just add information about the - answers. */ - cur_off += dissect_query_records(tvb, cur_off, - nbns_data_offset, quest, - (!(flags & F_RESPONSE) ? cinfo : NULL), nbns_tree); - } - - if (ans > 0) { - /* If this is a request, don't add information about the - answers to the summary, just add information about the - queries. */ - cur_off += dissect_answer_records(tvb, cur_off, - nbns_data_offset, ans, - ((flags & F_RESPONSE) ? cinfo : NULL), nbns_tree, - opcode, "Answers"); - } - - if (tree) { - /* Don't add information about the authoritative name - servers, or the additional records, to the summary. */ - if (auth > 0) - cur_off += dissect_answer_records(tvb, cur_off, - nbns_data_offset, - 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, opcode, - "Additional records"); - } + int offset = 0; + int nbns_data_offset; + column_info *cinfo; + proto_tree *nbns_tree = NULL; + proto_item *ti; + guint16 id, flags, opcode, quest, ans, auth, add; + int cur_off; + + nbns_data_offset = offset; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBNS"); + col_clear(pinfo->cinfo, COL_INFO); + + /* 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); + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_add_fstr(pinfo->cinfo, COL_INFO, "%s%s", + val_to_str(opcode, opcode_vals, "Unknown operation (%u)"), + (flags & F_RESPONSE) ? " response" : ""); + cinfo = pinfo->cinfo; + } else { + /* Set "cinfo" to NULL; we pass a NULL "cinfo" to the query + and answer dissectors, as a way of saying that they + shouldn't add stuff to the COL_INFO column (a call to + "check_col(cinfo, COL_INFO)" is more expensive than + a check that a pointer isn't NULL). */ + cinfo = NULL; + } + + if (tree) { + ti = proto_tree_add_item(tree, proto_nbns, tvb, offset, -1, + ENC_NA); + nbns_tree = proto_item_add_subtree(ti, ett_nbns); + + proto_tree_add_uint(nbns_tree, hf_nbns_transaction_id, tvb, + offset + NBNS_ID, 2, id); + } + + nbns_add_nbns_flags(pinfo->cinfo, nbns_tree, tvb, offset + NBNS_FLAGS, + flags, 0); + + quest = tvb_get_ntohs(tvb, offset + NBNS_QUEST); + if (tree) { + proto_tree_add_uint(nbns_tree, hf_nbns_count_questions, tvb, + offset + NBNS_QUEST, 2, quest); + } + ans = tvb_get_ntohs(tvb, offset + NBNS_ANS); + if (tree) { + proto_tree_add_uint(nbns_tree, hf_nbns_count_answers, tvb, + offset + NBNS_ANS, 2, ans); + } + auth = tvb_get_ntohs(tvb, offset + NBNS_AUTH); + if (tree) { + proto_tree_add_uint(nbns_tree, hf_nbns_count_auth_rr, tvb, + offset + NBNS_AUTH, 2, auth); + } + add = tvb_get_ntohs(tvb, offset + NBNS_ADD); + if (tree) { + proto_tree_add_uint(nbns_tree, hf_nbns_count_add_rr, tvb, + offset + NBNS_ADD, 2, add); + } + + cur_off = offset + NBNS_HDRLEN; + + if (quest > 0) { + /* If this is a response, don't add information about the + queries to the summary, just add information about the + answers. */ + cur_off += dissect_query_records(tvb, cur_off, + nbns_data_offset, quest, + (!(flags & F_RESPONSE) ? cinfo : NULL), nbns_tree); + } + + if (ans > 0) { + /* If this is a request, don't add information about the + answers to the summary, just add information about the + queries. */ + cur_off += dissect_answer_records(tvb, cur_off, + nbns_data_offset, ans, + ((flags & F_RESPONSE) ? cinfo : NULL), nbns_tree, + opcode, "Answers"); + } + + /* Don't add information about the authoritative name + servers, or the additional records, to the summary. */ + if (auth > 0) + cur_off += dissect_answer_records(tvb, cur_off, + nbns_data_offset, + auth, NULL, nbns_tree, opcode, + "Authoritative nameservers"); + + if (add > 0) + /*cur_off += */dissect_answer_records(tvb, cur_off, + nbns_data_offset, + add, NULL, nbns_tree, opcode, + "Additional records"); } /* NetBIOS datagram packet, from RFC 1002, page 32 */ struct nbdgm_header { - guint8 msg_type; - struct { - guint8 more; - guint8 first; - guint8 node_type; - } flags; - guint16 dgm_id; - guint32 src_ip; - guint16 src_port; - - /* For packets with data */ - guint16 dgm_length; - guint16 pkt_offset; - - /* For error packets */ - guint8 error_code; + guint8 msg_type; + struct { + guint8 more; + guint8 first; + guint8 node_type; + } flags; + guint16 dgm_id; + guint32 src_ip; + guint16 src_port; + + /* For packets with data */ + guint16 dgm_length; + guint16 pkt_offset; + + /* For error packets */ + guint8 error_code; }; /* @@ -1166,182 +1223,182 @@ struct nbdgm_header { #define NBDS_NEG_QUERY_RESPONSE 0x16 static const value_string nbds_msgtype_vals[] = { - { NBDS_DIRECT_UNIQUE, "Direct_unique datagram" }, - { NBDS_DIRECT_GROUP, "Direct_group datagram" }, - { NBDS_BROADCAST, "Broadcast datagram" }, - { NBDS_ERROR, "Datagram error" }, - { NBDS_QUERY_REQUEST, "Datagram query request" }, - { NBDS_POS_QUERY_RESPONSE, "Datagram positive query response" }, - { NBDS_NEG_QUERY_RESPONSE, "Datagram negative query response" }, - { 0, NULL } + { NBDS_DIRECT_UNIQUE, "Direct_unique datagram" }, + { NBDS_DIRECT_GROUP, "Direct_group datagram" }, + { NBDS_BROADCAST, "Broadcast datagram" }, + { NBDS_ERROR, "Datagram error" }, + { NBDS_QUERY_REQUEST, "Datagram query request" }, + { NBDS_POS_QUERY_RESPONSE, "Datagram positive query response" }, + { NBDS_NEG_QUERY_RESPONSE, "Datagram negative query response" }, + { 0, NULL } }; static const value_string node_type_vals[] = { - { 0, "B node" }, - { 1, "P node" }, - { 2, "M node" }, - { 3, "NBDD" }, - { 0, NULL } + { 0, "B node" }, + { 1, "P node" }, + { 2, "M node" }, + { 3, "NBDD" }, + { 0, NULL } }; static void dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - int offset = 0; - proto_tree *nbdgm_tree = NULL; - proto_item *ti = NULL; - struct nbdgm_header header; - int flags; - tvbuff_t *next_tvb; - - static const value_string error_codes[] = { - { 0x82, "Destination name not present" }, - { 0x83, "Invalid source name format" }, - { 0x84, "Invalid destination name format" }, - { 0x00, NULL } - }; - - char *name; - int name_type; - int len; - - name=ep_alloc(MAX_NAME_LEN); - - col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBDS"); - 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; - header.flags.node_type = (flags & 12) >> 2; - - header.dgm_id = tvb_get_ntohs(tvb, offset+2); - header.src_ip = tvb_get_ipv4(tvb, offset+4); - header.src_port = tvb_get_ntohs(tvb, offset+8); - - /* avoid gcc warnings */ - header.dgm_length = 0; - header.pkt_offset = 0; - header.error_code = 0; - switch (header.msg_type) { - - case NBDS_DIRECT_UNIQUE: - case NBDS_DIRECT_GROUP: - case NBDS_BROADCAST: - header.dgm_length = tvb_get_ntohs(tvb, offset+10); - header.pkt_offset = tvb_get_ntohs(tvb, offset+12); - break; - - case NBDS_ERROR: - header.error_code = tvb_get_guint8(tvb, offset+10); - break; - } - - col_add_str(pinfo->cinfo, COL_INFO, - val_to_str(header.msg_type, nbds_msgtype_vals, - "Unknown message type (0x%02X)")); - - if (tree) { - ti = proto_tree_add_item(tree, proto_nbdgm, tvb, offset, -1, - ENC_NA); - nbdgm_tree = proto_item_add_subtree(ti, ett_nbdgm); - - proto_tree_add_uint(nbdgm_tree, hf_nbdgm_type, tvb, - offset, 1, - header.msg_type); - proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_fragment, tvb, - offset+1, 1, - header.flags.more); - proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_first, tvb, - offset+1, 1, - header.flags.first); - proto_tree_add_uint(nbdgm_tree, hf_nbdgm_node_type, tvb, - offset+1, 1, - header.flags.node_type); - - proto_tree_add_uint(nbdgm_tree, hf_nbdgm_datagram_id, tvb, - offset+2, 2, header.dgm_id); - proto_tree_add_ipv4(nbdgm_tree, hf_nbdgm_src_ip, tvb, - offset+4, 4, header.src_ip); - proto_tree_add_uint(nbdgm_tree, hf_nbdgm_src_port, tvb, - offset+8, 2, header.src_port); - - } - - offset += 10; - - switch (header.msg_type) { - - case NBDS_DIRECT_UNIQUE: - case NBDS_DIRECT_GROUP: - case NBDS_BROADCAST: - if (tree) { - proto_tree_add_text(nbdgm_tree, tvb, offset, 2, - "Datagram length: %d bytes", header.dgm_length); - proto_tree_add_text(nbdgm_tree, tvb, offset+2, 2, - "Packet offset: %d bytes", header.pkt_offset); - } - - offset += 4; - - /* Source name */ - len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); - - if (tree) { - add_name_and_type(nbdgm_tree, tvb, offset, len, - "Source name", name, name_type); - } - offset += len; - - /* Destination name */ - len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); - - if (tree) { - add_name_and_type(nbdgm_tree, tvb, offset, len, - "Destination name", name, name_type); - } - offset += len; - - /* - * Here we can pass the packet off to the next protocol. - * Set the length of our top-level tree item to include - * only our stuff. - * - * XXX - take the datagram length into account? - */ - if (ti != NULL) - proto_item_set_len(ti, offset); - next_tvb = tvb_new_subset_remaining(tvb, offset); - dissect_netbios_payload(next_tvb, pinfo, tree); - break; - - case NBDS_ERROR: - if (tree) { - proto_tree_add_text(nbdgm_tree, tvb, offset, 1, "Error code: %s", + int offset = 0; + proto_tree *nbdgm_tree = NULL; + proto_item *ti = NULL; + struct nbdgm_header header; + int flags; + tvbuff_t *next_tvb; + + static const value_string error_codes[] = { + { 0x82, "Destination name not present" }, + { 0x83, "Invalid source name format" }, + { 0x84, "Invalid destination name format" }, + { 0x00, NULL } + }; + + char *name; + int name_type; + int len; + + name = ep_alloc(MAX_NAME_LEN); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBDS"); + 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; + header.flags.node_type = (flags & 12) >> 2; + + header.dgm_id = tvb_get_ntohs(tvb, offset+2); + header.src_ip = tvb_get_ipv4( tvb, offset+4); + header.src_port = tvb_get_ntohs(tvb, offset+8); + + /* avoid gcc warnings */ + header.dgm_length = 0; + header.pkt_offset = 0; + header.error_code = 0; + switch (header.msg_type) { + + case NBDS_DIRECT_UNIQUE: + case NBDS_DIRECT_GROUP: + case NBDS_BROADCAST: + header.dgm_length = tvb_get_ntohs(tvb, offset+10); + header.pkt_offset = tvb_get_ntohs(tvb, offset+12); + break; + + case NBDS_ERROR: + header.error_code = tvb_get_guint8(tvb, offset+10); + break; + } + + col_add_str(pinfo->cinfo, COL_INFO, + val_to_str(header.msg_type, nbds_msgtype_vals, + "Unknown message type (0x%02X)")); + + if (tree) { + ti = proto_tree_add_item(tree, proto_nbdgm, tvb, offset, -1, + ENC_NA); + nbdgm_tree = proto_item_add_subtree(ti, ett_nbdgm); + + proto_tree_add_uint(nbdgm_tree, hf_nbdgm_type, tvb, + offset, 1, + header.msg_type); + proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_fragment, tvb, + offset+1, 1, + header.flags.more); + proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_first, tvb, + offset+1, 1, + header.flags.first); + proto_tree_add_uint(nbdgm_tree, hf_nbdgm_node_type, tvb, + offset+1, 1, + header.flags.node_type); + + proto_tree_add_uint(nbdgm_tree, hf_nbdgm_datagram_id, tvb, + offset+2, 2, header.dgm_id); + proto_tree_add_ipv4(nbdgm_tree, hf_nbdgm_src_ip, tvb, + offset+4, 4, header.src_ip); + proto_tree_add_uint(nbdgm_tree, hf_nbdgm_src_port, tvb, + offset+8, 2, header.src_port); + + } + + offset += 10; + + switch (header.msg_type) { + + case NBDS_DIRECT_UNIQUE: + case NBDS_DIRECT_GROUP: + case NBDS_BROADCAST: + if (tree) { + proto_tree_add_text(nbdgm_tree, tvb, offset, 2, + "Datagram length: %d bytes", header.dgm_length); + proto_tree_add_text(nbdgm_tree, tvb, offset+2, 2, + "Packet offset: %d bytes", header.pkt_offset); + } + + offset += 4; + + /* Source name */ + len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); + + if (tree) { + add_name_and_type(nbdgm_tree, tvb, offset, len, + "Source name", name, name_type); + } + offset += len; + + /* Destination name */ + len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); + + if (tree) { + add_name_and_type(nbdgm_tree, tvb, offset, len, + "Destination name", name, name_type); + } + offset += len; + + /* + * Here we can pass the packet off to the next protocol. + * Set the length of our top-level tree item to include + * only our stuff. + * + * XXX - take the datagram length into account? + */ + if (ti != NULL) + proto_item_set_len(ti, offset); + next_tvb = tvb_new_subset_remaining(tvb, offset); + dissect_netbios_payload(next_tvb, pinfo, tree); + break; + + case NBDS_ERROR: + if (tree) { + proto_tree_add_text(nbdgm_tree, tvb, offset, 1, "Error code: %s", val_to_str(header.error_code, error_codes, "Unknown (0x%x)")); - } - offset += 1; - if (ti != NULL) - proto_item_set_len(ti, offset); - break; - - case NBDS_QUERY_REQUEST: - case NBDS_POS_QUERY_RESPONSE: - case NBDS_NEG_QUERY_RESPONSE: - /* Destination name */ - len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); - - if (tree) { - add_name_and_type(nbdgm_tree, tvb, offset, len, - "Destination name", name, name_type); - } - offset += len; - if (ti != NULL) - proto_item_set_len(ti, offset); - break; - } + } + offset += 1; + if (ti != NULL) + proto_item_set_len(ti, offset); + break; + + case NBDS_QUERY_REQUEST: + case NBDS_POS_QUERY_RESPONSE: + case NBDS_NEG_QUERY_RESPONSE: + /* Destination name */ + len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); + + if (tree) { + add_name_and_type(nbdgm_tree, tvb, offset, len, + "Destination name", name, name_type); + } + offset += len; + if (ti != NULL) + proto_item_set_len(ti, offset); + break; + } } /* @@ -1355,13 +1412,13 @@ dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) #define SESSION_KEEP_ALIVE 0x85 static const value_string message_types[] = { - { SESSION_MESSAGE, "Session message" }, - { SESSION_REQUEST, "Session request" }, - { POSITIVE_SESSION_RESPONSE, "Positive session response" }, - { NEGATIVE_SESSION_RESPONSE, "Negative session response" }, - { RETARGET_SESSION_RESPONSE, "Retarget session response" }, - { SESSION_KEEP_ALIVE, "Session keep-alive" }, - { 0x0, NULL } + { SESSION_MESSAGE, "Session message" }, + { SESSION_REQUEST, "Session request" }, + { POSITIVE_SESSION_RESPONSE, "Positive session response" }, + { NEGATIVE_SESSION_RESPONSE, "Negative session response" }, + { RETARGET_SESSION_RESPONSE, "Retarget session response" }, + { SESSION_KEEP_ALIVE, "Session keep-alive" }, + { 0x0, NULL } }; /* @@ -1370,12 +1427,12 @@ static const value_string message_types[] = { #define NBSS_FLAGS_E 0x1 static const value_string error_codes[] = { - { 0x80, "Not listening on called name" }, - { 0x81, "Not listening for called name" }, - { 0x82, "Called name not present" }, - { 0x83, "Called name present, but insufficient resources" }, - { 0x8F, "Unspecified error" }, - { 0x0, NULL } + { 0x80, "Not listening on called name" }, + { 0x81, "Not listening for called name" }, + { 0x82, "Called name not present" }, + { 0x83, "Called name present, but insufficient resources" }, + { 0x8F, "Unspecified error" }, + { 0x0, NULL } }; /* @@ -1396,207 +1453,207 @@ static int dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int is_cifs) { - proto_tree *nbss_tree = NULL; - proto_item *ti = NULL; - proto_tree *field_tree; - proto_item *tf; - guint8 msg_type; - guint8 flags; - volatile int length; - int length_remaining; - int len; - char *name; - int name_type; - gint reported_len; - tvbuff_t *next_tvb; - const char *saved_proto; - void *pd_save; - - name=ep_alloc(MAX_NAME_LEN); - - /* Desegmentation */ - length_remaining = tvb_length_remaining(tvb, offset); - - /* - * Can we do reassembly? - */ - if (nbss_desegment && pinfo->can_desegment) { - /* - * Yes - is the NBSS header split across segment boundaries? - */ - if (length_remaining < 4) { - /* - * Yes. Tell our caller how many more bytes - * we need. - */ - return -(4 - length_remaining); - } - } - - /* - * Get the length of the NBSS message. - */ - if (is_cifs) { - flags = 0; - length = tvb_get_ntoh24(tvb, offset + 1); - } else { - flags = tvb_get_guint8(tvb, offset + 1); - length = tvb_get_ntohs(tvb, offset + 2); - if (flags & NBSS_FLAGS_E) - length += 65536; - } - - /* give a hint to TCP where the next PDU starts - * so that it can attempt to find it in case it starts - * somewhere in the middle of a segment. - */ - if(!pinfo->fd->flags.visited){ - /* 'Only' SMB is transported ontop of this so make sure - * there is an SMB header there ... - */ - if( ((length+4)>tvb_reported_length_remaining(tvb, offset)) - &&(tvb_length_remaining(tvb, offset)>=8) - &&(tvb_get_guint8(tvb,offset+5)=='S') - &&(tvb_get_guint8(tvb,offset+6)=='M') - &&(tvb_get_guint8(tvb,offset+7)=='B') ){ - pinfo->want_pdu_tracking=2; - pinfo->bytes_until_next_pdu=(length+4)-tvb_reported_length_remaining(tvb, offset); - } - } - - /* - * Can we do reassembly? - */ - if (nbss_desegment && pinfo->can_desegment) { - /* - * Yes - is the NBSS message split across segment boundaries? - */ - if (length_remaining < length + 4) { - /* - * Yes. Tell our caller how many more bytes - * we need. - */ - return -((length + 4) - length_remaining); - } - } - - msg_type = tvb_get_guint8(tvb, offset); - - if (tree) { - ti = proto_tree_add_item(tree, proto_nbss, tvb, offset, length + 4, ENC_NA); - nbss_tree = proto_item_add_subtree(ti, ett_nbss); - - proto_tree_add_item(nbss_tree, hf_nbss_type, tvb, offset, 1, ENC_NA); - } - - offset += 1; - - if (is_cifs) { - if (tree) { - proto_tree_add_item(nbss_tree, hf_nbss_cifs_length, tvb, offset, 3, ENC_BIG_ENDIAN); - } - offset += 3; - } else { - if (tree) { - tf = proto_tree_add_uint(nbss_tree, hf_nbss_flags, tvb, offset, 1, flags); - field_tree = proto_item_add_subtree(tf, ett_nbss_flags); - proto_tree_add_text(field_tree, tvb, offset, 1, "%s", - decode_boolean_bitfield(flags, NBSS_FLAGS_E, - 8, "Add 65536 to length", "Add 0 to length")); - } - offset += 1; - - if (tree) { - proto_tree_add_uint_format(nbss_tree, hf_nbss_length, tvb, offset, 2, - length, "Length: %u", length); - } - - offset += 2; - } - - switch (msg_type) { - - case SESSION_REQUEST: - len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); - if (tree) + proto_tree *nbss_tree = NULL; + proto_item *ti = NULL; + proto_tree *field_tree; + proto_item *tf; + guint8 msg_type; + guint8 flags; + volatile int length; + int length_remaining; + int len; + char *name; + int name_type; + gint reported_len; + tvbuff_t *next_tvb; + const char *saved_proto; + void *pd_save; + + name = ep_alloc(MAX_NAME_LEN); + + /* Desegmentation */ + length_remaining = tvb_length_remaining(tvb, offset); + + /* + * Can we do reassembly? + */ + if (nbss_desegment && pinfo->can_desegment) { + /* + * Yes - is the NBSS header split across segment boundaries? + */ + if (length_remaining < 4) { + /* + * Yes. Tell our caller how many more bytes + * we need. + */ + return -(4 - length_remaining); + } + } + + /* + * Get the length of the NBSS message. + */ + if (is_cifs) { + flags = 0; + length = tvb_get_ntoh24(tvb, offset + 1); + } else { + flags = tvb_get_guint8(tvb, offset + 1); + length = tvb_get_ntohs(tvb, offset + 2); + if (flags & NBSS_FLAGS_E) + length += 65536; + } + + /* give a hint to TCP where the next PDU starts + * so that it can attempt to find it in case it starts + * somewhere in the middle of a segment. + */ + if(!pinfo->fd->flags.visited){ + /* 'Only' SMB is transported ontop of this so make sure + * there is an SMB header there ... + */ + if( ((length+4)>tvb_reported_length_remaining(tvb, offset)) + &&(tvb_length_remaining(tvb, offset) >= 8) + &&(tvb_get_guint8(tvb,offset+5) == 'S') + &&(tvb_get_guint8(tvb,offset+6) == 'M') + &&(tvb_get_guint8(tvb,offset+7) == 'B') ){ + pinfo->want_pdu_tracking = 2; + pinfo->bytes_until_next_pdu = (length+4)-tvb_reported_length_remaining(tvb, offset); + } + } + + /* + * Can we do reassembly? + */ + if (nbss_desegment && pinfo->can_desegment) { + /* + * Yes - is the NBSS message split across segment boundaries? + */ + if (length_remaining < length + 4) { + /* + * Yes. Tell our caller how many more bytes + * we need. + */ + return -((length + 4) - length_remaining); + } + } + + msg_type = tvb_get_guint8(tvb, offset); + + if (tree) { + ti = proto_tree_add_item(tree, proto_nbss, tvb, offset, length + 4, ENC_NA); + nbss_tree = proto_item_add_subtree(ti, ett_nbss); + + proto_tree_add_item(nbss_tree, hf_nbss_type, tvb, offset, 1, ENC_NA); + } + + offset += 1; + + if (is_cifs) { + if (tree) { + proto_tree_add_item(nbss_tree, hf_nbss_cifs_length, tvb, offset, 3, ENC_BIG_ENDIAN); + } + offset += 3; + } else { + if (tree) { + tf = proto_tree_add_uint(nbss_tree, hf_nbss_flags, tvb, offset, 1, flags); + field_tree = proto_item_add_subtree(tf, ett_nbss_flags); + proto_tree_add_text(field_tree, tvb, offset, 1, "%s", + decode_boolean_bitfield(flags, NBSS_FLAGS_E, + 8, "Add 65536 to length", "Add 0 to length")); + } + offset += 1; + + if (tree) { + proto_tree_add_uint_format(nbss_tree, hf_nbss_length, tvb, offset, 2, + length, "Length: %u", length); + } + + offset += 2; + } + + switch (msg_type) { + + case SESSION_REQUEST: + len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); + if (tree) add_name_and_type(nbss_tree, tvb, offset, len, - "Called name", name, name_type); - offset += len; + "Called name", name, name_type); + offset += len; - col_append_fstr(pinfo->cinfo, COL_INFO, ", to %s ", name); + col_append_fstr(pinfo->cinfo, COL_INFO, ", to %s ", name); - len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); + len = get_nbns_name(tvb, offset, offset, name, MAX_NAME_LEN, &name_type); - if (tree) + if (tree) add_name_and_type(nbss_tree, tvb, offset, len, - "Calling name", name, name_type); + "Calling name", name, name_type); - col_append_fstr(pinfo->cinfo, COL_INFO, "from %s", name); + col_append_fstr(pinfo->cinfo, COL_INFO, "from %s", name); - break; + break; - case NEGATIVE_SESSION_RESPONSE: - if (tree) + case NEGATIVE_SESSION_RESPONSE: + 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)")); - col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", - val_to_str(tvb_get_guint8(tvb, offset), - error_codes, "Unknown (%x)")); + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str(tvb_get_guint8(tvb, offset), + error_codes, "Unknown (%x)")); - break; + break; - case RETARGET_SESSION_RESPONSE: - if (tree) + case RETARGET_SESSION_RESPONSE: + if (tree) proto_tree_add_text(nbss_tree, tvb, offset, 4, "Retarget IP address: %s", tvb_ip_to_str(tvb, offset)); - offset += 4; + offset += 4; - if (tree) + if (tree) proto_tree_add_text(nbss_tree, tvb, offset, 2, "Retarget port: %u", tvb_get_ntohs(tvb, offset)); - break; - - case SESSION_MESSAGE: - /* - * Here we can pass the message off to the next protocol. - * Set the length of our top-level tree item to include - * only our stuff. - */ - len = tvb_length_remaining(tvb, offset); - reported_len = tvb_reported_length_remaining(tvb, offset); - if (len > length) + break; + + case SESSION_MESSAGE: + /* + * Here we can pass the message off to the next protocol. + * Set the length of our top-level tree item to include + * only our stuff. + */ + len = tvb_length_remaining(tvb, offset); + reported_len = tvb_reported_length_remaining(tvb, offset); + if (len > length) len = length; - if (reported_len > length) + if (reported_len > length) reported_len = length; - next_tvb = tvb_new_subset(tvb, offset, len, reported_len); - - /* - * Catch the ReportedBoundsError exception; if this - * particular message happens to get a ReportedBoundsError - * exception, that doesn't mean that we should stop - * dissecting NetBIOS messages within this frame or chunk - * of reassembled data. - * - * If it gets a BoundsError, we can stop, as there's nothing - * more to see, so we just re-throw it. - */ - saved_proto = pinfo->current_proto; - pd_save = pinfo->private_data; - TRY { + next_tvb = tvb_new_subset(tvb, offset, len, reported_len); + + /* + * Catch the ReportedBoundsError exception; if this + * particular message happens to get a ReportedBoundsError + * exception, that doesn't mean that we should stop + * dissecting NetBIOS messages within this frame or chunk + * of reassembled data. + * + * If it gets a BoundsError, we can stop, as there's nothing + * more to see, so we just re-throw it. + */ + saved_proto = pinfo->current_proto; + pd_save = pinfo->private_data; + TRY { dissect_netbios_payload(next_tvb, pinfo, tree); - } - CATCH(BoundsError) { + } + CATCH(BoundsError) { RETHROW; - } - CATCH(ReportedBoundsError) { + } + CATCH(ReportedBoundsError) { /* Restore the private_data structure in case one of the * called dissectors modified it (and, due to the exception, * was unable to restore it). @@ -1604,389 +1661,392 @@ dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo, pinfo->private_data = pd_save; show_reported_bounds_error(tvb, pinfo, tree); pinfo->current_proto = saved_proto; - } - ENDTRY; - break; + } + ENDTRY; + break; - } - return length + 4; + } + return length + 4; } static void dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - struct tcpinfo *tcpinfo = pinfo->private_data; - int offset = 0; - int max_data; - guint8 msg_type; - guint8 flags; - guint32 length; - int len; - gboolean is_cifs; - proto_tree *nbss_tree; - proto_item *ti; - - col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBSS"); - col_clear(pinfo->cinfo, COL_INFO); - - max_data = tvb_length(tvb); - - msg_type = tvb_get_guint8(tvb, offset); - - if (pinfo->match_uint == TCP_PORT_CIFS) { - /* - * Windows 2000 CIFS clients can dispense completely - * with the NETBIOS encapsulation and directly use CIFS - * over TCP. As would be expected, the framing is - * identical, except that the length is 24 bits instead - * of 17. The only message types used are - * SESSION_MESSAGE and SESSION_KEEP_ALIVE. - */ - is_cifs = TRUE; - } else { - is_cifs = FALSE; - } - - /* - * This might be a continuation of an earlier message. - * (Yes, that might be true even if we're doing TCP reassembly, - * as the first TCP segment in the capture might start in the - * middle of an NBNS message.) - */ - - /* - * If this isn't reassembled data, check to see whether it - * looks like a continuation of a message. - * (If it is reassembled data, it shouldn't be a continuation, - * as reassembly should've gathered the continuations together - * into a message.) - */ - if (!tcpinfo->is_reassembled) { - if (max_data < 4) { - /* - * Not enough data for an NBSS header; assume - * it's a continuation of a message. - * - * XXX - if there's not enough data, we should - * attempt to reassemble the data, if the first byte - * is a valid message type. - */ - goto continuation; - } - - /* - * The larged size in for non-SMB NBSS traffic is - * 17 bits (0x1FFFF). - * - * The SMB1 unix extensions and the SMB2 multi credit - * feature allow more than 17 bits (0x1FFFF), they allow - * 24 bits (0xFFFFFF). - * - * So if it is a SESSION_MESSAGE and SMB1 or SMB2 - * mark it as is_cifs. - */ - if (tvb_length_remaining(tvb, offset) >=8 - && tvb_get_guint8(tvb,offset+0) == SESSION_MESSAGE - && tvb_get_guint8(tvb,offset+5) == 'S' - && tvb_get_guint8(tvb,offset+6) == 'M' - && tvb_get_guint8(tvb,offset+7) == 'B') { - is_cifs = TRUE; - } - - /* - * We have enough data for an NBSS header. - * Get the flags and length of the message, - * and see if they're sane. - */ - if (is_cifs) { - flags = 0; - length = tvb_get_ntoh24(tvb, offset + 1); - } else { - flags = tvb_get_guint8(tvb, offset + 1); - length = tvb_get_ntohs(tvb, offset + 2); - if (flags & NBSS_FLAGS_E) - length += 0x10000; - } - if ((flags & (~NBSS_FLAGS_E)) != 0) { - /* - * A bogus flag was set; assume it's a continuation. - */ - goto continuation; - } - - switch (msg_type) { - - case SESSION_MESSAGE: - /* - * This is variable-length. - * All we know is that it shouldn't be zero. - * (XXX - can we get zero-length messages? - * Not with SMB, but perhaps other NetBIOS-based - * protocols have them.) - */ - if (length == 0) - goto continuation; - - break; - - case SESSION_REQUEST: - /* - * This is variable-length. - * The names are DNS-encoded 32-byte values; - * we need at least 2 bytes (one for each name; - * actually, we should have more for the first - * name, as there's no name preceding it so - * there should be no compression), and we - * shouldn't have more than 128 bytes (actually, - * we shouldn't have that many). - * - * XXX - actually, Mac OS X 10.1 (yes, that's - * redundant, but that's what Apple calls it, - * not Mac OS X.1) puts names longer than 16 - * characters into session request messages, - * so we can have more than 32 bytes of - * name value, so we can have more than 128 - * bytes of data. - */ - if (length < 2 || length > 256) - goto continuation; - break; - - case POSITIVE_SESSION_RESPONSE: - /* - * This has no data, so the length must be zero. - */ - if (length != 0) - goto continuation; - break; - - case NEGATIVE_SESSION_RESPONSE: - /* - * This has 1 byte of data. - */ - if (length != 1) - goto continuation; - break; - - case RETARGET_SESSION_RESPONSE: - /* - * This has 6 bytes of data. - */ - if (length != 6) - goto continuation; - break; - - case SESSION_KEEP_ALIVE: - /* - * This has no data, so the length must be zero. - */ - if (length != 0) - goto continuation; - break; - - default: - /* - * Unknown message type; assume it's a continuation. - */ - goto continuation; - } - } - - col_add_str(pinfo->cinfo, COL_INFO, - val_to_str(msg_type, message_types, "Unknown (%02x)")); - - while (tvb_reported_length_remaining(tvb, offset) > 0) { - len = dissect_nbss_packet(tvb, offset, pinfo, tree, is_cifs); - if (len < 0) { - /* - * We need more data to dissect this, and - * desegmentation is enabled. "-len" is the - * number of additional bytes of data we need. - * - * Tell the TCP dissector where the data for this - * message starts in the data it handed us, and - * how many more bytes we need, and return. - */ - pinfo->desegment_offset = offset; - pinfo->desegment_len = -len; - return; - } - offset += len; - } - - return; + struct tcpinfo *tcpinfo = pinfo->private_data; + int offset = 0; + int max_data; + guint8 msg_type; + guint8 flags; + guint32 length; + int len; + gboolean is_cifs; + proto_tree *nbss_tree; + proto_item *ti; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBSS"); + col_clear(pinfo->cinfo, COL_INFO); + + max_data = tvb_length(tvb); + + msg_type = tvb_get_guint8(tvb, offset); + + if (pinfo->match_uint == TCP_PORT_CIFS) { + /* + * Windows 2000 CIFS clients can dispense completely + * with the NETBIOS encapsulation and directly use CIFS + * over TCP. As would be expected, the framing is + * identical, except that the length is 24 bits instead + * of 17. The only message types used are + * SESSION_MESSAGE and SESSION_KEEP_ALIVE. + */ + is_cifs = TRUE; + } else { + is_cifs = FALSE; + } + + /* + * This might be a continuation of an earlier message. + * (Yes, that might be true even if we're doing TCP reassembly, + * as the first TCP segment in the capture might start in the + * middle of an NBNS message.) + */ + + /* + * If this isn't reassembled data, check to see whether it + * looks like a continuation of a message. + * (If it is reassembled data, it shouldn't be a continuation, + * as reassembly should've gathered the continuations together + * into a message.) + */ + if (!tcpinfo->is_reassembled) { + if (max_data < 4) { + /* + * Not enough data for an NBSS header; assume + * it's a continuation of a message. + * + * XXX - if there's not enough data, we should + * attempt to reassemble the data, if the first byte + * is a valid message type. + */ + goto continuation; + } + + /* + * The larged size in for non-SMB NBSS traffic is + * 17 bits (0x1FFFF). + * + * The SMB1 unix extensions and the SMB2 multi credit + * feature allow more than 17 bits (0x1FFFF), they allow + * 24 bits (0xFFFFFF). + * + * So if it is a SESSION_MESSAGE and SMB1 or SMB2 + * mark it as is_cifs. + */ + if (tvb_length_remaining(tvb, offset) >= 8 + && tvb_get_guint8(tvb,offset+0) == SESSION_MESSAGE + && tvb_get_guint8(tvb,offset+5) == 'S' + && tvb_get_guint8(tvb,offset+6) == 'M' + && tvb_get_guint8(tvb,offset+7) == 'B') { + is_cifs = TRUE; + } + + /* + * We have enough data for an NBSS header. + * Get the flags and length of the message, + * and see if they're sane. + */ + if (is_cifs) { + flags = 0; + length = tvb_get_ntoh24(tvb, offset + 1); + } else { + flags = tvb_get_guint8(tvb, offset + 1); + length = tvb_get_ntohs(tvb, offset + 2); + if (flags & NBSS_FLAGS_E) + length += 0x10000; + } + if ((flags & (~NBSS_FLAGS_E)) != 0) { + /* + * A bogus flag was set; assume it's a continuation. + */ + goto continuation; + } + + switch (msg_type) { + + case SESSION_MESSAGE: + /* + * This is variable-length. + * All we know is that it shouldn't be zero. + * (XXX - can we get zero-length messages? + * Not with SMB, but perhaps other NetBIOS-based + * protocols have them.) + */ + if (length == 0) + goto continuation; + + break; + + case SESSION_REQUEST: + /* + * This is variable-length. + * The names are DNS-encoded 32-byte values; + * we need at least 2 bytes (one for each name; + * actually, we should have more for the first + * name, as there's no name preceding it so + * there should be no compression), and we + * shouldn't have more than 128 bytes (actually, + * we shouldn't have that many). + * + * XXX - actually, Mac OS X 10.1 (yes, that's + * redundant, but that's what Apple calls it, + * not Mac OS X.1) puts names longer than 16 + * characters into session request messages, + * so we can have more than 32 bytes of + * name value, so we can have more than 128 + * bytes of data. + */ + if (length < 2 || length > 256) + goto continuation; + break; + + case POSITIVE_SESSION_RESPONSE: + /* + * This has no data, so the length must be zero. + */ + if (length != 0) + goto continuation; + break; + + case NEGATIVE_SESSION_RESPONSE: + /* + * This has 1 byte of data. + */ + if (length != 1) + goto continuation; + break; + + case RETARGET_SESSION_RESPONSE: + /* + * This has 6 bytes of data. + */ + if (length != 6) + goto continuation; + break; + + case SESSION_KEEP_ALIVE: + /* + * This has no data, so the length must be zero. + */ + if (length != 0) + goto continuation; + break; + + default: + /* + * Unknown message type; assume it's a continuation. + */ + goto continuation; + } + } + + col_add_str(pinfo->cinfo, COL_INFO, + val_to_str(msg_type, message_types, "Unknown (%02x)")); + + while (tvb_reported_length_remaining(tvb, offset) > 0) { + len = dissect_nbss_packet(tvb, offset, pinfo, tree, is_cifs); + if (len < 0) { + /* + * We need more data to dissect this, and + * desegmentation is enabled. "-len" is the + * number of additional bytes of data we need. + * + * Tell the TCP dissector where the data for this + * message starts in the data it handed us, and + * how many more bytes we need, and return. + */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = -len; + return; + } + offset += len; + } + + return; continuation: - /* - * It looks like a continuation. - */ - col_set_str(pinfo->cinfo, COL_INFO, "NBSS Continuation Message"); - - if (tree) { - ti = proto_tree_add_item(tree, proto_nbss, tvb, 0, -1, ENC_NA); - nbss_tree = proto_item_add_subtree(ti, ett_nbss); - proto_tree_add_text(nbss_tree, tvb, 0, -1, "Continuation data"); - } + /* + * It looks like a continuation. + */ + col_set_str(pinfo->cinfo, COL_INFO, "NBSS Continuation Message"); + + if (tree) { + ti = proto_tree_add_item(tree, proto_nbss, tvb, 0, -1, ENC_NA); + nbss_tree = proto_item_add_subtree(ti, ett_nbss); + proto_tree_add_text(nbss_tree, tvb, 0, -1, "Continuation data"); + } } void proto_register_nbt(void) { - static hf_register_info hf_nbns[] = { - { &hf_nbns_flags, - { "Flags", "nbns.flags", - FT_UINT16, BASE_HEX, NULL, 0x0, - NULL, 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, - NULL, HFILL }}, - { &hf_nbns_transaction_id, - { "Transaction ID", "nbns.id", - FT_UINT16, BASE_HEX, NULL, 0x0, - "Identification of transaction", HFILL }}, - { &hf_nbns_count_questions, - { "Questions", "nbns.count.queries", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Number of queries in packet", HFILL }}, - { &hf_nbns_count_answers, - { "Answer RRs", "nbns.count.answers", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Number of answers in packet", HFILL }}, - { &hf_nbns_count_auth_rr, - { "Authority RRs", "nbns.count.auth_rr", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Number of authoritative records in packet", HFILL }}, - { &hf_nbns_count_add_rr, - { "Additional RRs", "nbns.count.add_rr", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Number of additional records in packet", HFILL }} - }; - - static hf_register_info hf_nbdgm[] = { - { &hf_nbdgm_type, - { "Message Type", "nbdgm.type", - FT_UINT8, BASE_DEC, VALS(nbds_msgtype_vals), 0x0, - "NBDGM message type", HFILL }}, - { &hf_nbdgm_fragment, - { "More fragments follow", "nbdgm.next", - FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, - "TRUE if more fragments follow", HFILL }}, - { &hf_nbdgm_first, - { "This is first fragment", "nbdgm.first", - FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, - "TRUE if first fragment", HFILL }}, - { &hf_nbdgm_node_type, - { "Node Type", "nbdgm.node_type", - FT_UINT8, BASE_DEC, VALS(node_type_vals), 0x0, - NULL, HFILL }}, - { &hf_nbdgm_datagram_id, - { "Datagram ID", "nbdgm.dgram_id", - FT_UINT16, BASE_HEX, NULL, 0x0, - "Datagram identifier", HFILL }}, - { &hf_nbdgm_src_ip, - { "Source IP", "nbdgm.src.ip", - FT_IPv4, BASE_NONE, NULL, 0x0, - "Source IPv4 address", HFILL }}, - { &hf_nbdgm_src_port, - { "Source Port", "nbdgm.src.port", - FT_UINT16, BASE_DEC, NULL, 0x0, - NULL, HFILL }} - }; - - static hf_register_info hf_nbss[] = { - { &hf_nbss_type, - { "Message Type", "nbss.type", - FT_UINT8, BASE_HEX, VALS(message_types), 0x0, - "NBSS message type", HFILL }}, - { &hf_nbss_flags, - { "Flags", "nbss.flags", - FT_UINT8, BASE_HEX, NULL, 0x0, - "NBSS message flags", HFILL }}, - { &hf_nbss_length, - { "Length", "nbss.length", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Length of trailer (payload) following this field in bytes", HFILL }}, - { &hf_nbss_cifs_length, - { "Length", "nbss.length", - FT_UINT24, BASE_DEC, NULL, 0x0, - "Length trailer (payload) following this field in bytes", HFILL }} - }; - static gint *ett[] = { - &ett_nbns, - &ett_nbns_qd, - &ett_nbns_flags, - &ett_nbns_nb_flags, - &ett_nbns_name_flags, - &ett_nbns_rr, - &ett_nbns_qry, - &ett_nbns_ans, - &ett_nbdgm, - &ett_nbss, - &ett_nbss_flags, - }; - module_t *nbss_module; - - proto_nbns = proto_register_protocol("NetBIOS Name Service", "NBNS", "nbns"); - proto_register_field_array(proto_nbns, hf_nbns, array_length(hf_nbns)); - - proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service", - "NBDS", "nbdgm"); - proto_register_field_array(proto_nbdgm, hf_nbdgm, array_length(hf_nbdgm)); - - proto_nbss = proto_register_protocol("NetBIOS Session Service", - "NBSS", "nbss"); - proto_register_field_array(proto_nbss, hf_nbss, array_length(hf_nbss)); - - proto_register_subtree_array(ett, array_length(ett)); - - nbss_module = prefs_register_protocol(proto_nbss, NULL); - prefs_register_bool_preference(nbss_module, "desegment_nbss_commands", - "Reassemble NBSS packets spanning multiple TCP segments", - "Whether the NBSS dissector should reassemble packets spanning multiple TCP segments." - " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", - &nbss_desegment); + static hf_register_info hf_nbns[] = { + { &hf_nbns_flags, + { "Flags", "nbns.flags", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, 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, + NULL, HFILL }}, + { &hf_nbns_transaction_id, + { "Transaction ID", "nbns.id", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Identification of transaction", HFILL }}, + { &hf_nbns_count_questions, + { "Questions", "nbns.count.queries", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Number of queries in packet", HFILL }}, + { &hf_nbns_count_answers, + { "Answer RRs", "nbns.count.answers", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Number of answers in packet", HFILL }}, + { &hf_nbns_count_auth_rr, + { "Authority RRs", "nbns.count.auth_rr", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Number of authoritative records in packet", HFILL }}, + { &hf_nbns_count_add_rr, + { "Additional RRs", "nbns.count.add_rr", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Number of additional records in packet", HFILL }} + }; + + static hf_register_info hf_nbdgm[] = { + { &hf_nbdgm_type, + { "Message Type", "nbdgm.type", + FT_UINT8, BASE_DEC, VALS(nbds_msgtype_vals), 0x0, + "NBDGM message type", HFILL }}, + { &hf_nbdgm_fragment, + { "More fragments follow", "nbdgm.next", + FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, + "TRUE if more fragments follow", HFILL }}, + { &hf_nbdgm_first, + { "This is first fragment", "nbdgm.first", + FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, + "TRUE if first fragment", HFILL }}, + { &hf_nbdgm_node_type, + { "Node Type", "nbdgm.node_type", + FT_UINT8, BASE_DEC, VALS(node_type_vals), 0x0, + NULL, HFILL }}, + { &hf_nbdgm_datagram_id, + { "Datagram ID", "nbdgm.dgram_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Datagram identifier", HFILL }}, + { &hf_nbdgm_src_ip, + { "Source IP", "nbdgm.src.ip", + FT_IPv4, BASE_NONE, NULL, 0x0, + "Source IPv4 address", HFILL }}, + { &hf_nbdgm_src_port, + { "Source Port", "nbdgm.src.port", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }} + }; + + static hf_register_info hf_nbss[] = { + { &hf_nbss_type, + { "Message Type", "nbss.type", + FT_UINT8, BASE_HEX, VALS(message_types), 0x0, + "NBSS message type", HFILL }}, + { &hf_nbss_flags, + { "Flags", "nbss.flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + "NBSS message flags", HFILL }}, + { &hf_nbss_length, + { "Length", "nbss.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of trailer (payload) following this field in bytes", HFILL }}, + { &hf_nbss_cifs_length, + { "Length", "nbss.length", + FT_UINT24, BASE_DEC, NULL, 0x0, + "Length trailer (payload) following this field in bytes", HFILL }} + }; + static gint *ett[] = { + &ett_nbns, + &ett_nbns_qd, + &ett_nbns_flags, + &ett_nbns_nb_flags, + &ett_nbns_name_flags, + &ett_nbns_rr, + &ett_nbns_qry, + &ett_nbns_ans, + &ett_nbdgm, + &ett_nbss, + &ett_nbss_flags, + }; + module_t *nbss_module; + + proto_nbns = proto_register_protocol("NetBIOS Name Service", "NBNS", "nbns"); + proto_register_field_array(proto_nbns, hf_nbns, array_length(hf_nbns)); + + proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service", + "NBDS", "nbdgm"); + proto_register_field_array(proto_nbdgm, hf_nbdgm, array_length(hf_nbdgm)); + + proto_nbss = proto_register_protocol("NetBIOS Session Service", + "NBSS", "nbss"); + proto_register_field_array(proto_nbss, hf_nbss, array_length(hf_nbss)); + + proto_register_subtree_array(ett, array_length(ett)); + + nbss_module = prefs_register_protocol(proto_nbss, NULL); + prefs_register_bool_preference(nbss_module, "desegment_nbss_commands", + "Reassemble NBSS packets spanning multiple TCP segments", + "Whether the NBSS dissector should reassemble packets spanning multiple TCP segments." + " To use this option, you must also enable" + " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", + &nbss_desegment); } void proto_reg_handoff_nbt(void) { - dissector_handle_t nbns_handle, nbdgm_handle, nbss_handle; - - nbns_handle = create_dissector_handle(dissect_nbns, proto_nbns); - dissector_add_uint("udp.port", UDP_PORT_NBNS, nbns_handle); - nbdgm_handle = create_dissector_handle(dissect_nbdgm, proto_nbdgm); - dissector_add_uint("udp.port", UDP_PORT_NBDGM, nbdgm_handle); - nbss_handle = create_dissector_handle(dissect_nbss, proto_nbss); - dissector_add_uint("tcp.port", TCP_PORT_NBSS, nbss_handle); - dissector_add_uint("tcp.port", TCP_PORT_CIFS, nbss_handle); + dissector_handle_t nbns_handle, nbdgm_handle, nbss_handle; + + nbns_handle = create_dissector_handle(dissect_nbns, proto_nbns); + dissector_add_uint("udp.port", UDP_PORT_NBNS, nbns_handle); + + nbdgm_handle = create_dissector_handle(dissect_nbdgm, proto_nbdgm); + dissector_add_uint("udp.port", UDP_PORT_NBDGM, nbdgm_handle); + + nbss_handle = create_dissector_handle(dissect_nbss, proto_nbss); + dissector_add_uint("tcp.port", TCP_PORT_NBSS, nbss_handle); + dissector_add_uint("tcp.port", TCP_PORT_CIFS, nbss_handle); } |