2 * Routines for NWP dissection
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
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.
18 #include <epan/packet.h>
19 #include <epan/expert.h>
21 void proto_register_nwp(void);
22 void proto_reg_handoff_nwp(void);
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
;
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
;
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
;
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
;
49 static expert_field ei_nwp_bad_type
;
51 static dissector_handle_t nwp_handle
;
53 #define NWP_XID_CHUNK_LEN 4
54 #define NWP_XID_LEN 20
55 /* Two characters for every byte + 4 for "hid-" + 1 for "\0" */
56 #define NWP_HID_STR_LEN ((NWP_XID_LEN * 2) + 5)
58 /* Room for a string of hardware addresses of the form:
60 * XX:...:XX; XX:...:XX; ...
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
66 #define NWP_HADDRS_STR_LEN(LEN, COUNT) (((2 * LEN) + (LEN - 1) + 2) * COUNT)
68 #define NWPH_MIN_LEN 4
69 #define ETHERTYPE_NWP 0xC0DF
70 #define NWP_VERSION 0x01
72 #define NWP_TYPE_ANNOUNCEMENT 0x01
73 #define NWP_TYPE_NEIGH_LIST 0x02
75 /* Offsets of fields in NWP Announcements/Neighbor Lists. */
84 static const value_string nwp_type_vals
[] = {
85 { NWP_TYPE_ANNOUNCEMENT
, "NWP Announcement" },
86 { NWP_TYPE_NEIGH_LIST
, "NWP Neighbor List" },
91 add_hid_to_strbuf(tvbuff_t
*tvb
, wmem_strbuf_t
*hid_buf
, int offset
)
94 for (i
= 0; i
< NWP_XID_LEN
/ NWP_XID_CHUNK_LEN
; i
++) {
95 wmem_strbuf_append_printf(hid_buf
, "%08x",
96 tvb_get_ntohl(tvb
, offset
));
97 offset
+= NWP_XID_CHUNK_LEN
;
102 dissect_nwp_ann(tvbuff_t
*tvb
, proto_tree
*nwp_tree
, uint8_t hid_count
,
105 proto_tree
*hid_tree
= NULL
;
106 proto_item
*ti
= NULL
;
112 /* Add hardware address. */
113 proto_tree_add_item(nwp_tree
, hf_nwp_ann_haddr
, tvb
, NWPH_HWAD
,
116 /* Add tree for HIDs. */
117 ti
= proto_tree_add_item(nwp_tree
, hf_nwp_ann_hids
, tvb
,
118 NWPH_HWAD
+ ha_len
, hid_count
* NWP_XID_LEN
, ENC_NA
);
119 hid_tree
= proto_item_add_subtree(ti
, ett_nwp_ann_hid_tree
);
121 buf
= wmem_strbuf_new_sized(wmem_packet_scope(), NWP_HID_STR_LEN
);
124 offset
= NWPH_HWAD
+ ha_len
;
125 for (i
= 0; i
< hid_count
; i
++) {
128 wmem_strbuf_append(buf
, "hid-");
129 add_hid_to_strbuf(tvb
, buf
, offset
);
130 hid_str
= wmem_strbuf_get_str(buf
);
132 proto_tree_add_string_format(hid_tree
, hf_nwp_ann_hid
, tvb
,
133 offset
, NWP_XID_LEN
, hid_str
, "%s", hid_str
);
134 wmem_strbuf_truncate(buf
, 0);
136 offset
+= NWP_XID_LEN
;
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
144 * HID_count NUM_count HA_count1 HA_count2 ... HA_countNUM_count
146 * count == hid_count.
149 dissect_nwp_nl(tvbuff_t
*tvb
, proto_tree
*nwp_tree
, uint8_t hid_count
,
152 proto_tree
*neigh_list_tree
= NULL
;
153 proto_tree
*neigh_tree
= NULL
;
154 proto_item
*pi
= NULL
;
157 int offset
= NWPH_NLST
;
159 wmem_strbuf_t
*hid_buf
= wmem_strbuf_new_sized(wmem_packet_scope(),
162 /* Set up tree for neighbor list. */
163 pi
= proto_tree_add_item(nwp_tree
, hf_nwp_neigh_list
,
164 tvb
, NWPH_NLST
, -1, ENC_NA
);
165 neigh_list_tree
= proto_item_add_subtree(pi
, ett_nwp_neigh_list_tree
);
167 for (i
= 0; i
< hid_count
; i
++) {
170 uint8_t ha_count
= tvb_get_uint8(tvb
, offset
+ NWP_XID_LEN
);
172 /* Set up tree for this individual neighbor. */
173 pi
= proto_tree_add_none_format(neigh_list_tree
, hf_nwp_neigh
,
174 tvb
, offset
, NWP_XID_LEN
+ 1 + ha_len
* ha_count
,
175 "Neighbor %d", i
+ 1);
176 neigh_tree
= proto_item_add_subtree(pi
, ett_nwp_neigh_tree
);
178 /* Add HID for this neighbor. */
179 wmem_strbuf_append(hid_buf
, "hid-");
180 add_hid_to_strbuf(tvb
, hid_buf
, offset
);
181 hid_str
= wmem_strbuf_get_str(hid_buf
);
182 proto_tree_add_string(neigh_tree
, hf_nwp_neigh_hid
, tvb
,
183 offset
, NWP_XID_LEN
, hid_str
);
184 wmem_strbuf_truncate(hid_buf
, 0);
185 offset
+= NWP_XID_LEN
;
187 /* Add number of devices this neighbor has. */
188 proto_tree_add_item(neigh_tree
, hf_nwp_neigh_num
, tvb
,
189 offset
, 1, ENC_BIG_ENDIAN
);
192 /* Add hardware addresses for the neighbor's devices. */
193 for (j
= 0; j
< ha_count
; j
++)
194 proto_tree_add_item(neigh_tree
, hf_nwp_neigh_haddr
,
195 tvb
, offset
+ (j
* ha_len
), ha_len
, ENC_NA
);
197 offset
+= (ha_len
* ha_count
);
202 dissect_nwp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
205 proto_tree
*nwp_tree
= NULL
;
207 proto_item
*ti
= NULL
;
208 proto_item
*type_ti
= NULL
;
210 const char *type_str
;
211 uint8_t type
, hid_count
, ha_len
;
213 if (tvb_reported_length(tvb
) < NWPH_MIN_LEN
)
216 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "NWP");
218 col_clear(pinfo
->cinfo
, COL_INFO
);
219 type
= tvb_get_uint8(tvb
, NWPH_TYPE
);
220 type_str
= val_to_str(type
, nwp_type_vals
,
221 "Unknown NWP packet type (0x%02x)");
222 col_add_str(pinfo
->cinfo
, COL_INFO
, type_str
);
224 /* Construct protocol tree. */
225 ti
= proto_tree_add_item(tree
, proto_nwp
, tvb
, 0, -1, ENC_NA
);
226 nwp_tree
= proto_item_add_subtree(ti
, ett_nwp_tree
);
228 /* Add NWP version. */
229 proto_tree_add_item(nwp_tree
, hf_nwp_version
, tvb
,
230 NWPH_VERS
, 1, ENC_BIG_ENDIAN
);
233 type_ti
= proto_tree_add_item(nwp_tree
, hf_nwp_type
, tvb
,
234 NWPH_TYPE
, 1, ENC_BIG_ENDIAN
);
235 if (!try_val_to_str(type
, nwp_type_vals
))
236 expert_add_info_format(pinfo
, type_ti
, &ei_nwp_bad_type
,
239 /* Get # of HIDs represented in this packet to use later and add it. */
240 hid_count
= tvb_get_uint8(tvb
, NWPH_HIDC
);
241 proto_tree_add_item(nwp_tree
, hf_nwp_hid_count
, tvb
,
242 NWPH_HIDC
, 1, ENC_BIG_ENDIAN
);
244 /* Get hardware address length to use later and add it. */
245 ha_len
= tvb_get_uint8(tvb
, NWPH_HLEN
);
246 proto_tree_add_item(nwp_tree
, hf_nwp_haddr_len
, tvb
,
247 NWPH_HLEN
, 1, ENC_BIG_ENDIAN
);
250 case NWP_TYPE_ANNOUNCEMENT
:
251 dissect_nwp_ann(tvb
, nwp_tree
, hid_count
, ha_len
);
253 case NWP_TYPE_NEIGH_LIST
:
254 dissect_nwp_nl(tvb
, nwp_tree
, hid_count
, ha_len
);
260 return tvb_captured_length(tvb
);
264 proto_register_nwp(void)
266 static hf_register_info hf
[] = {
269 { "Version", "nwp.version", FT_UINT8
,
270 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
273 { "Type", "nwp.type", FT_UINT8
,
274 BASE_HEX
, VALS(nwp_type_vals
), 0x0, NULL
, HFILL
}},
277 { "HID Count", "nwp.hid_count", FT_UINT8
,
278 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
281 { "Hardware Address Length", "nwp.haddr_len", FT_UINT8
,
282 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
285 { "Hardware Address", "nwp.ann_haddr", FT_BYTES
,
286 SEP_COLON
, NULL
, 0x0, NULL
, HFILL
}},
289 { "HIDs", "nwp.ann_hids", FT_NONE
,
290 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
293 { "HID", "nwp.ann_hid", FT_STRING
,
294 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
296 { &hf_nwp_neigh_list
,
297 { "Neighbor List", "nwp.neigh_list", FT_NONE
,
298 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
301 { "Neighbor", "nwp.neigh", FT_NONE
,
302 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
305 { "HID", "nwp.neigh_hid", FT_STRING
,
306 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
309 { "Number of Devices", "nwp.neigh_num", FT_UINT8
,
310 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
312 { &hf_nwp_neigh_haddr
,
313 { "Hardware Address", "nwp.neigh_haddr", FT_BYTES
,
314 SEP_COLON
, NULL
, 0x0, NULL
, HFILL
}}
317 static int *ett
[] = {
319 &ett_nwp_ann_hid_tree
,
320 &ett_nwp_neigh_list_tree
,
324 static ei_register_info ei
[] = {
326 { "nwp.bad_type", PI_MALFORMED
, PI_ERROR
,
327 "Invalid type", EXPFILL
}}
330 expert_module_t
*expert_nwp
;
332 proto_nwp
= proto_register_protocol("Neighborhood Watch Protocol", "NWP", "nwp");
334 nwp_handle
= register_dissector("nwp", dissect_nwp
, proto_nwp
);
335 proto_register_field_array(proto_nwp
, hf
, array_length(hf
));
336 proto_register_subtree_array(ett
, array_length(ett
));
338 expert_nwp
= expert_register_protocol(proto_nwp
);
339 expert_register_field_array(expert_nwp
, ei
, array_length(ei
));
343 proto_reg_handoff_nwp(void)
345 dissector_add_uint("ethertype", ETHERTYPE_NWP
, nwp_handle
);
349 * Editor modelines - https://www.wireshark.org/tools/modelines.html
354 * indent-tabs-mode: t
357 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
358 * :indentSize=8:tabSize=8:noTabs=false: