Coverage Report

Created: 2026-01-02 06:13

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