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-nwp.c
Line
Count
Source
1
/* packet-nwp.c
2
 * Routines for NWP dissection
3
 *
4
 * Wireshark - Network traffic analyzer
5
 * By Gerald Combs <gerald@wireshark.org>
6
 * Copyright 1998 Gerald Combs
7
 *
8
 * SPDX-License-Identifier: GPL-2.0-or-later
9
 *
10
 * Neighborhood Watch Protocol (NWP) is an XIA protocol for resolving network
11
 * addresses to link-layer addresses. Hosts on a LAN send NWP Announcement
12
 * packets with their host identifiers (HIDs), and neighbors in the LAN
13
 * respond with NWP Neighbor List packets containing their HIDs and associated
14
 * link-layer addresses.
15
 */
16
17
#include "config.h"
18
#include <epan/packet.h>
19
#include <epan/expert.h>
20
21
void proto_register_nwp(void);
22
void proto_reg_handoff_nwp(void);
23
24
static int proto_nwp;
25
26
/* Header fields for all NWP headers. */
27
static int hf_nwp_version;
28
static int hf_nwp_type;
29
static int hf_nwp_hid_count;
30
static int hf_nwp_haddr_len;
31
32
/* Header fields for NWP Announcement packets. */
33
static int hf_nwp_ann_haddr;
34
static int hf_nwp_ann_hids;
35
static int hf_nwp_ann_hid;
36
37
/* Header fields for NWP Neighbor List packets. */
38
static int hf_nwp_neigh_list;
39
static int hf_nwp_neigh;
40
static int hf_nwp_neigh_hid;
41
static int hf_nwp_neigh_num;
42
static int hf_nwp_neigh_haddr;
43
44
static int ett_nwp_tree;
45
static int ett_nwp_ann_hid_tree;
46
static int ett_nwp_neigh_list_tree;
47
static int ett_nwp_neigh_tree;
48
49
static expert_field ei_nwp_bad_type;
50
51
static dissector_handle_t nwp_handle;
52
53
3.33k
#define NWP_XID_CHUNK_LEN 4
54
3.19k
#define NWP_XID_LEN   20
55
/* Two characters for every byte + 4 for "hid-" + 1 for "\0" */
56
36
#define NWP_HID_STR_LEN   ((NWP_XID_LEN * 2) + 5)
57
58
/* Room for a string of hardware addresses of the form:
59
 *
60
 *  XX:...:XX; XX:...:XX; ...
61
 *
62
 * (2 * LEN) bytes for each hardware address, plus (LEN - 1) bytes for colons,
63
 * plus 2 bytes for "; ". Multiply that by the COUNT of hardware addresses
64
 * that are present.
65
 */
66
#define NWP_HADDRS_STR_LEN(LEN, COUNT)  (((2 * LEN) + (LEN - 1) + 2) * COUNT)
67
68
39
#define NWPH_MIN_LEN    4
69
14
#define ETHERTYPE_NWP   0xC0DF
70
#define NWP_VERSION   0x01
71
72
0
#define NWP_TYPE_ANNOUNCEMENT 0x01
73
36
#define NWP_TYPE_NEIGH_LIST 0x02
74
75
/* Offsets of fields in NWP Announcements/Neighbor Lists. */
76
38
#define NWPH_VERS   0
77
76
#define NWPH_TYPE   1
78
76
#define NWPH_HIDC   2
79
76
#define NWPH_HLEN   3
80
81
72
#define NWPH_NLST   4
82
0
#define NWPH_HWAD   4
83
84
static const value_string nwp_type_vals[] = {
85
  { NWP_TYPE_ANNOUNCEMENT,  "NWP Announcement" },
86
  { NWP_TYPE_NEIGH_LIST,    "NWP Neighbor List" },
87
  { 0,        NULL }
88
};
89
90
static void
91
add_hid_to_strbuf(tvbuff_t *tvb, wmem_strbuf_t *hid_buf, int offset)
92
303
{
93
303
  int i;
94
1.81k
  for (i = 0; i < NWP_XID_LEN / NWP_XID_CHUNK_LEN; i++) {
95
1.51k
    wmem_strbuf_append_printf(hid_buf, "%08x",
96
1.51k
      tvb_get_ntohl(tvb, offset));
97
1.51k
    offset += NWP_XID_CHUNK_LEN;
98
1.51k
  }
99
303
}
100
101
static void
102
dissect_nwp_ann(tvbuff_t *tvb, packet_info* pinfo, proto_tree *nwp_tree, uint8_t hid_count,
103
  uint8_t ha_len)
