Coverage Report

Created: 2025-12-27 06:52

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