diff options
author | Evan Huus <eapache@gmail.com> | 2013-09-30 11:57:14 +0000 |
---|---|---|
committer | Evan Huus <eapache@gmail.com> | 2013-09-30 11:57:14 +0000 |
commit | 67da8b61fd5e8cd64bcf2461411cb1e134be2b97 (patch) | |
tree | 1768845b30a1359bb362d512df479e7c5c3813ba /epan/dissectors/packet-bpdu.c | |
parent | 2468b33ccef7189a2ee845f3c926ec12cb01e02f (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.c | 151 |
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 */ } |