1 /* packet-ecp-oui.c
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.
6 *
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13
14 #include "config.h"
15
16 #include <epan/packet.h>
17 #include <epan/addr_resolv.h>
18 #include <epan/oui.h>
19 #include <epan/addr_resolv.h>
20
21 #include <wsutil/str_util.h>
22
23 #include "packet-ieee802a.h"
24
25 void proto_register_ecp_oui(void);
26 void proto_reg_handoff_ecp(void);
27
28 #define ECP_SUBTYPE 0x00
29
30 #define END_OF_VDPDU_TLV_TYPE 0x00 /* Mandatory */
31 #define VDP_TLV_TYPE 0x02
32 #define ORG_SPECIFIC_TLV_TYPE 0x7F
33
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
39
40 /* Masks */
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)
45
46 static gint proto_ecp = -1;
47 static gint hf_ecp_pid = -1;
48 static gint hf_ecp_tlv_type = -1;
49 static gint hf_ecp_tlv_len = -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
64 static gint ett_ecp = -1;
65 static gint ett_end_of_vdpdu = -1;
66 static gint ett_802_1qbg_capabilities_flags = -1;
67
68 static dissector_handle_t ecp_handle;
69
70 static const value_string ecp_pid_vals[] = {
71 { 0x0000, "ECP draft 0" },
72 { 0, NULL }
73 };
74
75 /* IEEE 802.1Qbg ECP subtypes */
76 static const value_string ecp_subtypes[] = {
77 { 0x00, "ECP default subtype" },
78 { 0, NULL }
79 };
80
81 /* IEEE 802.1Qbg ECP modes */
82 static const value_string ecp_modes[] = {
83 { 0x00, "REQUEST" },
84 { 0x01, "ACK" },
85 { 0, NULL }
86 };
87
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" },
94 { 0, NULL }
95 };
96
97 /* IEEE 802.1Qbg VDP responses */
98 static const value_string ecp_vdp_responses[] = {
99 { 0x00, "success" },
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" },
106 { 0, NULL }
107 };
108
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" },
115 { 0, NULL }
116 };
117
118 /* IEEE 802.1Qbg Subtypes */
119 static const value_string ieee_802_1qbg_subtypes[] = {
120 { 0x00, "EVB" },
121 { 0x01, "CDCP" },
122 { 0x02, "VDP" },
123 { 0, NULL }
124 };
125
126 /* Dissect Unknown TLV */
127 static gint32
dissect_ecp_unknown_tlv(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,guint32 offset)128 dissect_ecp_unknown_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
129 {
130 guint16 tempLen;
131 guint16 tempShort;
132
133 proto_tree *ecp_unknown_tlv_tree;
134
135 /* Get tlv type and length */
136 tempShort = tvb_get_ntohs(tvb, offset);
137
138 /* Get tlv length */
139 tempLen = TLV_INFO_LEN(tempShort);
140
141 ecp_unknown_tlv_tree = proto_tree_add_subtree(tree, tvb, offset, (tempLen + 2), ett_ecp, NULL, "Unknown TLV");
142
143 proto_tree_add_item(ecp_unknown_tlv_tree, hf_ecp_subtype, tvb, offset, 2, ENC_BIG_ENDIAN);
144
145 return -1;
146 }
147
148 /* Dissect mac/vid pairs in VDP TLVs */
149 static gint32
dissect_vdp_fi_macvid(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,guint32 offset)150 dissect_vdp_fi_macvid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
151 {
152 gint i;
153 guint16 entries;
154 guint32 tempOffset = offset;
155
156 proto_tree *ecp_vdp_tlv_fi_subtree;
157
158 entries = tvb_get_ntohs(tvb, offset);
159
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"));
162
163 tempOffset += 2;
164
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);
167
168 tempOffset += 6;
169
170 proto_tree_add_item(ecp_vdp_tlv_fi_subtree, hf_ecp_vdp_vlan, tvb, tempOffset, 2, ENC_BIG_ENDIAN);
171
172 tempOffset += 2;
173 }
174
175 return tempOffset-offset;
176 }
177
178 /* Dissect Organizationally Defined TLVs */
179 static gint32
dissect_vdp_org_specific_tlv(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,guint32 offset)180 dissect_vdp_org_specific_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
181 {
182 guint16 tempLen;
183 guint16 len;
184 guint16 tempShort;
185 guint32 tempOffset = offset;
186 guint32 oui;
187 const char *ouiStr;
188 guint8 subType, format;
189 const char *subTypeStr;
190
191 proto_tree *ecp_vdp_tlv_subtree;
192
193 tempLen = 0;
194 tempShort = tvb_get_ntohs(tvb, offset);
195 len = TLV_INFO_LEN(tempShort);
196
197 tempOffset += 2;
198
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";
203
204 tempOffset += 3;
205
206 subType = tvb_get_guint8(tvb, tempOffset);
207 tempOffset++;
208
209 switch(oui) {
210 case OUI_IEEE_802_1QBG:
211 subTypeStr = val_to_str(subType, ieee_802_1qbg_subtypes, "Unknown subtype 0x%x");
212 break;
213 default:
214 subTypeStr = "Unknown";
215 break;
216 }
217
218 ecp_vdp_tlv_subtree = proto_tree_add_subtree_format(tree, tvb, offset, (len + 2), ett_ecp, NULL,
219 "%s - %s", ouiStr, subTypeStr);
220
221 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_mode, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
222 tempOffset++;
223
224 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_response, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
225 tempOffset++;
226
227 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_mgrid, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
228 tempOffset++;
229
230 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_vsitypeid, tvb, tempOffset, 3, ENC_BIG_ENDIAN);
231 tempOffset += 3;
232
233 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_vsitypeidversion, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
234 tempOffset += 1;
235
236 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_instanceid, tvb, tempOffset, 16, ENC_NA);
237 tempOffset += 16;
238
239 format = tvb_get_guint8(tvb, tempOffset);
240 proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_format, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
241 tempOffset++;
242
243 switch (format) {
244 case VDP_FIF_VID:
245 /* place holder for future enablement */
246 /* For compatibility of different implementations proceed to next entry */
247 case VDP_FIF_MACVID:
248 tempLen = dissect_vdp_fi_macvid(tvb, pinfo, ecp_vdp_tlv_subtree, tempOffset);
249 break;
250 case VDP_FIF_GROUPVID:
251 /* place holder for future enablement */
252 break;
253 case VDP_FIF_GROUPVMACVID:
254 /* place holder for future enablement */
255 break;
256 default:
257 break;
258 }
259
260 tempOffset += tempLen;
261
262 return tempOffset-offset;
263 }
264
265 /* Dissect End of VDP TLV (Mandatory) */
266 static gint32
dissect_vdp_end_of_vdpdu_tlv(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,guint32 offset)267 dissect_vdp_end_of_vdpdu_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
268 {
269 guint16 tempLen;
270 guint16 tempShort;
271
272 proto_tree *end_of_vdpdu_tree;
273
274 /* Get tlv type and length */
275 tempShort = tvb_get_ntohs(tvb, offset);
276
277 /* Get tlv length */
278 tempLen = TLV_INFO_LEN(tempShort);
279
280 if (tree)
281 {
282 /* Set port tree */
283 end_of_vdpdu_tree = proto_tree_add_subtree(tree, tvb, offset, (tempLen + 2),
284 ett_end_of_vdpdu, NULL, "End of VDPDU");
285
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);
288 }
289
290 return -1; /* Force the VDP dissector to terminate */
291 }
292
293 static int
dissect_ecp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)294 dissect_ecp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
295 {
296 proto_tree *ecp_tree;
297 proto_item *ti;
298 gint32 tempLen = 0;
299 guint32 offset = 0;
300 guint16 tempShort;
301 guint8 tempType;
302 gboolean end = FALSE;
303
304 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ECP");
305
306 ti = proto_tree_add_item(tree, proto_ecp, tvb, 0, -1, ENC_NA);
307 ecp_tree = proto_item_add_subtree(ti, ett_ecp);
308
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);
312
313 offset += 4;
314
315 while (!end) {
316 if (!tvb_bytes_exist(tvb, offset, 1))
317 break;
318
319 tempShort = tvb_get_ntohs(tvb, offset);
320 tempType = TLV_TYPE(tempShort);
321
322 switch (tempType) {
323 case ORG_SPECIFIC_TLV_TYPE:
324 tempLen = dissect_vdp_org_specific_tlv(tvb, pinfo, ecp_tree, offset);
325 break;
326 case END_OF_VDPDU_TLV_TYPE:
327 tempLen = dissect_vdp_end_of_vdpdu_tlv(tvb, pinfo, ecp_tree, offset);
328 break;
329 default:
330 tempLen = dissect_ecp_unknown_tlv(tvb, pinfo, ecp_tree, offset);
331 break;
332 }
333
334 offset += tempLen;
335
336 if (tempLen < 0)
337 end = TRUE;
338 }
339 return tvb_captured_length(tvb);
340 }
341
proto_register_ecp_oui(void)342 void proto_register_ecp_oui(void)
343 {
344 static hf_register_info hf_reg = {
345 &hf_ecp_pid,
346 { "PID", "ieee802a.ecp_pid", FT_UINT16, BASE_HEX,
347 VALS(ecp_pid_vals), 0x0, NULL, HFILL },
348 };
349
350 static hf_register_info hf[] = {
351 { &hf_ecp_tlv_type,
352 { "TLV Type", "ecp.tlv.type", FT_UINT16, BASE_DEC,
353 NULL, TLV_TYPE_MASK, NULL, HFILL }
354 },
355 { &hf_ecp_tlv_len,
356 { "TLV Length", "ecp.tlv.len", FT_UINT16, BASE_DEC,
357 NULL, TLV_INFO_LEN_MASK, NULL, HFILL }
358 },
359
360 { &hf_ecp_subtype,
361 { "subtype", "ecp.subtype", FT_UINT8, BASE_HEX,
362 VALS(ecp_subtypes), 0x0, NULL, HFILL },
363 },
364 { &hf_ecp_mode,
365 { "mode", "ecp.mode", FT_UINT8, BASE_HEX,
366 VALS(ecp_modes), 0x0, NULL, HFILL },
367 },
368 { &hf_ecp_sequence,
369 { "sequence number", "ecp.seq", FT_UINT16, BASE_HEX,
370 NULL, 0x0, NULL, HFILL },
371 },
372 #if 0
373 { &hf_ecp_vdp_oui,
374 { "Organization Unique Code", "ecp.vdp.oui", FT_UINT24, BASE_OUI,
375 NULL, 0x0, NULL, HFILL }
376 },
377 #endif
378 { &hf_ecp_vdp_mode,
379 { "mode", "ecp.vdp.mode", FT_UINT8, BASE_HEX,
380 VALS(ecp_vdp_modes), 0x0, NULL, HFILL },
381 },
382 { &hf_ecp_vdp_response,
383 { "response", "ecp.vdp.response", FT_UINT8, BASE_HEX,
384 VALS(ecp_vdp_responses), 0x0, NULL, HFILL },
385 },
386 { &hf_ecp_vdp_mgrid,
387 { "Manager ID", "ecp.vdp.mgrid", FT_UINT8, BASE_HEX,
388 NULL, 0x0, NULL, HFILL },
389 },
390 { &hf_ecp_vdp_vsitypeid,
391 { "VSI type ID", "ecp.vdp.vsitypeid", FT_UINT24, BASE_HEX,
392 NULL, 0x0, NULL, HFILL },
393 },
394 { &hf_ecp_vdp_vsitypeidversion,
395 { "VSI type ID version", "ecp.vdp.vsitypeidversion", FT_UINT8, BASE_HEX,
396 NULL, 0x0, NULL, HFILL },
397 },
398 { &hf_ecp_vdp_instanceid,
399 { "VSI Instance ID version", "ecp.vdp.instanceid", FT_BYTES, BASE_NONE,
400 NULL, 0x0, NULL, HFILL },
401 },
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 },
405 },
406 { &hf_ecp_vdp_mac,
407 { "VSI Mac Address", "ecp.vdp.mac", FT_ETHER, BASE_NONE,
408 NULL, 0x0, NULL, HFILL }
409 },
410 { &hf_ecp_vdp_vlan,
411 { "VSI VLAN ID", "ecp.vdp.vlan", FT_UINT16, BASE_DEC,
412 NULL, 0x0, NULL, HFILL }
413 },
414 };
415
416 static gint *ett[] = {
417 &ett_ecp,
418 &ett_end_of_vdpdu,
419 &ett_802_1qbg_capabilities_flags,
420 };
421
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));
425
426 ieee802a_add_oui(OUI_IEEE_802_1QBG, "ieee802a.ecp_pid",
427 "IEEE802a ECP PID", &hf_reg, proto_ecp);
428
429 ecp_handle = register_dissector("ecp", dissect_ecp, proto_ecp);
430 }
431
proto_reg_handoff_ecp(void)432 void proto_reg_handoff_ecp(void)
433 {
434 dissector_add_uint("ieee802a.ecp_pid", 0x0000, ecp_handle);
435 }
436
437 /*
438 * Editor modelines - https://www.wireshark.org/tools/modelines.html
439 *
440 * Local variables:
441 * c-basic-offset: 8
442 * tab-width: 8
443 * indent-tabs-mode: t
444 * End:
445 *
446 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
447 * :indentSize=8:tabSize=8:noTabs=false:
448 */
449