/src/wireshark/epan/dissectors/packet-aarp.c
Line | Count | Source |
1 | | /* packet-aarp.c |
2 | | * Routines for Appletalk ARP packet disassembly |
3 | | * |
4 | | * Simon Wilkinson <sxw@dcs.ed.ac.uk> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | #include "config.h" |
14 | | |
15 | | #include <epan/packet.h> |
16 | | #include <epan/etypes.h> |
17 | | #include <epan/expert.h> |
18 | | #include <epan/to_str.h> |
19 | | |
20 | | /* Forward declarations */ |
21 | | void proto_register_aarp(void); |
22 | | void proto_reg_handoff_aarp(void); |
23 | | |
24 | | static int proto_aarp; |
25 | | static int hf_aarp_hard_type; |
26 | | static int hf_aarp_proto_type; |
27 | | static int hf_aarp_hard_size; |
28 | | static int hf_aarp_proto_size; |
29 | | static int hf_aarp_opcode; |
30 | | static int hf_aarp_src_hw; |
31 | | static int hf_aarp_src_hw_mac; |
32 | | static int hf_aarp_src_proto; |
33 | | static int hf_aarp_src_proto_id; |
34 | | static int hf_aarp_dst_hw; |
35 | | static int hf_aarp_dst_hw_mac; |
36 | | static int hf_aarp_dst_proto; |
37 | | static int hf_aarp_dst_proto_id; |
38 | | |
39 | | static int ett_aarp; |
40 | | |
41 | | static expert_field ei_aarp_length_invalid; |
42 | | |
43 | | #ifndef AARP_REQUEST |
44 | 0 | #define AARP_REQUEST 0x0001 |
45 | | #endif |
46 | | #ifndef AARP_REPLY |
47 | 0 | #define AARP_REPLY 0x0002 |
48 | | #endif |
49 | | #ifndef AARP_PROBE |
50 | 0 | #define AARP_PROBE 0x0003 |
51 | | #endif |
52 | | |
53 | | /* The following is screwed up shit to deal with the fact that |
54 | | the linux kernel edits the packet inline. */ |
55 | 1 | #define AARP_REQUEST_SWAPPED 0x0100 |
56 | 0 | #define AARP_REPLY_SWAPPED 0x0200 |
57 | 0 | #define AARP_PROBE_SWAPPED 0x0300 |
58 | | |
59 | | static const value_string op_vals[] = { |
60 | | {AARP_REQUEST, "request" }, |
61 | | {AARP_REPLY, "reply" }, |
62 | | {AARP_PROBE, "probe" }, |
63 | | {AARP_REQUEST_SWAPPED, "request" }, |
64 | | {AARP_REPLY_SWAPPED, "reply" }, |
65 | | {AARP_PROBE_SWAPPED, "probe" }, |
66 | | {0, NULL } }; |
67 | | |
68 | | /* AARP protocol HARDWARE identifiers. */ |
69 | 32 | #define AARPHRD_ETHER 1 /* Ethernet 10Mbps */ |
70 | 12 | #define AARPHRD_TR 2 /* Token Ring */ |
71 | | |
72 | | static const value_string hrd_vals[] = { |
73 | | {AARPHRD_ETHER, "Ethernet" }, |
74 | | {AARPHRD_TR, "Token Ring" }, |
75 | | {0, NULL } }; |
76 | | |
77 | | /* |
78 | | * Given the hardware address type and length, check whether an address |
79 | | * is an Ethernet address - the address must be of type "Ethernet" or |
80 | | * "Token Ring", and the length must be 6 bytes. |
81 | | */ |
82 | | #define AARP_HW_IS_ETHER(ar_hrd, ar_hln) \ |
83 | 16 | (((ar_hrd) == AARPHRD_ETHER || (ar_hrd) == AARPHRD_TR) \ |
84 | 16 | && (ar_hln) == 6) |
85 | | |
86 | | /* |
87 | | * Given the protocol address type and length, check whether an address |
88 | | * is an Appletalk address - the address must be of type "Appletalk", |
89 | | * and the length must be 4 bytes. |
90 | | */ |
91 | | #define AARP_PRO_IS_ATALK(ar_pro, ar_pln) \ |
92 | 17 | ((ar_pro) == ETHERTYPE_ATALK && (ar_pln) == 4) |
93 | | |
94 | | static char * |
95 | | tvb_atalkid_to_str(wmem_allocator_t *scope, tvbuff_t *tvb, int offset) |
96 | 0 | { |
97 | 0 | int node; |
98 | 0 | char *cur; |
99 | |
|
100 | 0 | cur=(char *)wmem_alloc(scope, 16); |
101 | 0 | node=tvb_get_uint8(tvb, offset+1)<<8|tvb_get_uint8(tvb, offset+2); |
102 | 0 | snprintf(cur, 16, "%d.%d",node,tvb_get_uint8(tvb, offset+3)); |
103 | 0 | return cur; |
104 | 0 | } |
105 | | |
106 | | static const char * |
107 | | tvb_aarphrdaddr_to_str(wmem_allocator_t *scope, tvbuff_t *tvb, int offset, int ad_len, uint16_t type) |
108 | 8 | { |
109 | 8 | if (AARP_HW_IS_ETHER(type, ad_len)) { |
110 | | /* Ethernet address (or Token Ring address, which is the same type |
111 | | of address). */ |
112 | 0 | return tvb_ether_to_str(scope, tvb, offset); |
113 | 0 | } |
114 | 8 | return tvb_bytes_to_str(scope, tvb, offset, ad_len); |
115 | 8 | } |
116 | | |
117 | | static char * |
118 | | tvb_aarpproaddr_to_str(wmem_allocator_t *scope, tvbuff_t *tvb, int offset, int ad_len, uint16_t type) |
119 | 11 | { |
120 | 11 | if (AARP_PRO_IS_ATALK(type, ad_len)) { |
121 | | /* Appletalk address. */ |
122 | 0 | return tvb_atalkid_to_str(scope, tvb, offset); |
123 | 0 | } |
124 | 11 | return tvb_bytes_to_str(scope, tvb, offset, ad_len); |
125 | 11 | } |
126 | | |
127 | | /* Offsets of fields within an AARP packet. */ |
128 | 18 | #define AR_HRD 0 |
129 | 18 | #define AR_PRO 2 |
130 | 18 | #define AR_HLN 4 |
131 | 18 | #define AR_PLN 5 |
132 | 18 | #define AR_OP 6 |
133 | 18 | #define MIN_AARP_HEADER_SIZE 8 |
134 | | |
135 | | static int |
136 | 11 | dissect_aarp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { |
137 | 11 | uint16_t ar_hrd; |
138 | 11 | uint16_t ar_pro; |
139 | 11 | uint8_t ar_hln; |
140 | 11 | uint8_t ar_pln; |
141 | 11 | uint16_t ar_op; |
142 | 11 | proto_tree *aarp_tree; |
143 | 11 | proto_item *ti; |
144 | 11 | const char *op_str; |
145 | 11 | int sha_offset, spa_offset, tha_offset, tpa_offset; |
146 | 11 | const char *sha_str, *spa_str, /* *tha_str, */ *tpa_str; |
147 | | |
148 | 11 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "AARP"); |
149 | 11 | col_clear(pinfo->cinfo, COL_INFO); |
150 | | |
151 | 11 | ar_hrd = tvb_get_ntohs(tvb, AR_HRD); |
152 | 11 | ar_pro = tvb_get_ntohs(tvb, AR_PRO); |
153 | 11 | ar_hln = tvb_get_uint8(tvb, AR_HLN); |
154 | 11 | ar_pln = tvb_get_uint8(tvb, AR_PLN); |
155 | 11 | ar_op = tvb_get_ntohs(tvb, AR_OP); |
156 | | |
157 | | /* Get the offsets of the addresses. */ |
158 | 11 | sha_offset = MIN_AARP_HEADER_SIZE; |
159 | 11 | spa_offset = sha_offset + ar_hln; |
160 | 11 | tha_offset = spa_offset + ar_pln; |
161 | 11 | tpa_offset = tha_offset + ar_hln; |
162 | | |
163 | | /* Extract the addresses. */ |
164 | | |
165 | 11 | if (ar_hln < 1) { |
166 | 3 | expert_add_info_format(pinfo, tree, &ei_aarp_length_invalid, |
167 | 3 | "Invalid hardware address length: %d", ar_hln); |
168 | 3 | sha_str = "Unknown"; |
169 | | #if 0 |
170 | | tha_str = "Unknown"; |
171 | | #endif |
172 | 8 | } else { |
173 | 8 | sha_str = tvb_aarphrdaddr_to_str(pinfo->pool, tvb, sha_offset, ar_hln, ar_hrd); |
174 | | #if 0 |
175 | | /* TODO: tha_str is currently not shown nor parsed */ |
176 | | tha_str = tvb_aarphrdaddr_to_str(pinfo->pool, tvb, tha_offset, ar_hln, ar_hrd); |
177 | | #endif |
178 | 8 | } |
179 | | |
180 | 11 | if (ar_pln < 1) { |
181 | 4 | expert_add_info_format(pinfo, tree, &ei_aarp_length_invalid, |
182 | 4 | "Invalid protocol address length: %d", ar_pln); |
183 | 4 | spa_str = "Unknown"; |
184 | 4 | tpa_str = "Unknown"; |
185 | 7 | } else { |
186 | 7 | spa_str = tvb_aarpproaddr_to_str(pinfo->pool, tvb, spa_offset, ar_pln, ar_pro); |
187 | 7 | tpa_str = tvb_aarpproaddr_to_str(pinfo->pool, tvb, tpa_offset, ar_pln, ar_pro); |
188 | 7 | } |
189 | | |
190 | 11 | switch (ar_op) { |
191 | 0 | case AARP_REQUEST: |
192 | 1 | case AARP_REQUEST_SWAPPED: |
193 | 1 | col_add_fstr(pinfo->cinfo, COL_INFO, "Who has %s? Tell %s", tpa_str, spa_str); |
194 | 1 | break; |
195 | 0 | case AARP_REPLY: |
196 | 0 | case AARP_REPLY_SWAPPED: |
197 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", spa_str, sha_str); |
198 | 0 | break; |
199 | 0 | case AARP_PROBE: |
200 | 0 | case AARP_PROBE_SWAPPED: |
201 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "Is there a %s", tpa_str); |
202 | 0 | break; |
203 | 6 | default: |
204 | 6 | col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown AARP opcode 0x%04x", ar_op); |
205 | 6 | break; |
206 | 11 | } |
207 | | |
208 | 7 | if (tree) { |
209 | 7 | if ((op_str = try_val_to_str(ar_op, op_vals))) |
210 | 1 | ti = proto_tree_add_protocol_format(tree, proto_aarp, tvb, 0, |
211 | 1 | MIN_AARP_HEADER_SIZE + 2*ar_hln + |
212 | 1 | 2*ar_pln, "AppleTalk Address Resolution Protocol (%s)", op_str); |
213 | 6 | else |
214 | 6 | ti = proto_tree_add_protocol_format(tree, proto_aarp, tvb, 0, |
215 | 6 | MIN_AARP_HEADER_SIZE + 2*ar_hln + |
216 | 6 | 2*ar_pln, |
217 | 6 | "AppleTalk Address Resolution Protocol (opcode 0x%04x)", ar_op); |
218 | 7 | aarp_tree = proto_item_add_subtree(ti, ett_aarp); |
219 | 7 | proto_tree_add_uint(aarp_tree, hf_aarp_hard_type, tvb, AR_HRD, 2, |
220 | 7 | ar_hrd); |
221 | 7 | proto_tree_add_uint(aarp_tree, hf_aarp_proto_type, tvb, AR_PRO, 2, |
222 | 7 | ar_pro); |
223 | 7 | proto_tree_add_uint(aarp_tree, hf_aarp_hard_size, tvb, AR_HLN, 1, |
224 | 7 | ar_hln); |
225 | 7 | proto_tree_add_uint(aarp_tree, hf_aarp_proto_size, tvb, AR_PLN, 1, |
226 | 7 | ar_pln); |
227 | 7 | proto_tree_add_uint(aarp_tree, hf_aarp_opcode, tvb, AR_OP, 2, |
228 | 7 | ar_op); |
229 | 7 | if (ar_hln != 0) { |
230 | 4 | proto_tree_add_item(aarp_tree, |
231 | 4 | AARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_aarp_src_hw_mac : hf_aarp_src_hw, |
232 | 4 | tvb, sha_offset, ar_hln, ENC_NA); |
233 | 4 | } |
234 | | |
235 | 7 | if (ar_pln != 0) { |
236 | 3 | if (AARP_PRO_IS_ATALK(ar_pro, ar_pln)) { |
237 | 0 | proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_src_proto_id, tvb, |
238 | 0 | spa_offset, ar_pln, NULL, |
239 | 0 | "%s", spa_str); |
240 | 3 | } else { |
241 | 3 | proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_src_proto, tvb, |
242 | 3 | spa_offset, ar_pln, NULL, |
243 | 3 | "%s", spa_str); |
244 | 3 | } |
245 | 3 | } |
246 | | |
247 | 7 | if (ar_hln != 0) { |
248 | 4 | proto_tree_add_item(aarp_tree, |
249 | 4 | AARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_aarp_dst_hw_mac : hf_aarp_dst_hw, |
250 | 4 | tvb, tha_offset, ar_hln, ENC_NA); |
251 | 4 | } |
252 | | |
253 | 7 | if (ar_pln != 0) { |
254 | 3 | if (AARP_PRO_IS_ATALK(ar_pro, ar_pln)) { |
255 | 0 | proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_dst_proto_id, tvb, |
256 | 0 | tpa_offset, ar_pln, |
257 | 0 | NULL, "%s", tpa_str); |
258 | 3 | } else { |
259 | 3 | proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_dst_proto, tvb, |
260 | 3 | tpa_offset, ar_pln, |
261 | 3 | NULL, "%s", tpa_str); |
262 | 3 | } |
263 | 3 | } |
264 | 7 | } |
265 | 7 | return tvb_captured_length(tvb); |
266 | 11 | } |
267 | | |
268 | | void |
269 | | proto_register_aarp(void) |
270 | 14 | { |
271 | 14 | static hf_register_info hf[] = { |
272 | 14 | { &hf_aarp_hard_type, |
273 | 14 | { "Hardware type", "aarp.hard.type", |
274 | 14 | FT_UINT16, BASE_HEX, VALS(hrd_vals), 0x0, |
275 | 14 | NULL, HFILL }}, |
276 | | |
277 | 14 | { &hf_aarp_proto_type, |
278 | 14 | { "Protocol type", "aarp.proto.type", |
279 | 14 | FT_UINT16, BASE_HEX, VALS(etype_vals), 0x0, |
280 | 14 | NULL, HFILL }}, |
281 | | |
282 | 14 | { &hf_aarp_hard_size, |
283 | 14 | { "Hardware size", "aarp.hard.size", |
284 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
285 | 14 | NULL, HFILL }}, |
286 | | |
287 | 14 | { &hf_aarp_proto_size, |
288 | 14 | { "Protocol size", "aarp.proto.size", |
289 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
290 | 14 | NULL, HFILL }}, |
291 | | |
292 | 14 | { &hf_aarp_opcode, |
293 | 14 | { "Opcode", "aarp.opcode", |
294 | 14 | FT_UINT16, BASE_DEC, VALS(op_vals), 0x0, |
295 | 14 | NULL, HFILL }}, |
296 | | |
297 | 14 | { &hf_aarp_src_hw, |
298 | 14 | { "Sender hardware address", "aarp.src.hw", |
299 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
300 | 14 | NULL, HFILL }}, |
301 | | |
302 | 14 | { &hf_aarp_src_hw_mac, |
303 | 14 | { "Sender MAC address", "aarp.src.hw_mac", |
304 | 14 | FT_ETHER, BASE_NONE, NULL, 0x0, |
305 | 14 | NULL, HFILL }}, |
306 | | |
307 | 14 | { &hf_aarp_src_proto, |
308 | 14 | { "Sender protocol address", "aarp.src.proto", |
309 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
310 | 14 | NULL, HFILL }}, |
311 | | |
312 | 14 | { &hf_aarp_src_proto_id, |
313 | 14 | { "Sender ID", "aarp.src.proto_id", |
314 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
315 | 14 | NULL, HFILL }}, |
316 | | |
317 | 14 | { &hf_aarp_dst_hw, |
318 | 14 | { "Target hardware address", "aarp.dst.hw", |
319 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
320 | 14 | NULL, HFILL }}, |
321 | | |
322 | 14 | { &hf_aarp_dst_hw_mac, |
323 | 14 | { "Target MAC address", "aarp.dst.hw_mac", |
324 | 14 | FT_ETHER, BASE_NONE, NULL, 0x0, |
325 | 14 | NULL, HFILL }}, |
326 | | |
327 | 14 | { &hf_aarp_dst_proto, |
328 | 14 | { "Target protocol address", "aarp.dst.proto", |
329 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
330 | 14 | NULL, HFILL }}, |
331 | | |
332 | 14 | { &hf_aarp_dst_proto_id, |
333 | 14 | { "Target ID", "aarp.dst.proto_id", |
334 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
335 | 14 | NULL, HFILL }}, |
336 | 14 | }; |
337 | 14 | static int *ett[] = { |
338 | 14 | &ett_aarp, |
339 | 14 | }; |
340 | | |
341 | 14 | static ei_register_info ei[] = { |
342 | 14 | { &ei_aarp_length_invalid, { "aarp.length.invalid", PI_PROTOCOL, PI_WARN, "Invalid length", EXPFILL }}, |
343 | 14 | }; |
344 | | |
345 | 14 | proto_aarp = proto_register_protocol("Appletalk Address Resolution Protocol", |
346 | 14 | "AARP", |
347 | 14 | "aarp"); |
348 | 14 | register_dissector("aarp", dissect_aarp, proto_aarp); |
349 | 14 | proto_register_field_array(proto_aarp, hf, array_length(hf)); |
350 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
351 | | |
352 | 14 | expert_module_t* expert_aarp = expert_register_protocol(proto_aarp); |
353 | 14 | expert_register_field_array(expert_aarp, ei, array_length(ei)); |
354 | | |
355 | 14 | } |
356 | | |
357 | | void |
358 | | proto_reg_handoff_aarp(void) |
359 | 14 | { |
360 | 14 | dissector_handle_t aarp_handle = find_dissector("aarp"); |
361 | | |
362 | 14 | dissector_add_uint("ethertype", ETHERTYPE_AARP, aarp_handle); |
363 | 14 | dissector_add_uint("chdlc.protocol", ETHERTYPE_AARP, aarp_handle); |
364 | 14 | } |
365 | | |
366 | | /* |
367 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
368 | | * |
369 | | * Local Variables: |
370 | | * c-basic-offset: 2 |
371 | | * tab-width: 8 |
372 | | * indent-tabs-mode: nil |
373 | | * End: |
374 | | * |
375 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
376 | | * :indentSize=2:tabSize=8:noTabs=true: |
377 | | */ |