/src/wireshark/epan/dissectors/packet-arcnet.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-arcnet.c |
2 | | * Routines for arcnet dissection |
3 | | * Copyright 2001-2002, Peter Fales <ethereal@fales-lorenz.net> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | |
14 | | #include <epan/packet.h> |
15 | | #include <epan/capture_dissectors.h> |
16 | | #include <epan/address_types.h> |
17 | | #include <epan/arcnet_pids.h> |
18 | | #include <epan/to_str.h> |
19 | | #include "packet-ip.h" |
20 | | #include "packet-arp.h" |
21 | | |
22 | | void proto_register_arcnet(void); |
23 | | void proto_reg_handoff_arcnet(void); |
24 | | |
25 | | static dissector_handle_t arcnet_handle; |
26 | | static dissector_handle_t arcnet_linux_handle; |
27 | | static capture_dissector_handle_t arcnet_cap_handle; |
28 | | static capture_dissector_handle_t arcnet_cap_has_ex_handle; |
29 | | |
30 | | /* Initialize the protocol and registered fields */ |
31 | | static int proto_arcnet; |
32 | | static int hf_arcnet_src; |
33 | | static int hf_arcnet_dst; |
34 | | static int hf_arcnet_offset; |
35 | | static int hf_arcnet_protID; |
36 | | static int hf_arcnet_exception_flag; |
37 | | static int hf_arcnet_split_flag; |
38 | | static int hf_arcnet_sequence; |
39 | | static int hf_arcnet_padding; |
40 | | |
41 | | /* Initialize the subtree pointers */ |
42 | | static int ett_arcnet; |
43 | | |
44 | | static int arcnet_address_type = -1; |
45 | | |
46 | | static dissector_table_t arcnet_dissector_table; |
47 | | |
48 | | static capture_dissector_handle_t ip_cap_handle; |
49 | | static capture_dissector_handle_t arp_cap_handle; |
50 | | |
51 | | /* Cache protocol for packet counting */ |
52 | | static int proto_ipx; |
53 | | |
54 | | static int arcnet_str_len(const address* addr _U_) |
55 | 8 | { |
56 | 8 | return 5; |
57 | 8 | } |
58 | | |
59 | | static int arcnet_to_str(const address* addr, char *buf, int buf_len _U_) |
60 | 4 | { |
61 | 4 | *buf++ = '0'; |
62 | 4 | *buf++ = 'x'; |
63 | 4 | buf = bytes_to_hexstr(buf, (const uint8_t *)addr->data, 1); |
64 | 4 | *buf = '\0'; /* NULL terminate */ |
65 | | |
66 | 4 | return arcnet_str_len(addr); |
67 | 4 | } |
68 | | |
69 | | static const char* arcnet_col_filter_str(const address* addr _U_, bool is_src) |
70 | 0 | { |
71 | 0 | if (is_src) |
72 | 0 | return "arcnet.src"; |
73 | | |
74 | 0 | return "arcnet.dst"; |
75 | 0 | } |
76 | | |
77 | | static int arcnet_len(void) |
78 | 0 | { |
79 | 0 | return 1; |
80 | 0 | } |
81 | | |
82 | | static bool |
83 | | capture_arcnet_common(const unsigned char *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header, bool has_exception) |
84 | 0 | { |
85 | 0 | if (!BYTES_ARE_IN_FRAME(offset, len, 1)) { |
86 | 0 | return false; |
87 | 0 | } |
88 | | |
89 | 0 | switch (pd[offset]) { |
90 | | |
91 | 0 | case ARCNET_PROTO_IP_1051: |
92 | | /* No fragmentation stuff in the header */ |
93 | 0 | return call_capture_dissector(ip_cap_handle, pd, offset + 1, len, cpinfo, pseudo_header); |
94 | | |
95 | 0 | case ARCNET_PROTO_IP_1201: |
96 | | /* |
97 | | * There's fragmentation stuff in the header. |
98 | | * |
99 | | * XXX - on at least some versions of NetBSD, it appears that we |
100 | | * might we get ARCNET frames, not reassembled packets; we should |
101 | | * perhaps bump "counts->other" for all but the first frame of a packet. |
102 | | * |
103 | | * XXX - but on FreeBSD it appears that we get reassembled packets |
104 | | * on input (but apparently we get frames on output - or maybe |
105 | | * we get the packet *and* all its frames!); how to tell the |
106 | | * difference? It looks from the FreeBSD reassembly code as if |
107 | | * the reassembled packet arrives with the header for the first |
108 | | * frame. It also looks as if, on output, we first get the |
109 | | * full packet, with a header containing none of the fragmentation |
110 | | * stuff, and then get the frames. |
111 | | * |
112 | | * On Linux, we get only reassembled packets, and the exception |
113 | | * frame stuff is hidden - there's a split flag and sequence |
114 | | * number, but it appears that it will never have the exception |
115 | | * frame stuff. |
116 | | * |
117 | | * XXX - what about OpenBSD? And, for that matter, what about |
118 | | * Windows? (I suspect Windows supplies reassembled frames, |
119 | | * as WinPcap, like PF_PACKET sockets, taps into the networking |
120 | | * stack just as other protocols do.) |
121 | | */ |
122 | 0 | offset++; |
123 | 0 | if (!BYTES_ARE_IN_FRAME(offset, len, 1)) { |
124 | 0 | return false; |
125 | 0 | } |
126 | 0 | if (has_exception && pd[offset] == 0xff) { |
127 | | /* This is an exception packet. The flag value there is the |
128 | | "this is an exception flag" packet; the next two bytes |
129 | | after it are padding, and another copy of the packet |
130 | | type appears after the padding. */ |
131 | 0 | offset += 4; |
132 | 0 | } |
133 | 0 | return call_capture_dissector(ip_cap_handle, pd, offset + 3, len, cpinfo, pseudo_header); |
134 | | |
135 | 0 | case ARCNET_PROTO_ARP_1051: |
136 | 0 | case ARCNET_PROTO_ARP_1201: |
137 | | /* |
138 | | * XXX - do we have to worry about fragmentation for ARP? |
139 | | */ |
140 | 0 | return call_capture_dissector(arp_cap_handle, pd, offset + 1, len, cpinfo, pseudo_header); |
141 | | |
142 | 0 | case ARCNET_PROTO_IPX: |
143 | 0 | capture_dissector_increment_count(cpinfo, proto_ipx); |
144 | 0 | break; |
145 | | |
146 | 0 | default: |
147 | 0 | return false; |
148 | 0 | } |
149 | | |
150 | 0 | return true; |
151 | 0 | } |
152 | | |
153 | | static bool |
154 | | capture_arcnet (const unsigned char *pd, int offset _U_, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header) |
155 | 0 | { |
156 | 0 | return capture_arcnet_common(pd, 4, len, cpinfo, pseudo_header, false); |
157 | 0 | } |
158 | | |
159 | | static bool |
160 | | capture_arcnet_has_exception(const unsigned char *pd, int offset _U_, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header) |
161 | 0 | { |
162 | 0 | return capture_arcnet_common(pd, 2, len, cpinfo, pseudo_header, true); |
163 | 0 | } |
164 | | |
165 | | static void |
166 | | dissect_arcnet_common (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, |
167 | | bool has_offset, bool has_exception) |
168 | 4 | { |
169 | 4 | int offset = 0; |
170 | 4 | uint8_t dst, src, protID, split_flag; |
171 | 4 | tvbuff_t *next_tvb; |
172 | 4 | proto_item *ti; |
173 | 4 | proto_tree *arcnet_tree; |
174 | | |
175 | 4 | col_set_str (pinfo->cinfo, COL_PROTOCOL, "ARCNET"); |
176 | | |
177 | 4 | col_set_str(pinfo->cinfo, COL_INFO, "ARCNET"); |
178 | | |
179 | 4 | src = tvb_get_uint8 (tvb, 0); |
180 | 4 | dst = tvb_get_uint8 (tvb, 1); |
181 | 4 | set_address_tvb(&pinfo->dl_src, arcnet_address_type, 1, tvb, 0); |
182 | 4 | copy_address_shallow(&pinfo->src, &pinfo->dl_src); |
183 | 4 | set_address_tvb(&pinfo->dl_dst, arcnet_address_type, 1, tvb, 1); |
184 | 4 | copy_address_shallow(&pinfo->dst, &pinfo->dl_dst); |
185 | | |
186 | 4 | ti = proto_tree_add_item (tree, proto_arcnet, tvb, 0, -1, ENC_NA); |
187 | | |
188 | 4 | arcnet_tree = proto_item_add_subtree (ti, ett_arcnet); |
189 | | |
190 | 4 | proto_tree_add_uint (arcnet_tree, hf_arcnet_src, tvb, offset, 1, src); |
191 | 4 | offset++; |
192 | | |
193 | 4 | proto_tree_add_uint (arcnet_tree, hf_arcnet_dst, tvb, offset, 1, dst); |
194 | 4 | offset++; |
195 | | |
196 | 4 | if (has_offset) { |
197 | 1 | proto_tree_add_item (arcnet_tree, hf_arcnet_offset, tvb, offset, 2, ENC_NA); |
198 | 1 | offset += 2; |
199 | 1 | } |
200 | | |
201 | 4 | protID = tvb_get_uint8 (tvb, offset); |
202 | 4 | proto_tree_add_uint (arcnet_tree, hf_arcnet_protID, tvb, offset, 1, protID); |
203 | 4 | offset++; |
204 | | |
205 | 4 | switch (protID) { |
206 | | |
207 | 0 | case ARCNET_PROTO_IP_1051: |
208 | 0 | case ARCNET_PROTO_ARP_1051: |
209 | 0 | case ARCNET_PROTO_DIAGNOSE: |
210 | 0 | case ARCNET_PROTO_BACNET: /* XXX - no fragmentation? */ |
211 | | /* No fragmentation stuff in the header */ |
212 | 0 | break; |
213 | | |
214 | 4 | default: |
215 | | /* |
216 | | * Show the fragmentation stuff - flag and sequence ID. |
217 | | * |
218 | | * XXX - on at least some versions of NetBSD, it appears that |
219 | | * we might get ARCNET frames, not reassembled packets; if so, |
220 | | * we should reassemble them. |
221 | | * |
222 | | * XXX - but on FreeBSD it appears that we get reassembled packets |
223 | | * on input (but apparently we get frames on output - or maybe |
224 | | * we get the packet *and* all its frames!); how to tell the |
225 | | * difference? It looks from the FreeBSD reassembly code as if |
226 | | * the reassembled packet arrives with the header for the first |
227 | | * frame. It also looks as if, on output, we first get the |
228 | | * full packet, with a header containing none of the fragmentation |
229 | | * stuff, and then get the frames. |
230 | | * |
231 | | * On Linux, we get only reassembled packets, and the exception |
232 | | * frame stuff is hidden - there's a split flag and sequence |
233 | | * number, but it appears that it will never have the exception |
234 | | * frame stuff. |
235 | | * |
236 | | * XXX - what about OpenBSD? And, for that matter, what about |
237 | | * Windows? (I suspect Windows supplies reassembled frames, |
238 | | * as WinPcap, like PF_PACKET sockets, taps into the networking |
239 | | * stack just as other protocols do.) |
240 | | */ |
241 | 4 | split_flag = tvb_get_uint8 (tvb, offset); |
242 | 4 | if (has_exception && split_flag == 0xff) { |
243 | | /* This is an exception packet. The flag value there is the |
244 | | "this is an exception flag" packet; the next two bytes |
245 | | after it are padding. */ |
246 | 1 | proto_tree_add_uint (arcnet_tree, hf_arcnet_exception_flag, tvb, offset, 1, |
247 | 1 | split_flag); |
248 | 1 | offset++; |
249 | | |
250 | 1 | proto_tree_add_item(arcnet_tree, hf_arcnet_padding, tvb, offset, 2, ENC_BIG_ENDIAN); |
251 | 1 | offset += 2; |
252 | | |
253 | | /* Another copy of the packet type appears after the padding. */ |
254 | 1 | proto_tree_add_item (arcnet_tree, hf_arcnet_protID, tvb, offset, 1, ENC_BIG_ENDIAN); |
255 | 1 | offset++; |
256 | | |
257 | | /* And after that comes the real split flag. */ |
258 | 1 | split_flag = tvb_get_uint8 (tvb, offset); |
259 | 1 | } |
260 | | |
261 | 4 | proto_tree_add_uint (arcnet_tree, hf_arcnet_split_flag, tvb, offset, 1, |
262 | 4 | split_flag); |
263 | 4 | offset++; |
264 | | |
265 | 4 | proto_tree_add_item (arcnet_tree, hf_arcnet_sequence, tvb, offset, 2, ENC_BIG_ENDIAN); |
266 | 4 | offset += 2; |
267 | | |
268 | 4 | break; |
269 | 4 | } |
270 | | |
271 | | /* Set the length of the ARCNET header protocol tree item. */ |
272 | 4 | proto_item_set_len(ti, offset); |
273 | | |
274 | 4 | next_tvb = tvb_new_subset_remaining (tvb, offset); |
275 | | |
276 | 4 | if (!dissector_try_uint (arcnet_dissector_table, protID, |
277 | 4 | next_tvb, pinfo, tree)) |
278 | 2 | { |
279 | 2 | col_add_fstr (pinfo->cinfo, COL_PROTOCOL, "0x%04x", protID); |
280 | 2 | call_data_dissector(next_tvb, pinfo, tree); |
281 | 2 | } |
282 | | |
283 | 4 | } |
284 | | |
285 | | /* |
286 | | * BSD-style ARCNET headers - they don't have the offset field from the |
287 | | * ARCNET hardware packet, but we might get an exception frame header. |
288 | | */ |
289 | | static int |
290 | | dissect_arcnet (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* data _U_) |
291 | 3 | { |
292 | 3 | dissect_arcnet_common (tvb, pinfo, tree, false, true); |
293 | 3 | return tvb_captured_length(tvb); |
294 | 3 | } |
295 | | |
296 | | /* |
297 | | * Linux-style ARCNET headers - they *do* have the offset field from the |
298 | | * ARCNET hardware packet, but we should never see an exception frame |
299 | | * header. |
300 | | */ |
301 | | static int |
302 | | dissect_arcnet_linux (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* data _U_) |
303 | 1 | { |
304 | 1 | dissect_arcnet_common (tvb, pinfo, tree, true, false); |
305 | 1 | return tvb_captured_length(tvb); |
306 | 1 | } |
307 | | |
308 | | static const value_string arcnet_prot_id_vals[] = { |
309 | | {ARCNET_PROTO_IP_1051, "RFC 1051 IP"}, |
310 | | {ARCNET_PROTO_ARP_1051, "RFC 1051 ARP"}, |
311 | | {ARCNET_PROTO_IP_1201, "RFC 1201 IP"}, |
312 | | {ARCNET_PROTO_ARP_1201, "RFC 1201 ARP"}, |
313 | | {ARCNET_PROTO_RARP_1201, "RFC 1201 RARP"}, |
314 | | {ARCNET_PROTO_IPX, "IPX"}, |
315 | | {ARCNET_PROTO_NOVELL_EC, "Novell of some sort"}, |
316 | | {ARCNET_PROTO_IPv6, "IPv6"}, |
317 | | {ARCNET_PROTO_ETHERNET, "Encapsulated Ethernet"}, |
318 | | {ARCNET_PROTO_DATAPOINT_BOOT, "Datapoint boot"}, |
319 | | {ARCNET_PROTO_DATAPOINT_MOUNT, "Datapoint mount"}, |
320 | | {ARCNET_PROTO_POWERLAN_BEACON, "PowerLAN beacon"}, |
321 | | {ARCNET_PROTO_POWERLAN_BEACON2, "PowerLAN beacon2"}, |
322 | | {ARCNET_PROTO_APPLETALK, "Appletalk"}, |
323 | | {ARCNET_PROTO_BANYAN, "Banyan VINES"}, |
324 | | {ARCNET_PROTO_DIAGNOSE, "Diagnose"}, |
325 | | {ARCNET_PROTO_BACNET, "BACnet"}, |
326 | | {0, NULL} |
327 | | }; |
328 | | |
329 | | void |
330 | | proto_register_arcnet (void) |
331 | 14 | { |
332 | | |
333 | | /* Setup list of header fields See Section 1.6.1 for details*/ |
334 | 14 | static hf_register_info hf[] = { |
335 | 14 | {&hf_arcnet_src, |
336 | 14 | {"Source", "arcnet.src", |
337 | 14 | FT_UINT8, BASE_HEX, NULL, 0, |
338 | 14 | "Source ID", HFILL} |
339 | 14 | }, |
340 | 14 | {&hf_arcnet_dst, |
341 | 14 | {"Dest", "arcnet.dst", |
342 | 14 | FT_UINT8, BASE_HEX, NULL, 0, |
343 | 14 | "Dest ID", HFILL} |
344 | 14 | }, |
345 | 14 | {&hf_arcnet_offset, |
346 | 14 | {"Offset", "arcnet.offset", |
347 | 14 | FT_BYTES, BASE_NONE, NULL, 0, |
348 | 14 | NULL, HFILL} |
349 | 14 | }, |
350 | 14 | {&hf_arcnet_protID, |
351 | 14 | {"Protocol ID", "arcnet.protID", |
352 | 14 | FT_UINT8, BASE_HEX, VALS(arcnet_prot_id_vals), 0, |
353 | 14 | "Proto type", HFILL} |
354 | 14 | }, |
355 | 14 | {&hf_arcnet_split_flag, |
356 | 14 | {"Split Flag", "arcnet.split_flag", |
357 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
358 | 14 | NULL, HFILL} |
359 | 14 | }, |
360 | 14 | {&hf_arcnet_exception_flag, |
361 | 14 | {"Exception Flag", "arcnet.exception_flag", |
362 | 14 | FT_UINT8, BASE_HEX, NULL, 0, |
363 | 14 | NULL, HFILL} |
364 | 14 | }, |
365 | 14 | {&hf_arcnet_sequence, |
366 | 14 | {"Sequence", "arcnet.sequence", |
367 | 14 | FT_UINT16, BASE_DEC, NULL, 0, |
368 | 14 | "Sequence number", HFILL} |
369 | 14 | }, |
370 | 14 | {&hf_arcnet_padding, |
371 | 14 | {"Padding", "arcnet.padding", |
372 | 14 | FT_UINT16, BASE_HEX, NULL, 0, |
373 | 14 | NULL, HFILL} |
374 | 14 | }, |
375 | 14 | }; |
376 | | |
377 | | /* Setup protocol subtree array */ |
378 | 14 | static int *ett[] = { |
379 | 14 | &ett_arcnet, |
380 | 14 | }; |
381 | | |
382 | | /* Register the protocol name and description */ |
383 | 14 | proto_arcnet = proto_register_protocol ("ARCNET", "ARCNET", "arcnet"); |
384 | | |
385 | | /* Required function calls to register the header fields and subtrees used */ |
386 | 14 | proto_register_field_array (proto_arcnet, hf, array_length (hf)); |
387 | 14 | proto_register_subtree_array (ett, array_length (ett)); |
388 | | |
389 | 14 | arcnet_dissector_table = register_dissector_table ("arcnet.protocol_id", "ARCNET Protocol ID", |
390 | 14 | proto_arcnet, FT_UINT8, BASE_HEX); |
391 | | |
392 | 14 | arcnet_address_type = address_type_dissector_register("AT_ARCNET", "ARCNET Address", arcnet_to_str, arcnet_str_len, NULL, arcnet_col_filter_str, arcnet_len, NULL, NULL); |
393 | | |
394 | 14 | arcnet_handle = register_dissector("arcnet", dissect_arcnet, proto_arcnet); |
395 | 14 | arcnet_linux_handle = register_dissector("arcnet_linux", dissect_arcnet_linux, proto_arcnet); |
396 | | |
397 | 14 | arcnet_cap_handle = register_capture_dissector("arcnet_linux", capture_arcnet, proto_arcnet); |
398 | 14 | arcnet_cap_has_ex_handle = register_capture_dissector("arcnet", capture_arcnet_has_exception, proto_arcnet); |
399 | 14 | } |
400 | | |
401 | | |
402 | | void |
403 | | proto_reg_handoff_arcnet (void) |
404 | 14 | { |
405 | 14 | dissector_add_uint ("wtap_encap", WTAP_ENCAP_ARCNET, arcnet_handle); |
406 | 14 | dissector_add_uint ("wtap_encap", WTAP_ENCAP_ARCNET_LINUX, arcnet_linux_handle); |
407 | | |
408 | 14 | proto_ipx = proto_get_id_by_filter_name("ipx"); |
409 | | |
410 | 14 | capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_ARCNET_LINUX, arcnet_cap_handle); |
411 | 14 | capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_ARCNET, arcnet_cap_has_ex_handle); |
412 | | |
413 | 14 | ip_cap_handle = find_capture_dissector("ip"); |
414 | 14 | arp_cap_handle = find_capture_dissector("arp"); |
415 | 14 | } |
416 | | |
417 | | /* |
418 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
419 | | * |
420 | | * Local Variables: |
421 | | * c-basic-offset: 2 |
422 | | * tab-width: 8 |
423 | | * indent-tabs-mode: nil |
424 | | * End: |
425 | | * |
426 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
427 | | * :indentSize=2:tabSize=8:noTabs=true: |
428 | | */ |