104
0
{
105
0
  proto_tree *hid_tree = NULL;
106
0
  proto_item *ti = NULL;
107
108
0
  wmem_strbuf_t *buf;
109
0
  unsigned i;
110
0
  int offset;
111
112
  /* Add hardware address. */
113
0
  proto_tree_add_item(nwp_tree, hf_nwp_ann_haddr, tvb, NWPH_HWAD,
114
0
    ha_len, ENC_NA);
115
116
  /* Add tree for HIDs. */
117
0
  ti = proto_tree_add_item(nwp_tree, hf_nwp_ann_hids, tvb,
118
0
    NWPH_HWAD + ha_len, hid_count * NWP_XID_LEN, ENC_NA);
119
0
  hid_tree = proto_item_add_subtree(ti, ett_nwp_ann_hid_tree);
120
121
0
  buf = wmem_strbuf_new_sized(pinfo->pool, NWP_HID_STR_LEN);
122
123
  /* Add HIDs. */
124
0
  offset = NWPH_HWAD + ha_len;
125
0
  for (i = 0; i < hid_count; i++) {
126
0
    const char *hid_str;
127
128
0
    wmem_strbuf_append(buf, "hid-");
129
0
    add_hid_to_strbuf(tvb, buf, offset);
130
0
    hid_str = wmem_strbuf_get_str(buf);
131
132
0
    proto_tree_add_string_format(hid_tree, hf_nwp_ann_hid, tvb,
133
0
      offset, NWP_XID_LEN, hid_str, "%s", hid_str);
134
0
    wmem_strbuf_truncate(buf, 0);
135
136
0
    offset += NWP_XID_LEN;
137
0
  }
138
0
}
139
140
/* Neighbor list is of the form:
141
 *      HID_1 NUM_1 HA_11 HA_12 ... HA_1NUM_1
142
 *      HID_2 NUM_2 HA_21 HA_22 ... HA_2NUM_2
143
 *      ...
144
 *      HID_count NUM_count HA_count1 HA_count2 ... HA_countNUM_count
145
 *
146
 *      count == hid_count.
147
 */
148
static void
149
dissect_nwp_nl(tvbuff_t *tvb, packet_info* pinfo, proto_tree *nwp_tree, uint8_t hid_count,
150
  uint8_t ha_len)
151
36
{
152
36
  proto_tree *neigh_list_tree = NULL;
153
36
  proto_tree *neigh_tree = NULL;
154
36
  proto_item *pi = NULL;
155
156
36
  unsigned i;
157
36
  int   offset = NWPH_NLST;
158
159
36
  wmem_strbuf_t *hid_buf = wmem_strbuf_new_sized(pinfo->pool,
160
36
    NWP_HID_STR_LEN);
161
162
  /* Set up tree for neighbor list. */
163
36
  pi = proto_tree_add_item(nwp_tree, hf_nwp_neigh_list,
164
36
    tvb, NWPH_NLST, -1, ENC_NA);
165
36
  neigh_list_tree = proto_item_add_subtree(pi, ett_nwp_neigh_list_tree);
166
167
370
  for (i = 0; i < hid_count; i++) {
168
334
    const char *hid_str;
169
334
    unsigned j;
170
334
    uint8_t ha_count = tvb_get_uint8(tvb, offset + NWP_XID_LEN);
171
172
    /* Set up tree for this individual neighbor. */
173
334
    pi = proto_tree_add_none_format(neigh_list_tree, hf_nwp_neigh,
174
334
      tvb, offset, NWP_XID_LEN + 1 + ha_len * ha_count,
175
334
      "Neighbor %d", i + 1);
176
334
    neigh_tree = proto_item_add_subtree(pi, ett_nwp_neigh_tree);
177
178
    /* Add HID for this neighbor. */
179
334
    wmem_strbuf_append(hid_buf, "hid-");
180
334
    add_hid_to_strbuf(tvb, hid_buf, offset);
181
334
    hid_str = wmem_strbuf_get_str(hid_buf);
182
334
    proto_tree_add_string(neigh_tree, hf_nwp_neigh_hid, tvb,
183
334
      offset, NWP_XID_LEN, hid_str);
184
334
    wmem_strbuf_truncate(hid_buf, 0);
185
334
    offset += NWP_XID_LEN;
186
187
    /* Add number of devices this neighbor has. */
188
334
    proto_tree_add_item(neigh_tree, hf_nwp_neigh_num, tvb,
189
334
      offset, 1, ENC_BIG_ENDIAN);
190
334
    offset++;
191
192
    /* Add hardware addresses for the neighbor's devices. */
193
29.1k
    for (j = 0; j < ha_count; j++)
194
28.7k
      proto_tree_add_item(neigh_tree, hf_nwp_neigh_haddr,
195
28.7k
        tvb, offset + (j * ha_len), ha_len, ENC_NA);
196
197
334
    offset += (ha_len * ha_count);
198
334
  }
199
36
}
200
201
static int
202
dissect_nwp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
203
  void *data _U_)
