DTP Dissector Enhancements

1) Corrections to the naming and terminology of DTP, its TLVs, types and values

2) Improvements to the dissection of Trunk Status and Trunk Type TLVs whose values and meaning have not been properly decoded so far

3) Improvements to the dissection of the Domain TLV (now using proto_tree_add_item() to display its value; this also allows for filtering operations)

4) Minor cleanups to the code (mainly renaming the macro names to make them more consistent)


From Peter Paluch, Bug 9156 (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9156)

svn path=/trunk/; revision=52189
This commit is contained in:
Michael Mann 2013-09-23 15:54:29 +00:00
parent 2a1175c963
commit d09b1dbe8f
1 changed files with 219 additions and 84 deletions

View File

@ -1,5 +1,5 @@
/* packet-dtp.c /* packet-dtp.c
* Routines for the disassembly for Cisco Dynamic Trunking Protocol * Routines for the disassembly for Cisco Dynamic Trunk Protocol
* *
* $Id$ * $Id$
* *
@ -12,6 +12,11 @@
* Additional information comes from Yersinia (http://www.yersinia.net/) * Additional information comes from Yersinia (http://www.yersinia.net/)
* by Alfredo Andres and David Barroso * by Alfredo Andres and David Barroso
* *
* Improved dissection for Trunk Status and Trunk Type TLVs
* based on DTP description in U.S. Patent #6,445,715 and
* consultations with Aninda Chatterjee @ Cisco
* by Peter Paluch <Peter.Paluch@fri.uniza.sk>
*
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
@ -33,6 +38,7 @@
#include <glib.h> #include <glib.h>
#include <epan/packet.h> #include <epan/packet.h>
#include <epan/expert.h>
/* /*
* It's incomplete, and it appears to be inaccurate in a number of places, * It's incomplete, and it appears to be inaccurate in a number of places,
@ -42,48 +48,125 @@ void proto_register_dtp(void);
static int proto_dtp = -1; static int proto_dtp = -1;
static int hf_dtp_version = -1; static int hf_dtp_version = -1;
static int hf_dtp_domain = -1;
static int hf_dtp_tlvtype = -1; static int hf_dtp_tlvtype = -1;
static int hf_dtp_tlvlength = -1; static int hf_dtp_tlvlength = -1;
static int hf_dtp_some_mac = -1; static int hf_dtp_senderid = -1;
static int hf_dtp_tot = -1;
static int hf_dtp_tat = -1;
static int hf_dtp_tos = -1;
static int hf_dtp_tas = -1;
static gint ett_dtp = -1; static gint ett_dtp = -1;
static gint ett_dtp_tlv = -1; static gint ett_dtp_tlv = -1;
static gint ett_dtp_status = -1;
static gint ett_dtp_type = -1;
static void dissect_dtp_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree, proto_item *ti, guint8 type); static expert_field ei_dtp_tlv_length_invalid = EI_INIT;
static expert_field ei_dtp_truncated = EI_INIT;
static void
dissect_dtp_tlv(packet_info *pinfo, tvbuff_t *tvb, int offset, int length,
proto_tree *tree, proto_item *ti, proto_item *tlv_length_item, guint8 type);
#define TYPE_DOMAIN 0x01 #define DTP_TLV_DOMAIN 0x01 /* VTP Domain Name */
#define TYPE_STATUS 0x02 #define DTP_TLV_TRSTATUS 0x02 /* Trunk Status */
#define TYPE_DTPTYPE 0x03 #define DTP_TLV_TRTYPE 0x03 /* Trunk Type */
#define TYPE_NEIGHBOR 0x04 #define DTP_TLV_SENDERID 0x04 /* Sender ID (MAC) */
#define DTP_TOS_SHIFT 7
#define DTP_TOT_SHIFT 5
#define DTP_TOS_MASK 0x80
#define DTP_TAS_MASK 0x07
#define DTP_TOT_MASK 0xE0
#define DTP_TAT_MASK 0x07
#define DTP_TOSVALUE(status) (((status) & DTP_TOS_MASK) >> DTP_TOS_SHIFT)
#define DTP_TASVALUE(status) ((status) & DTP_TAS_MASK)
#define DTP_TOTVALUE(type) (((type) & DTP_TOT_MASK) >> DTP_TOT_SHIFT)
#define DTP_TATVALUE(type) ((type) & DTP_TAT_MASK)
/* Trunk Operating Status */
#define DTP_TOS_ACCESS 0x0
#define DTP_TOS_TRUNK 0x1
/* Trunk Administrative Status */
#define DTP_TAS_ON 0x1
#define DTP_TAS_OFF 0x2
#define DTP_TAS_DESIRABLE 0x3
#define DTP_TAS_AUTO 0x4
/* Trunk Operating Type */
#define DTP_TOT_NATIVE 0x1
#define DTP_TOT_ISL 0x2
#define DTP_TOT_DOT1Q 0x5
/* Trunk Administrative Type */
#define DTP_TAT_NEGOTIATED 0x0
#define DTP_TAT_NATIVE 0x1
#define DTP_TAT_ISL 0x2
#define DTP_TAT_DOT1Q 0x5
static const value_string dtp_tlv_type_vals[] = { static const value_string dtp_tlv_type_vals[] = {
{ TYPE_DOMAIN, "Domain" }, { DTP_TLV_DOMAIN, "Domain" },
{ TYPE_STATUS, "Status" }, { DTP_TLV_TRSTATUS, "Trunk Status" },
{ TYPE_DTPTYPE, "Type" }, { DTP_TLV_TRTYPE, "Trunk Type" },
{ TYPE_NEIGHBOR, "Neighbor" }, { DTP_TLV_SENDERID, "Sender ID" },
{ 0, NULL } { 0, NULL }
}; };
static const value_string dtp_tos_vals[] = {
{ DTP_TOS_ACCESS, "Access" },
{ DTP_TOS_TRUNK, "Trunk"},
{ 0, NULL }
};
static const value_string dtp_tas_vals[] = {
{ DTP_TAS_ON, "On" },
{ DTP_TAS_OFF, "Off" },
{ DTP_TAS_DESIRABLE, "Desirable" },
{ DTP_TAS_AUTO, "Auto" },
{ 0, NULL }
};
static const value_string dtp_tot_vals[] = {
{ DTP_TOT_NATIVE, "Native" },
{ DTP_TOT_ISL, "ISL" },
{ DTP_TOT_DOT1Q, "802.1Q" },
{ 0, NULL }
};
static const value_string dtp_tat_vals[] = {
{ DTP_TAT_NEGOTIATED, "Negotiated" },
{ DTP_TAT_NATIVE, "Native" },
{ DTP_TAT_ISL, "ISL" },
{ DTP_TAT_DOT1Q, "802.1Q" },
{ 0, NULL }
};
static void static void
dissect_dtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) dissect_dtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{ {
proto_item *ti; proto_item *ti;
proto_tree *dtp_tree = NULL; proto_tree *dtp_tree;
proto_tree *tlv_tree=NULL; proto_tree *tlv_tree;
int offset = 0; int offset = 0;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "DTP"); col_set_str(pinfo->cinfo, COL_PROTOCOL, "DTP");
col_set_str(pinfo->cinfo, COL_INFO, "Dynamic Trunking Protocol"); col_set_str(pinfo->cinfo, COL_INFO, "Dynamic Trunk Protocol");
if (tree) {
ti = proto_tree_add_item(tree, proto_dtp, tvb, offset, -1, ENC_NA); ti = proto_tree_add_item(tree, proto_dtp, tvb, offset, -1, ENC_NA);
dtp_tree = proto_item_add_subtree(ti, ett_dtp); dtp_tree = proto_item_add_subtree(ti, ett_dtp);
}
/* We assume version */ /* We assume version */
proto_tree_add_item(dtp_tree, hf_dtp_version, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(dtp_tree, hf_dtp_version, tvb, offset, 1, ENC_BIG_ENDIAN);
@ -91,15 +174,17 @@ dissect_dtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
while (tvb_reported_length_remaining(tvb, offset) > 0) { while (tvb_reported_length_remaining(tvb, offset) > 0) {
int type, length, valuelength; int type, length, valuelength;
proto_item * tlv_length_item;
if (tvb_length_remaining(tvb, offset) < 4) {
expert_add_info(pinfo, dtp_tree, &ei_dtp_truncated);
break;
}
type = tvb_get_ntohs(tvb, offset); type = tvb_get_ntohs(tvb, offset);
length = tvb_get_ntohs(tvb, offset + 2); length = tvb_get_ntohs(tvb, offset + 2);
valuelength = (length-4); valuelength = (length-4);
/* make sure still in valid tlv */
if ((valuelength < 1) || ( length > tvb_length_remaining(tvb, offset) ))
break;
ti = proto_tree_add_text(dtp_tree, tvb, offset, length, "%s", ti = proto_tree_add_text(dtp_tree, tvb, offset, length, "%s",
val_to_str(type, dtp_tlv_type_vals, "Unknown TLV type: 0x%02x")); val_to_str(type, dtp_tlv_type_vals, "Unknown TLV type: 0x%02x"));
@ -107,84 +192,96 @@ dissect_dtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_uint(tlv_tree, hf_dtp_tlvtype, tvb, offset, 2, type); proto_tree_add_uint(tlv_tree, hf_dtp_tlvtype, tvb, offset, 2, type);
offset+=2; offset+=2;
proto_tree_add_uint(tlv_tree, hf_dtp_tlvlength, tvb, offset, 2, length); tlv_length_item = proto_tree_add_uint(tlv_tree, hf_dtp_tlvlength, tvb, offset, 2, length);
offset+=2; offset+=2;
if (valuelength > tvb_length_remaining(tvb, offset)) {
if (valuelength > 0) { expert_add_info(pinfo, dtp_tree, &ei_dtp_truncated);
dissect_dtp_tlv(tvb, offset, valuelength, tlv_tree, ti, (guint8) type); break;
} }
if (valuelength > 0) { /* No known TLVs have value length of 0 */
dissect_dtp_tlv(pinfo, tvb, offset, valuelength, tlv_tree, ti, tlv_length_item, (guint8) type);
}
else
expert_add_info(pinfo, tlv_length_item, &ei_dtp_tlv_length_invalid);
offset += valuelength; offset += valuelength;
} }
} }
static void static void
dissect_dtp_tlv(tvbuff_t *tvb, int offset, int length, dissect_dtp_tlv(packet_info *pinfo, tvbuff_t *tvb, int offset, int length,
proto_tree *tree, proto_item *ti, guint8 type) proto_tree *tree, proto_item *ti, proto_item *tlv_length_item, guint8 type)
{ {
switch (type) { switch (type) {
case TYPE_DOMAIN: case DTP_TLV_DOMAIN:
if (length > 0) { if (length <= 33) { /* VTP domain name is at most 32 bytes long and is null-terminated */
proto_item_set_text(ti, "Domain: %s", tvb_format_text(tvb, offset, length - 1)); proto_item_append_text(ti, ": %s", tvb_format_text(tvb, offset, length - 1));
proto_tree_add_text(tree, tvb, offset, length, "Domain: %s", tvb_format_text(tvb, offset, length - 1)); proto_tree_add_item(tree, hf_dtp_domain, tvb, offset, length, ENC_NA);
} else {
proto_item_set_text(ti, "Domain: Bad length %u", length);
proto_tree_add_text(tree, tvb, offset, length, "Domain: Bad length %u", length);
} }
else
expert_add_info(pinfo, tlv_length_item, &ei_dtp_tlv_length_invalid);
break; break;
case TYPE_STATUS: case DTP_TLV_TRSTATUS:
if (length > 0) { if (length == 1) { /* Value field length must be 1 byte */
proto_item_set_text(ti, proto_item * value_item = NULL;
"Status: 0x%02x", proto_tree * field_tree = NULL;
tvb_get_guint8(tvb, offset)); guint8 trunk_status = tvb_get_guint8(tvb, offset);
proto_tree_add_text(tree, tvb, offset, 1,
"Status: 0x%02x", proto_item_append_text(ti,
tvb_get_guint8(tvb, offset)); " (Operating/Administrative): %s/%s (0x%02x)",
} else { val_to_str_const(DTP_TOSVALUE(trunk_status), dtp_tos_vals, "Unknown operating status"),
proto_item_set_text(ti, val_to_str_const(DTP_TASVALUE(trunk_status), dtp_tas_vals, "Unknown administrative status"),
"Status: Bad length %u", trunk_status);
length); value_item = proto_tree_add_text(tree, tvb, offset, length, "Value: %s/%s (0x%02x)",
proto_tree_add_text(tree, tvb, offset, length, val_to_str_const(DTP_TOSVALUE(trunk_status), dtp_tos_vals, "Unknown operating status"),
"Status: Bad length %u", val_to_str_const(DTP_TASVALUE(trunk_status), dtp_tas_vals, "Unknown administrative status"),
length); trunk_status);
field_tree = proto_item_add_subtree(value_item, ett_dtp_status);
proto_tree_add_item(field_tree, hf_dtp_tos, tvb, offset, length, ENC_NA);
proto_tree_add_item(field_tree, hf_dtp_tas, tvb, offset, length, ENC_NA);
} }
else
expert_add_info(pinfo, tlv_length_item, &ei_dtp_tlv_length_invalid);
break; break;
case TYPE_DTPTYPE: case DTP_TLV_TRTYPE:
if (length > 0) { if (length == 1) { /* Value field length must be 1 byte */
proto_item_set_text(ti, proto_item * value_item = NULL;
"Dtptype: 0x%02x", proto_tree * field_tree = NULL;
tvb_get_guint8(tvb, offset)); guint8 trunk_type = tvb_get_guint8(tvb, offset);
proto_tree_add_text(tree, tvb, offset, 1, proto_item_append_text(ti,
"Dtptype: 0x%02x", " (Operating/Administrative): %s/%s (0x%02x)",
tvb_get_guint8(tvb, offset)); val_to_str_const(DTP_TOTVALUE(trunk_type), dtp_tot_vals, "Unknown operating type"),
} else { val_to_str_const(DTP_TATVALUE(trunk_type), dtp_tat_vals, "Unknown administrative type"),
proto_item_set_text(ti, trunk_type);
"Dtptype: Bad length %u", value_item = proto_tree_add_text(tree, tvb, offset, length, "Value: %s/%s (0x%02x)",
length); val_to_str_const(DTP_TOTVALUE(trunk_type), dtp_tot_vals, "Unknown operating type"),
proto_tree_add_text(tree, tvb, offset, length, val_to_str_const(DTP_TATVALUE(trunk_type), dtp_tat_vals, "Unknown administrative type"),
"Dtptype: Bad length %u", trunk_type);
length); field_tree = proto_item_add_subtree(value_item, ett_dtp_type);
proto_tree_add_item(field_tree, hf_dtp_tot, tvb, offset, length, ENC_NA);
proto_tree_add_item(field_tree, hf_dtp_tat, tvb, offset, length, ENC_NA);
} }
else
expert_add_info(pinfo, tlv_length_item, &ei_dtp_tlv_length_invalid);
break; break;
case DTP_TLV_SENDERID:
case TYPE_NEIGHBOR: if (length == 6) { /* Value length must be 6 bytes for a MAC address */
if (length == 6) { proto_item_append_text(ti, ": %s",
proto_item_set_text(ti, "Neighbor: %s",
tvb_ether_to_str(tvb, offset)); /* XXX - resolve? */ tvb_ether_to_str(tvb, offset)); /* XXX - resolve? */
proto_tree_add_item(tree, hf_dtp_some_mac, tvb, offset, length, ENC_NA); proto_tree_add_item(tree, hf_dtp_senderid, tvb, offset, length, ENC_NA);
} else {
proto_item_set_text(ti,
"Neighbor: Bad length %u",
length);
proto_tree_add_text(tree, tvb, offset, length,
"Neighbor: Bad length %u",
length);
} }
else
expert_add_info(pinfo, tlv_length_item, &ei_dtp_tlv_length_invalid);
break; break;
default: default:
@ -198,7 +295,11 @@ proto_register_dtp(void)
{ {
static hf_register_info hf[] = { static hf_register_info hf[] = {
{ &hf_dtp_version, { &hf_dtp_version,
{ "Version", "dtp.version", FT_UINT8, BASE_HEX, { "Version", "dtp.version", FT_UINT8, BASE_DEC,
NULL, 0x0, NULL, HFILL }},
{ &hf_dtp_domain,
{ "Domain", "dtp.domain", FT_STRING, BASE_NONE,
NULL, 0x0, NULL, HFILL }}, NULL, 0x0, NULL, HFILL }},
{ &hf_dtp_tlvtype, { &hf_dtp_tlvtype,
@ -209,8 +310,24 @@ proto_register_dtp(void)
{ "Length", "dtp.tlv_len", FT_UINT16, BASE_DEC, { "Length", "dtp.tlv_len", FT_UINT16, BASE_DEC,
NULL, 0x0, NULL, HFILL }}, NULL, 0x0, NULL, HFILL }},
{ &hf_dtp_some_mac, { &hf_dtp_tos,
{ "Neighbor", "dtp.neighbor", FT_ETHER, BASE_NONE, { "Trunk Operating Status", "dtp.tos", FT_UINT8, BASE_HEX,
VALS(dtp_tos_vals), DTP_TOS_MASK, NULL, HFILL }},
{ &hf_dtp_tas,
{ "Trunk Administrative Status", "dtp.tas", FT_UINT8, BASE_HEX,
VALS(dtp_tas_vals), DTP_TAS_MASK, NULL, HFILL }},
{ &hf_dtp_tot,
{ "Trunk Operating Type", "dtp.tot", FT_UINT8, BASE_HEX,
VALS(dtp_tot_vals), DTP_TOT_MASK, NULL, HFILL }},
{ &hf_dtp_tat,
{ "Trunk Administrative Type", "dtp.tat", FT_UINT8, BASE_HEX,
VALS(dtp_tat_vals), DTP_TAT_MASK, NULL, HFILL }},
{ &hf_dtp_senderid,
{ "Sender ID", "dtp.senderid", FT_ETHER, BASE_NONE,
NULL, 0x0, "MAC Address of neighbor", HFILL }}, NULL, 0x0, "MAC Address of neighbor", HFILL }},
}; };
@ -218,11 +335,29 @@ proto_register_dtp(void)
static gint *ett[] = { static gint *ett[] = {
&ett_dtp, &ett_dtp,
&ett_dtp_tlv, &ett_dtp_tlv,
&ett_dtp_status,
&ett_dtp_type,
}; };
proto_dtp = proto_register_protocol("Dynamic Trunking Protocol", "DTP", "dtp"); static ei_register_info ei[] = {
{ &ei_dtp_tlv_length_invalid,
{ "dtp.tlv_len.invalid", PI_MALFORMED, PI_ERROR,
"Indicated length does not correspond to this record type", EXPFILL }},
{ &ei_dtp_truncated,
{ "dtp.truncated", PI_MALFORMED, PI_ERROR,
"DTP message is truncated prematurely", EXPFILL }}
};
expert_module_t *expert_dtp;
proto_dtp = proto_register_protocol("Dynamic Trunk Protocol", "DTP", "dtp");
proto_register_field_array(proto_dtp, hf, array_length(hf)); proto_register_field_array(proto_dtp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett)); proto_register_subtree_array(ett, array_length(ett));
expert_dtp = expert_register_protocol(proto_dtp);
expert_register_field_array(expert_dtp, ei, array_length(ei));
} }
void void