Coverage Report

Created: 2026-08-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-ecp-oui.c
Line
Count
Source
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
0
#define END_OF_VDPDU_TLV_TYPE 0x00  /* Mandatory */
31
#define VDP_TLV_TYPE    0x02
32
0
#define ORG_SPECIFIC_TLV_TYPE 0x7F
33
34
/* IEEE 802.1Qbg VDP filter info formats */
35
0
#define VDP_FIF_VID   0x01
36
0
#define VDP_FIF_MACVID    0x02
37
0
#define VDP_FIF_GROUPVID  0x03
38
0
#define VDP_FIF_GROUPVMACVID  0x04
39
40
/* Masks */
41
16
#define TLV_TYPE_MASK   0xFE00
42
0
#define TLV_TYPE(value)   (((value) & TLV_TYPE_MASK) >> 9)
43
16
#define TLV_INFO_LEN_MASK 0x01FF
44
0
#define TLV_INFO_LEN(value) ((value) & TLV_INFO_LEN_MASK)
45
46
static int proto_ecp;
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;
63
64
static int ett_ecp;
65
static int ett_end_of_vdpdu;
66
static int ett_802_1qbg_capabilities_flags;
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 int32_t
128
dissect_ecp_unknown_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, uint32_t offset)
129
0
{
130
0
  uint16_t tempLen;
131
0
  uint16_t tempShort;
132
133
0
  proto_tree *ecp_unknown_tlv_tree;
134
135
  /* Get tlv type and length */
136
0
  tempShort = tvb_get_ntohs(tvb, offset);
137
138
  /* Get tlv length */
139
0
  tempLen = TLV_INFO_LEN(tempShort);
140
141
0
  ecp_unknown_tlv_tree = proto_tree_add_subtree(tree, tvb, offset, (tempLen + 2), ett_ecp, NULL, "Unknown TLV");
142
143
0
  proto_tree_add_item(ecp_unknown_tlv_tree, hf_ecp_subtype, tvb, offset, 1, ENC_BIG_ENDIAN);
144
145
0
  return -1;
146
0
}
147
148
/* Dissect mac/vid pairs in VDP TLVs */
149
static int32_t
150
dissect_vdp_fi_macvid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, uint32_t offset)
151
0
{
152
0
  int i;
153
0
  uint16_t entries;
154
0
  uint32_t tempOffset = offset;
155
156
0
  proto_tree *ecp_vdp_tlv_fi_subtree;
157
158
0
  entries = tvb_get_ntohs(tvb, offset);
159
160
0
  ecp_vdp_tlv_fi_subtree = proto_tree_add_subtree_format(tree, tvb, tempOffset, 2, ett_ecp, NULL,
161
0
      "%i MAC/VID pair%s", entries, plurality(entries, "", "s"));
162
163
0
  tempOffset += 2;
164
165
0
  for (i=0; i < entries; i++) {
166
0
    proto_tree_add_item(ecp_vdp_tlv_fi_subtree, hf_ecp_vdp_mac, tvb, tempOffset, 6, ENC_NA);
167
168
0
    tempOffset += 6;
169
170
0
    proto_tree_add_item(ecp_vdp_tlv_fi_subtree, hf_ecp_vdp_vlan, tvb, tempOffset, 2, ENC_BIG_ENDIAN);
171
172
0
    tempOffset += 2;
173
0
  }
174
175
0
  return tempOffset-offset;
176
0
}
177
178
/* Dissect Organizationally Defined TLVs */
179
static int32_t
180
dissect_vdp_org_specific_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset)
181
0
{
182
0
  uint16_t tempLen;
183
0
  uint16_t len;
184
0
  uint16_t tempShort;
185
0
  uint32_t tempOffset = offset;
186
0
  uint32_t oui;
187
0
  const char *ouiStr;
188
0
  uint8_t subType, format;
189
0
  const char *subTypeStr;
190
191
0
  proto_tree  *ecp_vdp_tlv_subtree;
192
193
0
  tempLen = 0;
194
0
  tempShort = tvb_get_ntohs(tvb, offset);
195
0
  len = TLV_INFO_LEN(tempShort);
196
197
0
  tempOffset += 2;
198
199
0
  oui = tvb_get_ntoh24(tvb, (tempOffset));
200
  /* Look in manuf database for OUI */
201
0
  ouiStr = uint_get_manuf_name_if_known(oui);
202
0
  if(ouiStr==NULL) ouiStr="Unknown";
203
204
0
  tempOffset += 3;
205
206
0
  subType = tvb_get_uint8(tvb, tempOffset);
207
0
  tempOffset++;
208
209
0
  switch(oui) {
210
0
  case OUI_IEEE_802_1QBG:
211
0
    subTypeStr = val_to_str(pinfo->pool, subType, ieee_802_1qbg_subtypes, "Unknown subtype 0x%x");
212
0
    break;
213
0
  default:
214
0
    subTypeStr = "Unknown";
215
0
    break;
216
0
  }
217
218
0
  ecp_vdp_tlv_subtree = proto_tree_add_subtree_format(tree, tvb, offset, (len + 2), ett_ecp, NULL,
219
0
      "%s - %s", ouiStr, subTypeStr);
220
221
0
  proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_mode, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
222
0
  tempOffset++;
223
224
0
  proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_response, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
225
0
  tempOffset++;
226
227
0
  proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_mgrid, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
228
0
  tempOffset++;
229
230
0
  proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_vsitypeid, tvb, tempOffset, 3, ENC_BIG_ENDIAN);
231
0
  tempOffset += 3;
232
233
0
  proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_vsitypeidversion, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
234
0
  tempOffset += 1;
235
236
0
  proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_instanceid, tvb, tempOffset, 16, ENC_NA);
237
0
  tempOffset += 16;
238
239
0
  proto_tree_add_item_ret_uint8(ecp_vdp_tlv_subtree, hf_ecp_vdp_format, tvb, tempOffset, 1, ENC_BIG_ENDIAN, &format);
240
0
  tempOffset++;
241
242
0
  switch (format) {
243
0
  case VDP_FIF_VID:
244
    /* place holder for future enablement */
245
    /* For compatibility of different implementations proceed to next entry */
246
0
  case VDP_FIF_MACVID:
247
0
    tempLen = dissect_vdp_fi_macvid(tvb, pinfo, ecp_vdp_tlv_subtree, tempOffset);
248
0
    break;
249
0
  case VDP_FIF_GROUPVID:
250
    /* place holder for future enablement */
251
0
    break;
252
0
  case VDP_FIF_GROUPVMACVID:
253
    /* place holder for future enablement */
254
0
    break;
255
0
  default:
256
0
    break;
257
0
  }
258
259
0
  tempOffset += tempLen;
260
261
0
  return tempOffset-offset;
262
0
}
263
264
/* Dissect End of VDP TLV (Mandatory) */
265
static int32_t
266
dissect_vdp_end_of_vdpdu_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, uint32_t offset)
267
0
{
268
0
  uint16_t tempLen;
269
0
  uint16_t tempShort;
270
271
0
  proto_tree  *end_of_vdpdu_tree;
272
273
  /* Get tlv type and length */
274
0
  tempShort = tvb_get_ntohs(tvb, offset);
275
276
  /* Get tlv length */
277
0
  tempLen = TLV_INFO_LEN(tempShort);
278
279
0
  if (tree)
280
0
  {
281
    /* Set port tree */
282
0
    end_of_vdpdu_tree = proto_tree_add_subtree(tree, tvb, offset, (tempLen + 2),
283
0
                    ett_end_of_vdpdu, NULL, "End of VDPDU");
284
285
0
    proto_tree_add_item(end_of_vdpdu_tree, hf_ecp_tlv_type, tvb, offset, 2, ENC_BIG_ENDIAN);
286
0
    proto_tree_add_item(end_of_vdpdu_tree, hf_ecp_tlv_len, tvb, offset, 2, ENC_BIG_ENDIAN);
287
0
  }
288
289
0
  return -1;  /* Force the VDP dissector to terminate */
290
0
}
291
292
static int
293
dissect_ecp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
294
0
{
295
0
  proto_tree *ecp_tree;
296
0
  proto_item *ti;
297
0
  int32_t tempLen = 0;
298
0
  uint32_t offset = 0;
299
0
  uint16_t tempShort;
300
0
  uint8_t tempType;
301
0
  bool end = false;
302
303
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "ECP");
304
305
0
  ti = proto_tree_add_item(tree, proto_ecp, tvb, 0, -1, ENC_NA);
306
0
  ecp_tree = proto_item_add_subtree(ti, ett_ecp);
307
308
0
  proto_tree_add_item(ecp_tree, hf_ecp_subtype, tvb, offset, 1, ENC_BIG_ENDIAN);
309
0
  proto_tree_add_item(ecp_tree, hf_ecp_mode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
310
0
  proto_tree_add_item(ecp_tree, hf_ecp_sequence, tvb, offset+2, 2, ENC_BIG_ENDIAN);
311
312
0
  offset += 4;
313
314
0
  while (!end) {
315
0
    if (!tvb_bytes_exist(tvb, offset, 1))
316
0
      break;
317
318
0
    tempShort = tvb_get_ntohs(tvb, offset);
319
0
    tempType = TLV_TYPE(tempShort);
320
321
0
    switch (tempType) {
322
0
    case ORG_SPECIFIC_TLV_TYPE:
323
0
      tempLen = dissect_vdp_org_specific_tlv(tvb, pinfo, ecp_tree, offset);
324
0
      break;
325
0
    case END_OF_VDPDU_TLV_TYPE:
326
0
      tempLen = dissect_vdp_end_of_vdpdu_tlv(tvb, pinfo, ecp_tree, offset);
327
0
      break;
328
0
    default:
329
0
      tempLen = dissect_ecp_unknown_tlv(tvb, pinfo, ecp_tree, offset);
330
0
      break;
331
0
    }
332
333
0
    offset += tempLen;
334
335
0
    if (tempLen < 0)
336
0
      end = true;
337
0
  }
338
0
  return tvb_captured_length(tvb);
339
0
}
340
341
void proto_register_ecp_oui(void)
342
16
{
343
16
  static hf_register_info hf_reg = {
344
16
    &hf_ecp_pid,
345
16
    { "PID", "ieee802a.ecp_pid", FT_UINT16, BASE_HEX,
346
16
      VALS(ecp_pid_vals), 0x0, NULL, HFILL },
347
16
  };
348
349
16
  static hf_register_info hf[] = {
350
16
    { &hf_ecp_tlv_type,
351
16
      { "TLV Type", "ecp.tlv.type", FT_UINT16, BASE_DEC,
352
16
      NULL, TLV_TYPE_MASK, NULL, HFILL }
353
16
    },
354
16
    { &hf_ecp_tlv_len,
355
16
      { "TLV Length", "ecp.tlv.len", FT_UINT16, BASE_DEC,
356
16
      NULL, TLV_INFO_LEN_MASK, NULL, HFILL }
357
16
    },
358
359
16
    { &hf_ecp_subtype,
360
16
      { "subtype", "ecp.subtype", FT_UINT8, BASE_HEX,
361
16
        VALS(ecp_subtypes), 0x0, NULL, HFILL },
362
16
    },
363
16
    { &hf_ecp_mode,
364
16
      { "mode", "ecp.mode", FT_UINT8, BASE_HEX,
365
16
        VALS(ecp_modes), 0x0, NULL, HFILL },
366
16
    },
367
16
    { &hf_ecp_sequence,
368
16
      { "sequence number", "ecp.seq", FT_UINT16, BASE_HEX,
369
16
        NULL, 0x0, NULL, HFILL },
370
16
    },
371
#if 0
372
    { &hf_ecp_vdp_oui,
373
      { "Organization Unique Code", "ecp.vdp.oui", FT_UINT24, BASE_OUI,
374
      NULL, 0x0, NULL, HFILL }
375
    },
376
#endif
377
16
    { &hf_ecp_vdp_mode,
378
16
      { "mode", "ecp.vdp.mode", FT_UINT8, BASE_HEX,
379
16
        VALS(ecp_vdp_modes), 0x0, NULL, HFILL },
380
16
    },
381
16
    { &hf_ecp_vdp_response,
382
16
      { "response", "ecp.vdp.response", FT_UINT8, BASE_HEX,
383
16
        VALS(ecp_vdp_responses), 0x0, NULL, HFILL },
384
16
    },
385
16
    { &hf_ecp_vdp_mgrid,
386
16
      { "Manager ID", "ecp.vdp.mgrid", FT_UINT8, BASE_HEX,
387
16
        NULL, 0x0, NULL, HFILL },
388
16
    },
389
16
    { &hf_ecp_vdp_vsitypeid,
390
16
      { "VSI type ID", "ecp.vdp.vsitypeid", FT_UINT24, BASE_HEX,
391
16
        NULL, 0x0, NULL, HFILL },
392
16
    },
393
16
    { &hf_ecp_vdp_vsitypeidversion,
394
16
      { "VSI type ID version", "ecp.vdp.vsitypeidversion", FT_UINT8, BASE_HEX,
395
16
        NULL, 0x0, NULL, HFILL },
396
16
    },
397
16
    { &hf_ecp_vdp_instanceid,
398
16
      { "VSI Instance ID version", "ecp.vdp.instanceid", FT_BYTES, BASE_NONE,
399
16
        NULL, 0x0, NULL, HFILL },
400
16
    },
401
16
    { &hf_ecp_vdp_format,
402
16
      { "VSI filter info format", "ecp.vdp.format", FT_UINT8, BASE_HEX,
403
16
        VALS(ecp_vdp_formats), 0x0, NULL, HFILL },
404
16
    },
405
16
    { &hf_ecp_vdp_mac,
406
16
      { "VSI Mac Address", "ecp.vdp.mac", FT_ETHER, BASE_NONE,
407
16
        NULL, 0x0, NULL, HFILL }
408
16
    },
409
16
    { &hf_ecp_vdp_vlan,
410
16
      { "VSI VLAN ID", "ecp.vdp.vlan", FT_UINT16, BASE_DEC,
411
16
        NULL, 0x0, NULL, HFILL }
412
16
    },
413
16
  };
414
415
16
  static int *ett[] = {
416
16
    &ett_ecp,
417
16
    &ett_end_of_vdpdu,
418
16
    &ett_802_1qbg_capabilities_flags,
419
16
  };
420
421
16
  proto_ecp = proto_register_protocol("ECP Protocol", "ECP", "ecp");
422
16
  proto_register_field_array(proto_ecp, hf, array_length(hf));
423
16
  proto_register_subtree_array(ett, array_length(ett));
424
425
16
  ieee802a_add_oui(OUI_IEEE_802_1QBG, "ieee802a.ecp_pid",
426
16
    "IEEE802a ECP PID", &hf_reg, proto_ecp);
427
428
16
  ecp_handle = register_dissector("ecp", dissect_ecp, proto_ecp);
429
16
}
430
431
void proto_reg_handoff_ecp(void)
432
16
{
433
16
  dissector_add_uint("ieee802a.ecp_pid", 0x0000, ecp_handle);
434
16
}
435
436
/*
437
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
438
 *
439
 * Local variables:
440
 * c-basic-offset: 8
441
 * tab-width: 8
442
 * indent-tabs-mode: t
443
 * End:
444
 *
445
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
446
 * :indentSize=8:tabSize=8:noTabs=false:
447
 */