Coverage Report

Created: 2026-08-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
0
#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
20
#define AARPHRD_ETHER   1               /* Ethernet 10Mbps              */
70
10
#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
10
        (((ar_hrd) == AARPHRD_ETHER || (ar_hrd) == AARPHRD_TR) \
84
10
                                && (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
15
        ((ar_pro) == ETHERTYPE_ATALK && (ar_pln) == 4)
93
94
static char *
95
tvb_atalkid_to_str(wmem_allocator_t *scope, tvbuff_t *tvb, unsigned offset)
96
0
{
97
0
  unsigned 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, "%u.%u", 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, unsigned offset, unsigned ad_len, uint16_t type)
108
6
{
109
6
  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
6
  return tvb_bytes_to_str(scope, tvb, offset, ad_len);
115
6
}
116
117
static char *
118
tvb_aarpproaddr_to_str(wmem_allocator_t *scope, tvbuff_t *tvb, unsigned offset, unsigned 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
14
#define AR_HRD          0
129
14
#define AR_PRO          2
130
14
#define AR_HLN          4
131
14
#define AR_PLN          5
132
14
#define AR_OP           6
133
14
#define MIN_AARP_HEADER_SIZE    8
134
135
static int
136
10
dissect_aarp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) {
137
10
  uint16_t    ar_hrd;
138
10
  uint16_t    ar_pro;
139
10
  uint8_t     ar_hln;
140
10
  uint8_t     ar_pln;
141
10
  uint16_t    ar_op;
142
10
  proto_tree  *aarp_tree;
143
10
  proto_item  *ti;
144
10
  const char *op_str;
145
10
  unsigned    sha_offset, spa_offset, tha_offset, tpa_offset;
146
10
  const char *sha_str, *spa_str, /* *tha_str, */ *tpa_str;
147
148
10
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "AARP");
149
10
  col_clear(pinfo->cinfo, COL_INFO);
150
151
10
  ar_hrd = tvb_get_ntohs(tvb, AR_HRD);
152
10
  ar_pro = tvb_get_ntohs(tvb, AR_PRO);
153
10
  ar_hln = tvb_get_uint8(tvb, AR_HLN);
154
10
  ar_pln = tvb_get_uint8(tvb, AR_PLN);
155
10
  ar_op  = tvb_get_ntohs(tvb, AR_OP);
156
157
  /* Get the offsets of the addresses. */
158
10
  sha_offset = MIN_AARP_HEADER_SIZE;
159
10
  spa_offset = sha_offset + ar_hln;
160
10
  tha_offset = spa_offset + ar_pln;
161
10
  tpa_offset = tha_offset + ar_hln;
162
163
  /* Extract the addresses.  */
164
165
10
  if (ar_hln < 1) {
166
4
    expert_add_info_format(pinfo, tree, &ei_aarp_length_invalid,
167
4
      "Invalid hardware address length: %d", ar_hln);
168
4
    sha_str = "Unknown";
169
#if 0
170
    tha_str = "Unknown";
171
#endif
172
6
  } else {
173
6
    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
6
  }
179
180
10
  if (ar_pln < 1) {
181
2
    expert_add_info_format(pinfo, tree, &ei_aarp_length_invalid,
182
2
      "Invalid protocol address length: %d", ar_pln);
183
2
    spa_str = "Unknown";
184
2
    tpa_str = "Unknown";
185
8
  } else {
186
8
    spa_str = tvb_aarpproaddr_to_str(pinfo->pool, tvb, spa_offset, ar_pln, ar_pro);
187
8
    tpa_str = tvb_aarpproaddr_to_str(pinfo->pool, tvb, tpa_offset, ar_pln, ar_pro);
188
8
  }
189
190
10
  switch (ar_op) {
191
0
    case AARP_REQUEST:
192
0
    case AARP_REQUEST_SWAPPED:
193
0
      col_add_fstr(pinfo->cinfo, COL_INFO, "Who has %s?  Tell %s", tpa_str, spa_str);
194
0
      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
4
    default:
204
4
      col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown AARP opcode 0x%04x", ar_op);
205
4
      break;
206
10
  }
207
208
4
  if (tree) {
209
4
    if ((op_str = try_val_to_str(ar_op, op_vals)))
210
0
      ti = proto_tree_add_protocol_format(tree, proto_aarp, tvb, 0,
211
0
                                      MIN_AARP_HEADER_SIZE + 2*ar_hln +
212
0
                                      2*ar_pln, "AppleTalk Address Resolution Protocol (%s)", op_str);
213
4
    else
214
4
      ti = proto_tree_add_protocol_format(tree, proto_aarp, tvb, 0,
215
4
                                      MIN_AARP_HEADER_SIZE + 2*ar_hln +
216
4
                                      2*ar_pln,
217
4
                                      "AppleTalk Address Resolution Protocol (opcode 0x%04x)", ar_op);
218
4
    aarp_tree = proto_item_add_subtree(ti, ett_aarp);
219
4
    proto_tree_add_uint(aarp_tree, hf_aarp_hard_type, tvb, AR_HRD, 2,
220
4
                               ar_hrd);
221
4
    proto_tree_add_uint(aarp_tree, hf_aarp_proto_type, tvb, AR_PRO, 2,
222
4
                               ar_pro);
223
4
    proto_tree_add_uint(aarp_tree, hf_aarp_hard_size, tvb, AR_HLN, 1,
224
4
                               ar_hln);
225
4
    proto_tree_add_uint(aarp_tree, hf_aarp_proto_size, tvb, AR_PLN, 1,
226
4
                               ar_pln);
227
4
    proto_tree_add_uint(aarp_tree, hf_aarp_opcode, tvb, AR_OP, 2,
228
4
                               ar_op);
229
4
    if (ar_hln != 0) {
230
2
      proto_tree_add_item(aarp_tree,
231
2
        AARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_aarp_src_hw_mac : hf_aarp_src_hw,
232
2
        tvb, sha_offset, ar_hln, ENC_NA);
233
2
    }
234
235
4
    if (ar_pln != 0) {
236
2
      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
2
      } else {
241
2
        proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_src_proto, tvb,
242
2
                                          spa_offset, ar_pln, NULL,
243
2
                                          "%s", spa_str);
244
2
      }
245
2
    }
246
247
4
    if (ar_hln != 0) {
248
2
      proto_tree_add_item(aarp_tree,
249
2
        AARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_aarp_dst_hw_mac : hf_aarp_dst_hw,
250
2
        tvb, tha_offset, ar_hln, ENC_NA);
251
2
    }
252
253
4
    if (ar_pln != 0) {
254
2
      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
2
      } else {
259
2
        proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_dst_proto, tvb,
260
2
                                          tpa_offset, ar_pln,
261
2
                                          NULL, "%s", tpa_str);
262
2
      }
263
2
    }
264
4
  }
265
4
  return tvb_captured_length(tvb);
266
10
}
267
268
void
269
proto_register_aarp(void)
270
16
{
271
16
  static hf_register_info hf[] = {
272
16
    { &hf_aarp_hard_type,
273
16
      { "Hardware type",                "aarp.hard.type",
274
16
        FT_UINT16,      BASE_HEX,       VALS(hrd_vals), 0x0,
275
16
        NULL, HFILL }},
276
277
16
    { &hf_aarp_proto_type,
278
16
      { "Protocol type",                "aarp.proto.type",
279
16
        FT_UINT16,      BASE_HEX,       VALS(etype_vals),       0x0,
280
16
        NULL, HFILL }},
281
282
16
    { &hf_aarp_hard_size,
283
16
      { "Hardware size",                "aarp.hard.size",
284
16
        FT_UINT8,       BASE_DEC,       NULL,   0x0,
285
16
        NULL, HFILL }},
286
287
16
    { &hf_aarp_proto_size,
288
16
      { "Protocol size",                "aarp.proto.size",
289
16
        FT_UINT8,       BASE_DEC,       NULL,   0x0,
290
16
        NULL, HFILL }},
291
292
16
    { &hf_aarp_opcode,
293
16
      { "Opcode",                       "aarp.opcode",
294
16
        FT_UINT16,      BASE_DEC,       VALS(op_vals),  0x0,
295
16
        NULL, HFILL }},
296
297
16
    { &hf_aarp_src_hw,
298
16
      { "Sender hardware address",      "aarp.src.hw",
299
16
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
300
16
        NULL, HFILL }},
301
302
16
    { &hf_aarp_src_hw_mac,
303
16
      { "Sender MAC address",           "aarp.src.hw_mac",
304
16
        FT_ETHER,       BASE_NONE,      NULL,   0x0,
305
16
        NULL, HFILL }},
306
307
16
    { &hf_aarp_src_proto,
308
16
      { "Sender protocol address",      "aarp.src.proto",
309
16
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
310
16
        NULL, HFILL }},
311
312
16
    { &hf_aarp_src_proto_id,
313
16
      { "Sender ID",                    "aarp.src.proto_id",
314
16
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
315
16
        NULL, HFILL }},
316
317
16
    { &hf_aarp_dst_hw,
318
16
      { "Target hardware address",      "aarp.dst.hw",
319
16
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
320
16
        NULL, HFILL }},
321
322
16
    { &hf_aarp_dst_hw_mac,
323
16
      { "Target MAC address",           "aarp.dst.hw_mac",
324
16
        FT_ETHER,       BASE_NONE,      NULL,   0x0,
325
16
        NULL, HFILL }},
326
327
16
    { &hf_aarp_dst_proto,
328
16
      { "Target protocol address",      "aarp.dst.proto",
329
16
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
330
16
      NULL, HFILL }},
331
332
16
    { &hf_aarp_dst_proto_id,
333
16
      { "Target ID",                    "aarp.dst.proto_id",
334
16
        FT_BYTES,       BASE_NONE,      NULL,   0x0,
335
16
        NULL, HFILL }},
336
16
  };
337
16
  static int *ett[] = {
338
16
    &ett_aarp,
339
16
  };
340
341
16
  static ei_register_info ei[] = {
342
16
    { &ei_aarp_length_invalid, { "aarp.length.invalid", PI_PROTOCOL, PI_WARN, "Invalid length", EXPFILL }},
343
16
  };
344
345
16
  proto_aarp = proto_register_protocol("Appletalk Address Resolution Protocol",
346
16
                                       "AARP",
347
16
                                       "aarp");
348
16
  register_dissector("aarp", dissect_aarp, proto_aarp);
349
16
  proto_register_field_array(proto_aarp, hf, array_length(hf));
350
16
  proto_register_subtree_array(ett, array_length(ett));
351
352
16
  expert_module_t* expert_aarp = expert_register_protocol(proto_aarp);
353
16
  expert_register_field_array(expert_aarp, ei, array_length(ei));
354
355
16
}
356
357
void
358
proto_reg_handoff_aarp(void)
359
16
{
360
16
  dissector_handle_t aarp_handle = find_dissector("aarp");
361
362
16
  dissector_add_uint("ethertype", ETHERTYPE_AARP, aarp_handle);
363
16
  dissector_add_uint("chdlc.protocol", ETHERTYPE_AARP, aarp_handle);
364
16
}
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
 */