2 * ECP/VDP dissector for wireshark (according to IEEE 802.1Qbg draft 0)
3 * By Jens Osterkamp <jens at linux.vnet.ibm.com>
4 * Mijo Safradin <mijo at linux.vnet.ibm.com>
5 * Copyright 2011,2012 IBM Corp.
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <epan/packet.h>
33 #include <epan/addr_resolv.h>
35 #include "packet-ieee802a.h"
36 #include "packet-lldp.h"
40 #define VDP_TLV_TYPE 0x02
42 /* IEEE 802.1Qbg VDP filter info formats */
43 #define VDP_FIF_VID 0x01
44 #define VDP_FIF_MACVID 0x02
45 #define VDP_FIF_GROUPVID 0x03
46 #define VDP_FIF_GROUPVMACVID 0x04
48 static gint proto_ecp = -1;
49 static gint hf_ecp_pid = -1;
50 static gint hf_ecp_subtype = -1;
51 static gint hf_ecp_mode = -1;
52 static gint hf_ecp_sequence = -1;
53 static gint hf_ecp_vdp_oui = -1;
54 static gint hf_ecp_vdp_mode = -1;
55 static gint hf_ecp_vdp_response = -1;
56 static gint hf_ecp_vdp_mgrid = -1;
57 static gint hf_ecp_vdp_vsitypeid = -1;
58 static gint hf_ecp_vdp_vsitypeidversion = -1;
59 static gint hf_ecp_vdp_instanceid = -1;
60 static gint hf_ecp_vdp_format = -1;
61 static gint hf_ecp_vdp_mac = -1;
62 static gint hf_ecp_vdp_vlan = -1;
63 static gint ett_802_1qbg_capabilities_flags = -1;
65 static gint ett_ecp = -1;
67 static const value_string ecp_pid_vals[] = {
68 { 0x0000, "ECP draft 0" },
72 /* IEEE 802.1Qbg ECP subtypes */
73 static const value_string ecp_subtypes[] = {
74 { 0x00, "ECP default subtype" },
78 /* IEEE 802.1Qbg ECP modes */
79 static const value_string ecp_modes[] = {
85 /* IEEE 802.1Qbg VDP modes */
86 static const value_string ecp_vdp_modes[] = {
87 { 0x00, "Pre-Associate" },
88 { 0x01, "Pre-Associate with resource reservation" },
89 { 0x02, "Associate" },
90 { 0x03, "De-Associate" },
94 /* IEEE 802.1Qbg VDP responses */
95 static const value_string ecp_vdp_responses[] = {
97 { 0x01, "invalid format" },
98 { 0x02, "insufficient resources" },
99 { 0x03, "unused VTID" },
100 { 0x04, "VTID violation" },
101 { 0x05, "VTID version violation" },
102 { 0x06, "out of sync" },
106 /* IEEE 802.1Qbg VDP filter info formats */
107 static const value_string ecp_vdp_formats[] = {
108 { VDP_FIF_VID, "VID values" },
109 { VDP_FIF_MACVID, "MAC/VID pairs" },
110 { VDP_FIF_GROUPVID, "GROUPID/VID pairs" },
111 { VDP_FIF_GROUPVMACVID, "GROUPID/MAC/VID triples" },
115 /* Dissect Unknown TLV */
117 dissect_ecp_unknown_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
122 proto_tree *ecp_unknown_tlv_tree = NULL;
123 proto_item *ti = NULL;
125 /* Get tlv type and length */
126 tempShort = tvb_get_ntohs(tvb, offset);
129 tempLen = TLV_INFO_LEN(tempShort);
133 ti = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Unknown TLV");
134 ecp_unknown_tlv_tree = proto_item_add_subtree(ti, ett_ecp);
137 proto_tree_add_item(ecp_unknown_tlv_tree, hf_ecp_subtype, tvb, offset, 2, ENC_BIG_ENDIAN);
142 /* Dissect mac/vid pairs in VDP TLVs */
144 dissect_vdp_fi_macvid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
148 guint32 tempOffset = offset;
149 const guint8 *mac_addr = NULL;
151 proto_tree *ecp_vdp_tlv_fi_subtree = NULL;
152 proto_item *ti = NULL;
154 entries = tvb_get_ntohs(tvb, offset);
158 ti = proto_tree_add_text(tree, tvb, tempOffset, 2, "%i MAC/VID pair%s",
159 entries, plurality((entries > 1), "s", ""));
160 ecp_vdp_tlv_fi_subtree = proto_item_add_subtree(ti, ett_ecp);
165 for (i=0; i < entries; i++) {
166 mac_addr = tvb_get_ptr(tvb, tempOffset, 6);
169 proto_tree_add_ether(ecp_vdp_tlv_fi_subtree, hf_ecp_vdp_mac, tvb, tempOffset, 6, mac_addr);
174 proto_tree_add_item(ecp_vdp_tlv_fi_subtree, hf_ecp_vdp_vlan, tvb, tempOffset, 2, ENC_BIG_ENDIAN);
179 return tempOffset-offset;
182 /* Dissect VDP TLVs */
184 dissect_vdp_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
189 guint32 tempOffset = offset;
192 guint8 subType, format;
193 const char *subTypeStr;
195 proto_tree *ecp_vdp_tlv_subtree = NULL;
196 proto_item *ti = NULL;
199 tempShort = tvb_get_ntohs(tvb, offset);
200 len = TLV_INFO_LEN(tempShort);
204 oui = tvb_get_ntoh24(tvb, (tempOffset));
205 /* maintain previous OUI names. If not included, look in manuf database for OUI */
206 ouiStr = val_to_str_const(oui, tlv_oui_subtype_vals, "Unknown");
207 if (strcmp(ouiStr, "Unknown")==0) {
208 ouiStr = uint_get_manuf_name_if_known(oui);
209 if(ouiStr==NULL) ouiStr="Unknown";
214 subType = tvb_get_guint8(tvb, tempOffset);
217 case OUI_IEEE_802_1QBG:
218 subTypeStr = val_to_str(subType, ieee_802_1qbg_subtypes, "Unknown subtype 0x%x");
221 subTypeStr = "Unknown";
226 ti = proto_tree_add_text(tree, tvb, offset, (len + 2), "%s - %s",
228 ecp_vdp_tlv_subtree = proto_item_add_subtree(ti, ett_ecp);
233 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_mode, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
236 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_response, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
239 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_mgrid, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
242 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_vsitypeid, tvb, tempOffset, 3, ENC_BIG_ENDIAN);
245 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_vsitypeidversion, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
248 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_instanceid, tvb, tempOffset, 16, ENC_NA);
251 format = tvb_get_guint8(tvb, tempOffset);
252 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_format, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
257 /* place holder for future enablement */
258 /* For compatibility of different implementations proceed to next entry */
260 tempLen = dissect_vdp_fi_macvid(tvb, pinfo, ecp_vdp_tlv_subtree, tempOffset);
262 case VDP_FIF_GROUPVID:
263 /* place holder for future enablement */
265 case VDP_FIF_GROUPVMACVID:
266 /* place holder for future enablement */
272 tempOffset += tempLen;
274 return tempOffset-offset;
278 dissect_ecp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
280 proto_tree *ecp_tree = NULL;
281 proto_item *ti = NULL;
286 gboolean end = FALSE;
288 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ECP");
291 ti = proto_tree_add_item(tree, proto_ecp, tvb, 0, -1, ENC_NA);
292 ecp_tree = proto_item_add_subtree(ti, ett_ecp);
295 proto_tree_add_item(ecp_tree, hf_ecp_subtype, tvb, offset, 1, ENC_BIG_ENDIAN);
296 proto_tree_add_item(ecp_tree, hf_ecp_mode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
297 proto_tree_add_item(ecp_tree, hf_ecp_sequence, tvb, offset+2, 2, ENC_BIG_ENDIAN);
302 if (!tvb_bytes_exist(tvb, offset, 1))
305 tempShort = tvb_get_ntohs(tvb, offset);
306 tempType = TLV_TYPE(tempShort);
309 case ORGANIZATION_SPECIFIC_TLV_TYPE:
310 tempLen = dissect_vdp_tlv(tvb, pinfo, ecp_tree, offset);
312 case END_OF_LLDPDU_TLV_TYPE:
313 tempLen = dissect_lldp_end_of_lldpdu(tvb, pinfo, ecp_tree, offset);
316 tempLen = dissect_ecp_unknown_tlv(tvb, pinfo, ecp_tree, offset);
328 void proto_register_ecp_oui(void)
330 static hf_register_info hf_reg = {
332 { "PID", "ieee802a.ecp_pid", FT_UINT16, BASE_HEX,
333 VALS(ecp_pid_vals), 0x0, NULL, HFILL },
336 static hf_register_info hf[] = {
338 { "subtype", "ecp.subtype", FT_UINT8, BASE_HEX,
339 VALS(ecp_subtypes), 0x0, NULL, HFILL },
342 { "mode", "ecp.mode", FT_UINT8, BASE_HEX,
343 VALS(ecp_modes), 0x0, NULL, HFILL },
346 { "sequence number", "ecp.seq", FT_UINT16, BASE_HEX,
347 NULL, 0x0, NULL, HFILL },
350 { "Organization Unique Code", "ecp.vdp.oui", FT_UINT24, BASE_HEX,
351 VALS(tlv_oui_subtype_vals), 0x0, NULL, HFILL }
354 { "mode", "ecp.vdp.mode", FT_UINT8, BASE_HEX,
355 VALS(ecp_vdp_modes), 0x0, NULL, HFILL },
357 { &hf_ecp_vdp_response,
358 { "response", "ecp.vdp.response", FT_UINT8, BASE_HEX,
359 VALS(ecp_vdp_responses), 0x0, NULL, HFILL },
362 { "Manager ID", "ecp.vdp.mgrid", FT_UINT8, BASE_HEX,
363 NULL, 0x0, NULL, HFILL },
365 { &hf_ecp_vdp_vsitypeid,
366 { "VSI type ID", "ecp.vdp.vsitypeid", FT_UINT24, BASE_HEX,
367 NULL, 0x0, NULL, HFILL },
369 { &hf_ecp_vdp_vsitypeidversion,
370 { "VSI type ID version", "ecp.vdp.vsitypeidversion", FT_UINT8, BASE_HEX,
371 NULL, 0x0, NULL, HFILL },
373 { &hf_ecp_vdp_instanceid,
374 { "VSI Instance ID version", "ecp.vdp.instanceid", FT_BYTES, BASE_NONE,
375 NULL, 0x0, NULL, HFILL },
377 { &hf_ecp_vdp_format,
378 { "VSI filter info format", "ecp.vdp.format", FT_UINT8, BASE_HEX,
379 VALS(ecp_vdp_formats), 0x0, NULL, HFILL },
382 { "VSI Mac Address", "ecp.vdp.mac", FT_ETHER, BASE_NONE,
383 NULL, 0x0, NULL, HFILL }
386 { "VSI VLAN ID", "ecp.vdp.vlan", FT_UINT16, BASE_DEC,
387 NULL, 0x0, NULL, HFILL }
391 static gint *ett[] = {
393 &ett_802_1qbg_capabilities_flags,
396 ieee802a_add_oui(OUI_IEEE_802_1QBG, "ieee802a.ecp_pid", "ECP", &hf_reg);
398 proto_ecp = proto_register_protocol("ECP Protocol", "ECP", "ecp");
399 proto_register_field_array(proto_ecp, hf, array_length(hf));
400 proto_register_subtree_array(ett, array_length(ett));
402 register_dissector("ecp", dissect_ecp, proto_ecp);
405 void proto_reg_handoff_ecp(void)
407 static dissector_handle_t ecp_handle;
409 ecp_handle = find_dissector("ecp");
410 dissector_add_uint("ieee802a.ecp_pid", 0x0000, ecp_handle);