aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-bpdu.c
diff options
context:
space:
mode:
authorEvan Huus <eapache@gmail.com>2013-09-30 11:57:14 +0000
committerEvan Huus <eapache@gmail.com>2013-09-30 11:57:14 +0000
commit67da8b61fd5e8cd64bcf2461411cb1e134be2b97 (patch)
tree1768845b30a1359bb362d512df479e7c5c3813ba /epan/dissectors/packet-bpdu.c
parent2468b33ccef7189a2ee845f3c926ec12cb01e02f (diff)
From Peter Paluch via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9160
Extend the BPDU dissector in packet-bpdu.c so that it recognizes and displays the PVID TLV in Cisco's PVST+/RPVST+ BPDUs. svn path=/trunk/; revision=52294
Diffstat (limited to 'epan/dissectors/packet-bpdu.c')
-rw-r--r--epan/dissectors/packet-bpdu.c151
1 files changed, 146 insertions, 5 deletions
diff --git a/epan/dissectors/packet-bpdu.c b/epan/dissectors/packet-bpdu.c
index e345b51e35..f9b9316e7f 100644
--- a/epan/dissectors/packet-bpdu.c
+++ b/epan/dissectors/packet-bpdu.c
@@ -34,6 +34,7 @@
#include <epan/etypes.h>
#include <epan/addr_resolv.h>
#include <epan/prefs.h>
+#include <epan/expert.h>
/* Offsets of fields within a BPDU */
@@ -60,6 +61,8 @@
#define BPDU_CIST_REMAINING_HOPS 101
#define BPDU_MSTI 102
+#define BPDU_PVST_TLV 36
+
#define MSTI_FLAGS 0
#define MSTI_REGIONAL_ROOT 1
#define MSTI_INTERNAL_ROOT_PATH_COST 9
@@ -156,6 +159,11 @@ static int hf_bpdu_flags_agree_valid = -1;
static int hf_bpdu_flags_restricted_role = -1;
static int hf_bpdu_spt_agreement_digest = -1;
+static int hf_bpdu_pvst_tlvtype = -1;
+static int hf_bpdu_pvst_tlvlength = -1;
+static int hf_bpdu_pvst_tlvvalue = -1;
+static int hf_bpdu_pvst_tlv_origvlan = -1;
+
static gint ett_bpdu = -1;
static gint ett_bpdu_flags = -1;
static gint ett_root_id = -1;
@@ -166,6 +174,12 @@ static gint ett_cist_bridge_id = -1;
static gint ett_spt = -1;
static gint ett_aux_mcid = -1;
static gint ett_agreement = -1;
+static gint ett_bpdu_pvst_tlv = -1;
+
+static expert_field ei_pvst_tlv_length_invalid = EI_INIT;
+static expert_field ei_pvst_tlv_origvlan_missing = EI_INIT;
+static expert_field ei_pvst_tlv_truncated = EI_INIT;
+static expert_field ei_pvst_tlv_unknown = EI_INIT;
static gboolean bpdu_use_system_id_extensions = TRUE;
@@ -178,6 +192,14 @@ static const value_string protocol_id_vals[] = {
{ 0, NULL }
};
+#define BPDU_PVST_TLV_ORIGVLAN 0 /* Originating VLAN TLV in Cisco (R)PVST+ BPDUs */
+
+static const value_string bpdu_pvst_tlv_vals[] = {
+ { BPDU_PVST_TLV_ORIGVLAN, "Originating VLAN" },
+ { 0, NULL }
+};
+
+
#define BPDU_TYPE_CONF 0x00 /* STP Configuration BPDU */
#define BPDU_TYPE_RST 0x02 /* RST BPDU (or MST) */
#define BPDU_TYPE_TOPOLOGY_CHANGE 0x80 /* STP TCN (Topology change notify) BPDU */
@@ -223,7 +245,77 @@ static const char cont_sep[] = ", ";
}
static void
-dissect_bpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_bpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_bpdu_pvst);
+
+static void
+dissect_bpdu_cisco(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ dissect_bpdu(tvb, pinfo, tree, TRUE);
+}
+
+static void
+dissect_bpdu_generic(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ dissect_bpdu(tvb, pinfo, tree, FALSE);
+}
+
+static void
+dissect_bpdu_pvst_tlv(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb) {
+ gboolean pvst_tlv_origvlan_present = FALSE;
+ guint16 tlv_type, tlv_length;
+ int offset = BPDU_PVST_TLV;
+ proto_item * ti = NULL;
+ proto_item * tlv_length_item = NULL;
+ proto_tree * tlv_tree = NULL;
+
+ if (tvb_reported_length_remaining(tvb, offset) < 4) /* TLV Type and Length fields occupy 4 bytes in total */
+ expert_add_info(pinfo, tree, &ei_pvst_tlv_truncated);
+
+ while (tvb_reported_length_remaining(tvb, offset) >= 4) { /* TLV Type and Length fields occupy 4 bytes in total */
+ tlv_type = tvb_get_ntohs(tvb, offset);
+ tlv_length = tvb_get_ntohs(tvb, offset + 2);
+
+ ti = proto_tree_add_text(tree, tvb, offset, 4 + tlv_length, "%s",
+ val_to_str(tlv_type, bpdu_pvst_tlv_vals, "Unknown TLV type: 0x%04x"));
+
+ tlv_tree = proto_item_add_subtree(ti, ett_bpdu_pvst_tlv);
+ proto_tree_add_item(tlv_tree, hf_bpdu_pvst_tlvtype, tvb, offset, 2, ENC_BIG_ENDIAN);
+ tlv_length_item = proto_tree_add_item(tlv_tree, hf_bpdu_pvst_tlvlength,
+ tvb, offset + 2, 2, ENC_BIG_ENDIAN);
+
+ if (tvb_reported_length_remaining(tvb, offset + 4) < tlv_length) {
+ expert_add_info(pinfo, tlv_length_item, &ei_pvst_tlv_truncated);
+ break;
+ }
+
+ offset += 4;
+
+ switch (tlv_type) {
+ case BPDU_PVST_TLV_ORIGVLAN:
+ if (tlv_length == 2) { /* Originating VLAN ID must be 2 bytes long */
+ proto_item_append_text(ti, " (PVID): %u", tvb_get_ntohs(tvb, offset));
+ proto_tree_add_item(tlv_tree, hf_bpdu_pvst_tlv_origvlan, tvb, offset, tlv_length, ENC_BIG_ENDIAN);
+ pvst_tlv_origvlan_present = TRUE;
+ }
+ else
+ expert_add_info(pinfo, tlv_length_item, &ei_pvst_tlv_length_invalid);
+ break;
+
+ default:
+ proto_tree_add_item(tlv_tree, hf_bpdu_pvst_tlvvalue, tvb, offset, tlv_length, ENC_NA);
+ expert_add_info(pinfo, tlv_tree, &ei_pvst_tlv_unknown);
+ break;
+ }
+
+ offset += tlv_length;
+ }
+
+ if (pvst_tlv_origvlan_present == FALSE) /* If a (R)PVST+ BPDU lacks the Originating VLAN TLV, it is malformed */
+ expert_add_info(pinfo, tree, &ei_pvst_tlv_origvlan_missing);
+}
+
+static void
+dissect_bpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_bpdu_pvst)
{
guint16 protocol_identifier;
guint8 protocol_version_identifier;
@@ -589,6 +681,9 @@ dissect_bpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
BPDU_FORWARD_DELAY, 2, forward_delay);
if (bpdu_type == BPDU_TYPE_CONF) {
+ if (is_bpdu_pvst)
+ dissect_bpdu_pvst_tlv(pinfo, bpdu_tree, tvb);
+
/* Nothing more in this BPDU */
set_actual_length(tvb, CONF_BPDU_SIZE);
return;
@@ -1077,6 +1172,9 @@ dissect_bpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
}
}
+ } else { /* It is RSTP BPDU and may still be Rapid PVST+ */
+ if (is_bpdu_pvst)
+ dissect_bpdu_pvst_tlv(pinfo, bpdu_tree, tvb);
}
}
}
@@ -1182,6 +1280,22 @@ proto_register_bpdu(void)
{ "Version 1 Length", "stp.version_1_length",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
+ { &hf_bpdu_pvst_tlvtype,
+ { "Type", "stp.pvst.tlvtype",
+ FT_UINT16, BASE_HEX, VALS(bpdu_pvst_tlv_vals), 0x0,
+ NULL, HFILL }},
+ { &hf_bpdu_pvst_tlvlength,
+ { "Length", "stp.pvst.tlvlen",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+ { &hf_bpdu_pvst_tlv_origvlan,
+ { "Originating VLAN", "stp.pvst.origvlan",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+ { &hf_bpdu_pvst_tlvvalue,
+ { "Value", "stp.pvst.tlvval",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
{ &hf_bpdu_version_3_length,
{ "Version 3 Length", "mstp.version_3_length",
FT_UINT16, BASE_DEC, NULL, 0x0,
@@ -1301,15 +1415,40 @@ proto_register_bpdu(void)
&ett_cist_bridge_id,
&ett_spt,
&ett_aux_mcid,
- &ett_agreement
+ &ett_agreement,
+ &ett_bpdu_pvst_tlv
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_pvst_tlv_length_invalid,
+ { "stp.pvst.tlvlen.invalid", PI_MALFORMED, PI_ERROR,
+ "Indicated length is not valid for this record type", EXPFILL }},
+
+ { &ei_pvst_tlv_origvlan_missing,
+ { "stp.pvst.origvlan.missing", PI_MALFORMED, PI_ERROR,
+ "Originating (PVID) VLAN TLV is missing or corrupt", EXPFILL }},
+
+ { &ei_pvst_tlv_truncated,
+ { "stp.pvst.tlv.truncated", PI_MALFORMED, PI_ERROR,
+ "TLV record is truncated prematurely", EXPFILL }},
+
+ { &ei_pvst_tlv_unknown,
+ { "stp.pvst.tlv.unknown", PI_UNDECODED, PI_COMMENT,
+ "TLV type is unknown", EXPFILL }}
};
+
module_t *bpdu_module;
+ expert_module_t *expert_bpdu;
proto_bpdu = proto_register_protocol("Spanning Tree Protocol", "STP", "stp");
proto_register_field_array(proto_bpdu, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
- register_dissector("bpdu", dissect_bpdu, proto_bpdu);
+ register_dissector("bpdu", dissect_bpdu_generic, proto_bpdu);
+ register_dissector("bpdu_cisco", dissect_bpdu_cisco, proto_bpdu);
+
+ expert_bpdu = expert_register_protocol(proto_bpdu);
+ expert_register_field_array(expert_bpdu, ei, array_length(ei));
bpdu_module = prefs_register_protocol(proto_bpdu, NULL);
prefs_register_bool_preference(bpdu_module, "use_system_id_extension",
@@ -1337,7 +1476,9 @@ proto_reg_handoff_bpdu(void)
bpdu_handle = find_dissector("bpdu");
dissector_add_uint("llc.dsap", SAP_BPDU, bpdu_handle);
dissector_add_uint("chdlc.protocol", CHDLCTYPE_BPDU, bpdu_handle);
- dissector_add_uint("llc.cisco_pid", 0x010b, bpdu_handle);
- dissector_add_uint("llc.cisco_pid", 0x010c, bpdu_handle);
dissector_add_uint("ethertype", ETHERTYPE_STP, bpdu_handle);
+ dissector_add_uint("llc.cisco_pid", 0x010c, bpdu_handle); /* Cisco's VLAN-bridge STP is just plain STP */
+
+ bpdu_handle = find_dissector("bpdu_cisco");
+ dissector_add_uint("llc.cisco_pid", 0x010b, bpdu_handle); /* Handle Cisco's (R)PVST+ TLV extensions */
}