204
39
{
205
39
  proto_tree *nwp_tree = NULL;
206
207
39
  proto_item *ti = NULL;
208
39
  proto_item *type_ti = NULL;
209
210
39
  const char *type_str;
211
39
  uint8_t type, hid_count, ha_len;
212
213
39
  if (tvb_reported_length(tvb) < NWPH_MIN_LEN)
214
1
    return 0;
215
216
38
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "NWP");
217
218
38
  col_clear(pinfo->cinfo, COL_INFO);
219
38
  type = tvb_get_uint8(tvb, NWPH_TYPE);
220
38
  type_str = val_to_str(pinfo->pool, type, nwp_type_vals,
221
38
    "Unknown NWP packet type (0x%02x)");
222
38
  col_add_str(pinfo->cinfo, COL_INFO, type_str);
223
224
  /* Construct protocol tree. */
225
38
  ti = proto_tree_add_item(tree, proto_nwp, tvb, 0, -1, ENC_NA);
226
38
  nwp_tree = proto_item_add_subtree(ti, ett_nwp_tree);
227
228
  /* Add NWP version. */
229
38
  proto_tree_add_item(nwp_tree, hf_nwp_version, tvb,
230
38
    NWPH_VERS, 1, ENC_BIG_ENDIAN);
231
232
  /* Add NWP type. */
233
38
  type_ti = proto_tree_add_item(nwp_tree, hf_nwp_type, tvb,
234
38
    NWPH_TYPE, 1, ENC_BIG_ENDIAN);
235
38
  if (!try_val_to_str(type, nwp_type_vals))
236
2
    expert_add_info_format(pinfo, type_ti, &ei_nwp_bad_type,
237
2
      "%s", type_str);
238
239
  /* Get # of HIDs represented in this packet to use later and add it. */
240
38
  hid_count = tvb_get_uint8(tvb, NWPH_HIDC);
241
38
  proto_tree_add_item(nwp_tree, hf_nwp_hid_count, tvb,
242
38
    NWPH_HIDC, 1, ENC_BIG_ENDIAN);
243
244
  /* Get hardware address length to use later and add it. */
245
38
  ha_len = tvb_get_uint8(tvb, NWPH_HLEN);
246
38
  proto_tree_add_item(nwp_tree, hf_nwp_haddr_len, tvb,
247
38
    NWPH_HLEN, 1, ENC_BIG_ENDIAN);
248
249
38
  switch (type) {
250
0
  case NWP_TYPE_ANNOUNCEMENT:
251
0
    dissect_nwp_ann(tvb, pinfo, nwp_tree, hid_count, ha_len);
252
0
    break;
253
36
  case NWP_TYPE_NEIGH_LIST:
254
36
    dissect_nwp_nl(tvb, pinfo, nwp_tree, hid_count, ha_len);
255
36
    break;
256
2
  default:
257
2
    break;
258
38
  }
259
260
3
  return tvb_captured_length(tvb);
