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.
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <epan/packet.h>
17 #include <epan/addr_resolv.h>
19 #include <epan/addr_resolv.h>
21 #include <wsutil/str_util.h>
23 #include "packet-ieee802a.h"
25 void proto_register_ecp_oui(void);
26 void proto_reg_handoff_ecp(void);
28 #define ECP_SUBTYPE 0x00
30 #define END_OF_VDPDU_TLV_TYPE 0x00 /* Mandatory */
31 #define VDP_TLV_TYPE 0x02
32 #define ORG_SPECIFIC_TLV_TYPE 0x7F
34 /* IEEE 802.1Qbg VDP filter info formats */
35 #define VDP_FIF_VID 0x01
36 #define VDP_FIF_MACVID 0x02
37 #define VDP_FIF_GROUPVID 0x03
38 #define VDP_FIF_GROUPVMACVID 0x04
41 #define TLV_TYPE_MASK 0xFE00
42 #define TLV_TYPE(value) (((value) & TLV_TYPE_MASK) >> 9)
43 #define TLV_INFO_LEN_MASK 0x01FF
44 #define TLV_INFO_LEN(value) ((value) & TLV_INFO_LEN_MASK)
47 static int hf_ecp_pid
;
48 static int hf_ecp_tlv_type
;
49 static int hf_ecp_tlv_len
;
50 static int hf_ecp_subtype
;
51 static int hf_ecp_mode
;
52 static int hf_ecp_sequence
;
53 /* static int hf_ecp_vdp_oui; */
54 static int hf_ecp_vdp_mode
;
55 static int hf_ecp_vdp_response
;
56 static int hf_ecp_vdp_mgrid
;
57 static int hf_ecp_vdp_vsitypeid
;
58 static int hf_ecp_vdp_vsitypeidversion
;
59 static int hf_ecp_vdp_instanceid
;
60 static int hf_ecp_vdp_format
;
61 static int hf_ecp_vdp_mac
;
62 static int hf_ecp_vdp_vlan
;
65 static int ett_end_of_vdpdu
;
66 static int ett_802_1qbg_capabilities_flags
;
68 static dissector_handle_t ecp_handle
;
70 static const value_string ecp_pid_vals
[] = {
71 { 0x0000, "ECP draft 0" },
75 /* IEEE 802.1Qbg ECP subtypes */
76 static const value_string ecp_subtypes
[] = {
77 { 0x00, "ECP default subtype" },
81 /* IEEE 802.1Qbg ECP modes */
82 static const value_string ecp_modes
[] = {
88 /* IEEE 802.1Qbg VDP modes */
89 static const value_string ecp_vdp_modes
[] = {
90 { 0x00, "Pre-Associate" },
91 { 0x01, "Pre-Associate with resource reservation" },
92 { 0x02, "Associate" },
93 { 0x03, "De-Associate" },
97 /* IEEE 802.1Qbg VDP responses */
98 static const value_string ecp_vdp_responses
[] = {
100 { 0x01, "invalid format" },
101 { 0x02, "insufficient resources" },
102 { 0x03, "unused VTID" },
103 { 0x04, "VTID violation" },
104 { 0x05, "VTID version violation" },
105 { 0x06, "out of sync" },
109 /* IEEE 802.1Qbg VDP filter info formats */
110 static const value_string ecp_vdp_formats
[] = {
111 { VDP_FIF_VID
, "VID values" },
112 { VDP_FIF_MACVID
, "MAC/VID pairs" },
113 { VDP_FIF_GROUPVID
, "GROUPID/VID pairs" },
114 { VDP_FIF_GROUPVMACVID
, "GROUPID/MAC/VID triples" },
118 /* IEEE 802.1Qbg Subtypes */
119 static const value_string ieee_802_1qbg_subtypes
[] = {
126 /* Dissect Unknown TLV */
128 dissect_ecp_unknown_tlv(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, uint32_t offset
)
133 proto_tree
*ecp_unknown_tlv_tree
;
135 /* Get tlv type and length */
136 tempShort
= tvb_get_ntohs(tvb
, offset
);
139 tempLen
= TLV_INFO_LEN(tempShort
);
141 ecp_unknown_tlv_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, (tempLen
+ 2), ett_ecp
, NULL
, "Unknown TLV");
143 proto_tree_add_item(ecp_unknown_tlv_tree
, hf_ecp_subtype
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
148 /* Dissect mac/vid pairs in VDP TLVs */
150 dissect_vdp_fi_macvid(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, uint32_t offset
)
154 uint32_t tempOffset
= offset
;
156 proto_tree
*ecp_vdp_tlv_fi_subtree
;
158 entries
= tvb_get_ntohs(tvb
, offset
);
160 ecp_vdp_tlv_fi_subtree
= proto_tree_add_subtree_format(tree
, tvb
, tempOffset
, 2, ett_ecp
, NULL
,
161 "%i MAC/VID pair%s", entries
, plurality(entries
, "", "s"));
165 for (i
=0; i
< entries
; i
++) {
166 proto_tree_add_item(ecp_vdp_tlv_fi_subtree
, hf_ecp_vdp_mac
, tvb
, tempOffset
, 6, ENC_NA
);
170 proto_tree_add_item(ecp_vdp_tlv_fi_subtree
, hf_ecp_vdp_vlan
, tvb
, tempOffset
, 2, ENC_BIG_ENDIAN
);
175 return tempOffset
-offset
;
178 /* Dissect Organizationally Defined TLVs */
180 dissect_vdp_org_specific_tlv(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint32_t offset
)
185 uint32_t tempOffset
= offset
;
188 uint8_t subType
, format
;
189 const char *subTypeStr
;
191 proto_tree
*ecp_vdp_tlv_subtree
;
194 tempShort
= tvb_get_ntohs(tvb
, offset
);
195 len
= TLV_INFO_LEN(tempShort
);
199 oui
= tvb_get_ntoh24(tvb
, (tempOffset
));
200 /* Look in manuf database for OUI */
201 ouiStr
= uint_get_manuf_name_if_known(oui
);
202 if(ouiStr
==NULL
) ouiStr
="Unknown";
206 subType
= tvb_get_uint8(tvb
, tempOffset
);
210 case OUI_IEEE_802_1QBG
:
211 subTypeStr
= val_to_str(subType
, ieee_802_1qbg_subtypes
, "Unknown subtype 0x%x");
214 subTypeStr
= "Unknown";
218 ecp_vdp_tlv_subtree
= proto_tree_add_subtree_format(tree
, tvb
, offset
, (len
+ 2), ett_ecp
, NULL
,
219 "%s - %s", ouiStr
, subTypeStr
);
221 proto_tree_add_item(ecp_vdp_tlv_subtree
, hf_ecp_vdp_mode
, tvb
, tempOffset
, 1, ENC_BIG_ENDIAN
);
224 proto_tree_add_item(ecp_vdp_tlv_subtree
, hf_ecp_vdp_response
, tvb
, tempOffset
, 1, ENC_BIG_ENDIAN
);
227 proto_tree_add_item(ecp_vdp_tlv_subtree
, hf_ecp_vdp_mgrid
, tvb
, tempOffset
, 1, ENC_BIG_ENDIAN
);
230 proto_tree_add_item(ecp_vdp_tlv_subtree
, hf_ecp_vdp_vsitypeid
, tvb
, tempOffset
, 3, ENC_BIG_ENDIAN
);
233 proto_tree_add_item(ecp_vdp_tlv_subtree
, hf_ecp_vdp_vsitypeidversion
, tvb
, tempOffset
, 1, ENC_BIG_ENDIAN
);
236 proto_tree_add_item(ecp_vdp_tlv_subtree
, hf_ecp_vdp_instanceid
, tvb
, tempOffset
, 16, ENC_NA
);
239 format
= tvb_get_uint8(tvb
, tempOffset
);
240 proto_tree_add_item(ecp_vdp_tlv_subtree
, hf_ecp_vdp_format
, tvb
, tempOffset
, 1, ENC_BIG_ENDIAN
);
245 /* place holder for future enablement */
246 /* For compatibility of different implementations proceed to next entry */
248 tempLen
= dissect_vdp_fi_macvid(tvb
, pinfo
, ecp_vdp_tlv_subtree
, tempOffset
);
250 case VDP_FIF_GROUPVID
:
251 /* place holder for future enablement */
253 case VDP_FIF_GROUPVMACVID
:
254 /* place holder for future enablement */
260 tempOffset
+= tempLen
;
262 return tempOffset
-offset
;
265 /* Dissect End of VDP TLV (Mandatory) */
267 dissect_vdp_end_of_vdpdu_tlv(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, uint32_t offset
)
272 proto_tree
*end_of_vdpdu_tree
;
274 /* Get tlv type and length */
275 tempShort
= tvb_get_ntohs(tvb
, offset
);
278 tempLen
= TLV_INFO_LEN(tempShort
);
283 end_of_vdpdu_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, (tempLen
+ 2),
284 ett_end_of_vdpdu
, NULL
, "End of VDPDU");
286 proto_tree_add_item(end_of_vdpdu_tree
, hf_ecp_tlv_type
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
287 proto_tree_add_item(end_of_vdpdu_tree
, hf_ecp_tlv_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
290 return -1; /* Force the VDP dissector to terminate */
294 dissect_ecp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
296 proto_tree
*ecp_tree
;
304 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "ECP");
306 ti
= proto_tree_add_item(tree
, proto_ecp
, tvb
, 0, -1, ENC_NA
);
307 ecp_tree
= proto_item_add_subtree(ti
, ett_ecp
);
309 proto_tree_add_item(ecp_tree
, hf_ecp_subtype
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
310 proto_tree_add_item(ecp_tree
, hf_ecp_mode
, tvb
, offset
+1, 1, ENC_BIG_ENDIAN
);
311 proto_tree_add_item(ecp_tree
, hf_ecp_sequence
, tvb
, offset
+2, 2, ENC_BIG_ENDIAN
);
316 if (!tvb_bytes_exist(tvb
, offset
, 1))
319 tempShort
= tvb_get_ntohs(tvb
, offset
);
320 tempType
= TLV_TYPE(tempShort
);
323 case ORG_SPECIFIC_TLV_TYPE
:
324 tempLen
= dissect_vdp_org_specific_tlv(tvb
, pinfo
, ecp_tree
, offset
);
326 case END_OF_VDPDU_TLV_TYPE
:
327 tempLen
= dissect_vdp_end_of_vdpdu_tlv(tvb
, pinfo
, ecp_tree
, offset
);
330 tempLen
= dissect_ecp_unknown_tlv(tvb
, pinfo
, ecp_tree
, offset
);
339 return tvb_captured_length(tvb
);
342 void proto_register_ecp_oui(void)
344 static hf_register_info hf_reg
= {
346 { "PID", "ieee802a.ecp_pid", FT_UINT16
, BASE_HEX
,
347 VALS(ecp_pid_vals
), 0x0, NULL
, HFILL
},
350 static hf_register_info hf
[] = {
352 { "TLV Type", "ecp.tlv.type", FT_UINT16
, BASE_DEC
,
353 NULL
, TLV_TYPE_MASK
, NULL
, HFILL
}
356 { "TLV Length", "ecp.tlv.len", FT_UINT16
, BASE_DEC
,
357 NULL
, TLV_INFO_LEN_MASK
, NULL
, HFILL
}
361 { "subtype", "ecp.subtype", FT_UINT8
, BASE_HEX
,
362 VALS(ecp_subtypes
), 0x0, NULL
, HFILL
},
365 { "mode", "ecp.mode", FT_UINT8
, BASE_HEX
,
366 VALS(ecp_modes
), 0x0, NULL
, HFILL
},
369 { "sequence number", "ecp.seq", FT_UINT16
, BASE_HEX
,
370 NULL
, 0x0, NULL
, HFILL
},
374 { "Organization Unique Code", "ecp.vdp.oui", FT_UINT24
, BASE_OUI
,
375 NULL
, 0x0, NULL
, HFILL
}
379 { "mode", "ecp.vdp.mode", FT_UINT8
, BASE_HEX
,
380 VALS(ecp_vdp_modes
), 0x0, NULL
, HFILL
},
382 { &hf_ecp_vdp_response
,
383 { "response", "ecp.vdp.response", FT_UINT8
, BASE_HEX
,
384 VALS(ecp_vdp_responses
), 0x0, NULL
, HFILL
},
387 { "Manager ID", "ecp.vdp.mgrid", FT_UINT8
, BASE_HEX
,
388 NULL
, 0x0, NULL
, HFILL
},
390 { &hf_ecp_vdp_vsitypeid
,
391 { "VSI type ID", "ecp.vdp.vsitypeid", FT_UINT24
, BASE_HEX
,
392 NULL
, 0x0, NULL
, HFILL
},
394 { &hf_ecp_vdp_vsitypeidversion
,
395 { "VSI type ID version", "ecp.vdp.vsitypeidversion", FT_UINT8
, BASE_HEX
,
396 NULL
, 0x0, NULL
, HFILL
},
398 { &hf_ecp_vdp_instanceid
,
399 { "VSI Instance ID version", "ecp.vdp.instanceid", FT_BYTES
, BASE_NONE
,
400 NULL
, 0x0, NULL
, HFILL
},
402 { &hf_ecp_vdp_format
,
403 { "VSI filter info format", "ecp.vdp.format", FT_UINT8
, BASE_HEX
,
404 VALS(ecp_vdp_formats
), 0x0, NULL
, HFILL
},
407 { "VSI Mac Address", "ecp.vdp.mac", FT_ETHER
, BASE_NONE
,
408 NULL
, 0x0, NULL
, HFILL
}
411 { "VSI VLAN ID", "ecp.vdp.vlan", FT_UINT16
, BASE_DEC
,
412 NULL
, 0x0, NULL
, HFILL
}
416 static int *ett
[] = {
419 &ett_802_1qbg_capabilities_flags
,
422 proto_ecp
= proto_register_protocol("ECP Protocol", "ECP", "ecp");
423 proto_register_field_array(proto_ecp
, hf
, array_length(hf
));
424 proto_register_subtree_array(ett
, array_length(ett
));
426 ieee802a_add_oui(OUI_IEEE_802_1QBG
, "ieee802a.ecp_pid",
427 "IEEE802a ECP PID", &hf_reg
, proto_ecp
);
429 ecp_handle
= register_dissector("ecp", dissect_ecp
, proto_ecp
);
432 void proto_reg_handoff_ecp(void)
434 dissector_add_uint("ieee802a.ecp_pid", 0x0000, ecp_handle
);
438 * Editor modelines - https://www.wireshark.org/tools/modelines.html
443 * indent-tabs-mode: t
446 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
447 * :indentSize=8:tabSize=8:noTabs=false: