Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-foundry.c
Line
Count
Source
1
/* packet-foundry.c
2
 * Routines for the disassembly of Foundry LLC messages (currently
3
 * Foundry Discovery Protocol - FDP only)
4
 *
5
 * Copyright 2012 Joerg Mayer (see AUTHORS file)
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/expert.h>
18
#include <epan/strutil.h>
19
#include "packet-llc.h"
20
#include <epan/oui.h>
21
22
void proto_register_fdp(void);
23
void proto_reg_handoff_fdp(void);
24
25
static dissector_handle_t fdp_handle;
26
27
static int hf_llc_foundry_pid;
28
29
static int proto_fdp;
30
/* FDP header */
31
static int hf_fdp_version;
32
static int hf_fdp_holdtime;
33
static int hf_fdp_checksum;
34
/* TLV header */
35
static int hf_fdp_tlv_type;
36
static int hf_fdp_tlv_length;
37
/* Unknown element */
38
static int hf_fdp_unknown;
39
static int hf_fdp_unknown_data;
40
/* Port Tag element */
41
static int hf_fdp_tag;
42
static int hf_fdp_tag_native;
43
static int hf_fdp_tag_type;
44
static int hf_fdp_tag_unknown;
45
/* VLAN Bitmap */
46
static int hf_fdp_vlanmap;
47
static int hf_fdp_vlanmap_vlan;
48
/* String element */
49
static int hf_fdp_string;
50
static int hf_fdp_string_data;
51
static int hf_fdp_string_text;
52
/* Net? element */
53
static int hf_fdp_net;
54
static int hf_fdp_net_unknown;
55
static int hf_fdp_net_ip;
56
static int hf_fdp_net_iplength;
57
58
static int ett_fdp;
59
static int ett_fdp_tlv_header;
60
static int ett_fdp_unknown;
61
static int ett_fdp_string;
62
static int ett_fdp_net;
63
static int ett_fdp_tag;
64
static int ett_fdp_vlanmap;
65
66
static expert_field ei_fdp_tlv_length;
67
68
static const value_string foundry_pid_vals[] = {
69
  { 0x2000, "FDP" },
70
71
  { 0,    NULL }
72
};
73
74
typedef enum {
75
  FDP_TYPE_NAME = 1,
76
  FDP_TYPE_NET = 2,
77
  FDP_TYPE_PORT = 3,
78
  FDP_TYPE_CAPABILITIES = 4,
79
  FDP_TYPE_VERSION = 5,
80
  FDP_TYPE_MODEL = 6,
81
  FDP_TYPE_VLANMAP = 0x0101,
82
  FDP_TYPE_TAG = 0x0102
83
} fdp_type_t;
84
85
static const value_string fdp_type_vals[] = {
86
  { FDP_TYPE_NAME,    "DeviceID"},
87
  { FDP_TYPE_NET,     "Net?"},
88
  { FDP_TYPE_PORT,    "Interface"},
89
  { FDP_TYPE_CAPABILITIES,  "Capabilities"},
90
  { FDP_TYPE_VERSION,   "Version"},
91
  { FDP_TYPE_MODEL,   "Platform"},
92
  { FDP_TYPE_VLANMAP,   "VLAN-Bitmap"},
93
  { FDP_TYPE_TAG,     "Tagging-Info"},
94
95
  { 0,    NULL }
96
};
97
98
static int
99
dissect_tlv_header(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, int length _U_, proto_tree *tree)
100
0
{
101
0
  proto_tree  *tlv_tree;
102
0
  uint16_t    tlv_type;
103
0
  uint16_t    tlv_length;
104
105
0
  tlv_type = tvb_get_ntohs(tvb, offset);
106
0
  tlv_length = tvb_get_ntohs(tvb, offset + 2);
107
108
0
  tlv_tree = proto_tree_add_subtree_format(tree, tvb, offset, 4,
109
0
    ett_fdp_tlv_header, NULL, "Length %d, type %d = %s",
110
0
    tlv_length, tlv_type,
111
0
    val_to_str(pinfo->pool, tlv_type, fdp_type_vals, "Unknown (%d)"));
112
113
0
  proto_tree_add_uint(tlv_tree, hf_fdp_tlv_type, tvb, offset, 2, tlv_type);
114
0
  offset += 2;
115
116
0
  proto_tree_add_uint(tlv_tree, hf_fdp_tlv_length, tvb, offset, 2, tlv_length);
117
0
  offset += 2;
118
119
0
  return offset;
120
0
}
121
122
static int
123
dissect_string_tlv(tvbuff_t *tvb, packet_info *pinfo, int offset, int length, proto_tree *tree, const char* type_string)
124
0
{
125
0
  proto_item  *string_item;
126
0
  proto_tree  *string_tree;
127
0
  const char  *string_value;
128
129
0
  string_item = proto_tree_add_protocol_format(tree, hf_fdp_string,
130
0
    tvb, offset, length, "%s", type_string);
131
132
0
  string_tree = proto_item_add_subtree(string_item, ett_fdp_string);
133
134
0
  dissect_tlv_header(tvb, pinfo, offset, 4, string_tree);
135
0
  offset += 4;
136
0
  length -= 4;
137
138
0
  proto_tree_add_item(string_tree, hf_fdp_string_data, tvb, offset, length, ENC_NA);
139
0
  proto_tree_add_item_ret_string(string_tree, hf_fdp_string_text, tvb, offset, length, ENC_ASCII|ENC_NA, pinfo->pool, (const uint8_t**)&string_value);
140
0
  proto_item_append_text(string_item, ": \"%s\"",
141
0
    format_text(pinfo->pool, string_value, strlen(string_value)));
142
143
0
  return offset;
144
0
}
145
146
static void
147
dissect_net_tlv(tvbuff_t *tvb, packet_info *pinfo, int offset, int length, proto_tree *tree)
148
0
{
149
0
  proto_item  *net_item;
150
0
  proto_tree  *net_tree;
151
152
0
  net_item = proto_tree_add_protocol_format(tree, hf_fdp_net,
153
0
    tvb, offset, length, "Net?");
154
155
0
  net_tree = proto_item_add_subtree(net_item, ett_fdp_net);
156
157
0
  dissect_tlv_header(tvb, pinfo, offset, 4, net_tree);
158
0
  offset += 4;
159
0
  length -= 4;
160
161
0
  proto_tree_add_item(net_tree, hf_fdp_net_unknown, tvb, offset, 7, ENC_NA);
162
0
  offset += 7;
163
0
  length -= 7;
164
165
  /* Length of IP address block in bytes */
166
0
  proto_tree_add_item(net_tree, hf_fdp_net_iplength, tvb, offset, 2, ENC_BIG_ENDIAN);
167
0
  offset += 2;
168
0
  length -= 2;
169
170
0
  while (length >= 4) {
171
0
    proto_tree_add_item(net_tree, hf_fdp_net_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
172
0
    offset += 4;
173
0
    length -= 4;
174
0
  }
175
0
}
176
177
static void
178
dissect_vlanmap_tlv(tvbuff_t *tvb, packet_info *pinfo, int offset, int length, proto_tree *tree)
179
0
{
180
0
  proto_item  *vlanmap_item;
181
0
  proto_tree  *vlanmap_tree;
182
0
  unsigned    vlan, voffset;
183
0
  unsigned    bitoffset, byteoffset;
184
185
0
  vlanmap_item = proto_tree_add_protocol_format(tree, hf_fdp_vlanmap,
186
0
    tvb, offset, length, "VLAN-Map");
187
188
0
  vlanmap_tree = proto_item_add_subtree(vlanmap_item, ett_fdp_vlanmap);
189
190
0
  dissect_tlv_header(tvb, pinfo, offset, 4, vlanmap_tree);
191
0
  offset += 4;
192
0
  length -= 4;
193
194
0
  voffset = 1;
195
0
  for (vlan = 1; vlan <= (unsigned)length*8; vlan++) {
196
0
    byteoffset = (vlan - voffset) / 8;
197
0
    bitoffset = (vlan - voffset) % 8;
198
0
    if (tvb_get_uint8(tvb, offset + byteoffset) & (1 << bitoffset)) {
199
200
0
      proto_tree_add_uint(vlanmap_tree, hf_fdp_vlanmap_vlan, tvb,
201
0
        offset + byteoffset, 1, vlan);
202
0
    }
203
0
  }
204
0
}
205
206
static void
207
dissect_tag_tlv(tvbuff_t *tvb, packet_info *pinfo, int offset, int length, proto_tree *tree)
208
0
{
209
0
  proto_item  *tag_item;
210
0
  proto_tree  *tag_tree;
211
212
0
  tag_item = proto_tree_add_protocol_format(tree, hf_fdp_tag,
213
0
    tvb, offset, length, "Port tag");
214
215
0
  tag_tree = proto_item_add_subtree(tag_item, ett_fdp_tag);
216
217
0
  dissect_tlv_header(tvb, pinfo, offset, 4, tag_tree);
218
0
  offset += 4;
219
0
  length -= 4;
220
0
  proto_tree_add_item(tag_tree, hf_fdp_tag_native, tvb, offset, 2, ENC_BIG_ENDIAN);
221
0
  offset += 2;
222
0
  length -= 2;
223
0
  proto_tree_add_item(tag_tree, hf_fdp_tag_type, tvb, offset, 2, ENC_BIG_ENDIAN);
224
0
  offset += 2;
225
0
  length -= 2;
226
0
  proto_tree_add_item(tag_tree, hf_fdp_tag_unknown, tvb, offset, length, ENC_NA);
227
0
}
228
229
static void
230
dissect_unknown_tlv(tvbuff_t *tvb, packet_info *pinfo, int offset, int length, proto_tree *tree)
231
0
{
232
0
  proto_item  *unknown_item;
233
0
  proto_tree  *unknown_tree;
234
0
  uint16_t    tlv_type;
235
236
0
  tlv_type = tvb_get_ntohs(tvb, offset);
237
238
0
  unknown_item = proto_tree_add_protocol_format(tree, hf_fdp_unknown,
239
0
    tvb, offset, length, "Unknown element [%u]", tlv_type);
240
241
0
  unknown_tree = proto_item_add_subtree(unknown_item, ett_fdp_unknown);
242
243
0
  dissect_tlv_header(tvb, pinfo, offset, 4, unknown_tree);
244
0
  offset += 4;
245
0
  length -= 4;
246
247
0
  proto_tree_add_item(unknown_tree, hf_fdp_unknown_data, tvb, offset, length, ENC_NA);
248
0
}
249
250
static int
251
dissect_fdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
252
0
{
253
0
  proto_item *ti;
254
0
  proto_tree *fdp_tree = NULL;
255
0
  unsigned offset = 0;
256
0
  uint16_t tlv_type;
257
0
  uint16_t tlv_length;
258
0
  unsigned data_length;
259
0
  const char *type_string;
260
261
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "FDP");
262
0
  col_set_str(pinfo->cinfo, COL_INFO, "FDP:");
263
264
0
  if (tree) {
265
0
    data_length = tvb_reported_length_remaining(tvb, offset);
266
267
0
    ti = proto_tree_add_item(tree, proto_fdp, tvb, offset, -1, ENC_NA);
268
0
    fdp_tree = proto_item_add_subtree(ti, ett_fdp);
269
270
0
    proto_tree_add_item(fdp_tree, hf_fdp_version, tvb, offset, 1, ENC_BIG_ENDIAN);
271
0
    offset += 1;
272
0
    proto_tree_add_item(fdp_tree, hf_fdp_holdtime, tvb, offset, 1, ENC_BIG_ENDIAN);
273
0
    offset += 1;
274
0
    proto_tree_add_checksum(fdp_tree, tvb, offset, hf_fdp_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
275
0
    offset += 2;
276
277
    /* Decode the individual TLVs */
278
0
    while (offset < data_length) {
279
0
      if (data_length - offset < 4) {
280
0
        proto_tree_add_expert_format(fdp_tree, pinfo, &ei_fdp_tlv_length, tvb, offset, 4,
281
0
          "Too few bytes left for TLV: %u (< 4)", data_length - offset);
282
0
        break;
283
0
      }
284
0
      tlv_type = tvb_get_ntohs(tvb, offset);
285
0
      tlv_length = tvb_get_ntohs(tvb, offset + 2);
286
287
0
      if ((tlv_length < 4) || (tlv_length > (data_length - offset))) {
288
0
        proto_tree_add_expert_format(fdp_tree, pinfo, &ei_fdp_tlv_length, tvb, offset, 0,
289
0
          "TLV with invalid length: %u", tlv_length);
290
0
        break;
291
0
      }
292
0
      type_string = val_to_str(pinfo->pool, tlv_type, fdp_type_vals, "[%u]");
293
0
      col_append_fstr(pinfo->cinfo, COL_INFO, " %s", type_string);
294
295
0
      switch (tlv_type) {
296
0
      case FDP_TYPE_NAME:
297
0
      case FDP_TYPE_PORT:
298
0
      case FDP_TYPE_CAPABILITIES:
299
0
      case FDP_TYPE_VERSION:
300
0
      case FDP_TYPE_MODEL:
301
0
        dissect_string_tlv(tvb, pinfo, offset, tlv_length, fdp_tree, type_string);
302
0
        break;
303
0
      case FDP_TYPE_NET:
304
0
        dissect_net_tlv(tvb, pinfo, offset, tlv_length, fdp_tree);
305
0
        break;
306
0
      case FDP_TYPE_TAG:
307
0
        dissect_tag_tlv(tvb, pinfo, offset, tlv_length, fdp_tree);
308
0
        break;
309
0
      case FDP_TYPE_VLANMAP:
310
0
        dissect_vlanmap_tlv(tvb, pinfo, offset, tlv_length, fdp_tree);
311
0
        break;
312
0
      default:
313
0
        dissect_unknown_tlv(tvb, pinfo, offset, tlv_length, fdp_tree);
314
0
        break;
315
0
      }
316
0
      offset += tlv_length;
317
0
    }
318
319
0
  }
320
0
  return tvb_captured_length(tvb);
321
0
}
322
323
void
324
proto_register_fdp(void)
325
14
{
326
14
  static hf_register_info hf[] = {
327
328
  /* FDP header */
329
14
    { &hf_fdp_version,
330
14
    { "Version?", "fdp.version", FT_UINT8, BASE_DEC, NULL,
331
14
      0x0, NULL, HFILL }},
332
333
14
    { &hf_fdp_holdtime,
334
14
    { "Holdtime", "fdp.holdtime", FT_UINT8, BASE_DEC, NULL,
335
14
      0x0, NULL, HFILL }},
336
337
14
    { &hf_fdp_checksum,
338
14
    { "Checksum?",  "fdp.checksum", FT_UINT16, BASE_HEX, NULL,
339
14
      0x0, NULL, HFILL }},
340
341
  /* TLV header */
342
14
    { &hf_fdp_tlv_type,
343
14
    { "TLV type", "fdp.tlv.type", FT_UINT16, BASE_DEC, VALS(fdp_type_vals),
344
14
      0x0, NULL, HFILL }},
345
346
14
    { &hf_fdp_tlv_length,
347
14
    { "TLV length", "fdp.tlv.length", FT_UINT16, BASE_DEC, NULL,
348
14
      0x0, NULL, HFILL }},
349
350
  /* Unknown element */
351
14
    { &hf_fdp_unknown,
352
14
    { "Unknown",  "fdp.unknown", FT_PROTOCOL, BASE_NONE, NULL,
353
14
      0x0, NULL, HFILL }},
354
355
14
    { &hf_fdp_unknown_data,
356
14
    { "Unknown",  "fdp.unknown.data", FT_BYTES, BASE_NONE, NULL,
357
14
      0x0, NULL, HFILL }},
358
359
  /* String element */
360
14
    { &hf_fdp_string,
361
14
    { "DeviceID", "fdp.deviceid", FT_PROTOCOL, BASE_NONE, NULL,
362
14
      0x0, NULL, HFILL }},
363
364
14
    { &hf_fdp_string_data,
365
14
    { "Data", "fdp.string.data", FT_BYTES, BASE_NONE, NULL,
366
14
      0x0, NULL, HFILL }},
367
368
14
    { &hf_fdp_string_text,
369
14
    { "Text", "fdp.string.text", FT_STRING, BASE_NONE, NULL,
370
14
      0x0, NULL, HFILL }},
371
372
  /* Net? element */
373
14
    { &hf_fdp_net,
374
14
    { "Net?", "fdp.net", FT_PROTOCOL, BASE_NONE, NULL,
375
14
      0x0, NULL, HFILL }},
376
377
14
    { &hf_fdp_net_unknown,
378
14
    { "Net Unknown?", "fdp.net.unknown", FT_BYTES, BASE_NONE, NULL,
379
14
      0x0, NULL, HFILL }},
380
381
14
    { &hf_fdp_net_iplength,
382
14
    { "Net IP Bytes?",  "fdp.net.iplength", FT_UINT16, BASE_DEC, NULL,
383
14
      0x0, "Number of bytes carrying IP addresses", HFILL }},
384
385
14
    { &hf_fdp_net_ip,
386
14
    { "Net IP Address?",  "fdp.net.ip", FT_IPv4, BASE_NONE, NULL,
387
14
      0x0, NULL, HFILL }},
388
389
  /* VLAN Bitmap */
390
14
    { &hf_fdp_vlanmap,
391
14
    { "VLAN Map", "fdp.vlanmap", FT_PROTOCOL, BASE_NONE, NULL,
392
14
      0x0, NULL, HFILL }},
393
394
14
    { &hf_fdp_vlanmap_vlan,
395
14
    { "VLAN",   "fdp.vlanmap.vlan", FT_UINT16, BASE_DEC, NULL,
396
14
      0x0, NULL, HFILL }},
397
398
  /* Port Tag element */
399
14
    { &hf_fdp_tag,
400
14
    { "Tag",  "fdp.tag", FT_PROTOCOL, BASE_NONE, NULL,
401
14
      0x0, NULL, HFILL }},
402
403
14
    { &hf_fdp_tag_native,
404
14
    { "Native", "fdp.tag.native", FT_UINT16, BASE_DEC, NULL,
405
14
      0x0, NULL, HFILL }},
406
407
14
    { &hf_fdp_tag_type,
408
14
    { "Type", "fdp.tag.type", FT_UINT16, BASE_HEX, NULL,
409
14
      0x0, NULL, HFILL }},
410
411
14
    { &hf_fdp_tag_unknown,
412
14
    { "Unknown",  "fdp.tag.unknown", FT_BYTES, BASE_NONE, NULL,
413
14
      0x0, NULL, HFILL }},
414
415
14
  };
416
417
14
  static hf_register_info oui_hf[] = {
418
14
    { &hf_llc_foundry_pid,
419
14
    { "PID",  "llc.foundry_pid",  FT_UINT16, BASE_HEX,
420
14
      VALS(foundry_pid_vals), 0x0, NULL, HFILL }
421
14
    }
422
14
  };
423
424
14
  static int *ett[] = {
425
14
    &ett_fdp,
426
14
    &ett_fdp_tlv_header,
427
14
    &ett_fdp_unknown,
428
14
    &ett_fdp_string,
429
14
    &ett_fdp_net,
430
14
    &ett_fdp_tag,
431
14
    &ett_fdp_vlanmap,
432
14
  };
433
434
14
  static ei_register_info ei[] = {
435
14
    { &ei_fdp_tlv_length, { "fdp.tlv.length.invalid", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
436
14
  };
437
438
14
  expert_module_t* expert_fdp;
439
440
14
  proto_fdp = proto_register_protocol("Foundry Discovery Protocol", "FDP", "fdp");
441
442
14
  proto_register_field_array(proto_fdp, hf, array_length(hf));
443
14
  proto_register_subtree_array(ett, array_length(ett));
444
14
  expert_fdp = expert_register_protocol(proto_fdp);
445
14
  expert_register_field_array(expert_fdp, ei, array_length(ei));
446
447
14
  llc_add_oui(OUI_FOUNDRY, "llc.foundry_pid", "LLC Foundry OUI PID", oui_hf, proto_fdp);
448
449
14
  fdp_handle = register_dissector("fdp", dissect_fdp, proto_fdp);
450
14
}
451
452
void
453
proto_reg_handoff_fdp(void)
454
14
{
455
14
  dissector_add_uint("llc.foundry_pid", 0x2000, fdp_handle);
456
14
}
457
458
/*
459
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
460
 *
461
 * Local variables:
462
 * c-basic-offset: 8
463
 * tab-width: 8
464
 * indent-tabs-mode: t
465
 * End:
466
 *
467
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
468
 * :indentSize=8:tabSize=8:noTabs=false:
469
 */