261
38
}
262
263
void
264
proto_register_nwp(void)
265
14
{
266
14
  static hf_register_info hf[] = {
267
268
14
    { &hf_nwp_version,
269
14
    { "Version", "nwp.version", FT_UINT8,
270
14
       BASE_DEC, NULL, 0x0,  NULL, HFILL }},
271
272
14
    { &hf_nwp_type,
273
14
    { "Type", "nwp.type", FT_UINT8,
274
14
       BASE_HEX, VALS(nwp_type_vals), 0x0, NULL, HFILL }},
275
276
14
    { &hf_nwp_hid_count,
277
14
    { "HID Count", "nwp.hid_count", FT_UINT8,
278
14
       BASE_DEC, NULL, 0x0,  NULL, HFILL }},
279
280
14
    { &hf_nwp_haddr_len,
281
14
    { "Hardware Address Length", "nwp.haddr_len", FT_UINT8,
282
14
       BASE_DEC, NULL, 0x0,  NULL, HFILL }},
283
284
14
    { &hf_nwp_ann_haddr,
285
14
    { "Hardware Address", "nwp.ann_haddr", FT_BYTES,
286
14
       SEP_COLON, NULL, 0x0, NULL, HFILL }},
287
288
14
    { &hf_nwp_ann_hids,
289
14
    { "HIDs", "nwp.ann_hids", FT_NONE,
290
14
       BASE_NONE, NULL, 0x0, NULL, HFILL }},
291
292
14
    { &hf_nwp_ann_hid,
293
14
    { "HID", "nwp.ann_hid", FT_STRING,
294
14
       BASE_NONE, NULL, 0x0, NULL, HFILL }},
295
296
14
    { &hf_nwp_neigh_list,
297
14
    { "Neighbor List", "nwp.neigh_list", FT_NONE,
298
14
       BASE_NONE, NULL, 0x0, NULL, HFILL }},
299
300
14
    { &hf_nwp_neigh,
301
14
    { "Neighbor", "nwp.neigh", FT_NONE,
302
14
       BASE_NONE, NULL, 0x0, NULL, HFILL }},
303
304
14
    { &hf_nwp_neigh_hid,
305
14
    { "HID", "nwp.neigh_hid", FT_STRING,
306
14
       BASE_NONE, NULL, 0x0, NULL, HFILL }},
307
308
14
    { &hf_nwp_neigh_num,
309
14
    { "Number of Devices", "nwp.neigh_num", FT_UINT8,
310
14
       BASE_DEC, NULL, 0x0, NULL, HFILL }},
311
312
14
    { &hf_nwp_neigh_haddr,
313
14
    { "Hardware Address", "nwp.neigh_haddr", FT_BYTES,
314
14
       SEP_COLON, NULL, 0x0, NULL, HFILL }}
315
14
  };
316
317
14
  static int *ett[] = {
318
14
    &ett_nwp_tree,
319
14
    &ett_nwp_ann_hid_tree,
320
14
    &ett_nwp_neigh_list_tree,
321
14
    &ett_nwp_neigh_tree
322
14
  };
323
324
14
  static ei_register_info ei[] = {
325
14
    { &ei_nwp_bad_type,
326
14
    { "nwp.bad_type", PI_MALFORMED, PI_ERROR,
327
14
      "Invalid type", EXPFILL }}
328
14
  };
329
330
14
  expert_module_t *expert_nwp;
331
332
14
  proto_nwp = proto_register_protocol("Neighborhood Watch Protocol", "NWP", "nwp");
333
334
14
  nwp_handle = register_dissector("nwp", dissect_nwp, proto_nwp);
335
14
  proto_register_field_array(proto_nwp, hf, array_length(hf));
336
14
  proto_register_subtree_array(ett, array_length(ett));
337
338
14
  expert_nwp = expert_register_protocol(proto_nwp);
339
14
  expert_register_field_array(expert_nwp, ei, array_length(ei));
340
14
}
341
342
void
343
proto_reg_handoff_nwp(void)
344
14
{
345
14
  dissector_add_uint("ethertype", ETHERTYPE_NWP, nwp_handle);
346
14
}
347
348
/*
349
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
350
 *
351
 * Local variables:
352
 * c-basic-offset: 8
353
 * tab-width: 8
354
 * indent-tabs-mode: t
355
 * End:
356
 *
357
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
358
 * :indentSize=8:tabSize=8:noTabs=false:
359
 */