/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 | | */ |