Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-chdlc.c
Line
Count
Source
1
/* packet-chdlc.c
2
 * Routines for Cisco HDLC packet disassembly
3
 *
4
 * Wireshark - Network traffic analyzer
5
 * By Gerald Combs <gerald@wireshark.org>
6
 * Copyright 1998 Gerald Combs
7
 *
8
 * SPDX-License-Identifier: GPL-2.0-or-later
9
 */
10
11
#include "config.h"
12
13
#include <epan/packet.h>
14
#include <epan/capture_dissectors.h>
15
#include <wsutil/pint.h>
16
#include <epan/etypes.h>
17
#include <epan/prefs.h>
18
#include <epan/addr_resolv.h>
19
#include <epan/expert.h>
20
#include "packet-chdlc.h"
21
#include "packet-ppp.h"
22
#include "packet-ip.h"
23
#include "packet-juniper.h"
24
#include "packet-l2tp.h"
25
#include "packet-osi.h"
26
27
/*
28
 * See section 4.3.1 of RFC 1547, and
29
 *
30
 *    http://www.nethelp.no/net/cisco-hdlc.txt
31
 */
32
33
void proto_register_chdlc(void);
34
void proto_reg_handoff_chdlc(void);
35
void proto_register_slarp(void);
36
void proto_reg_handoff_slarp(void);
37
38
static int proto_chdlc;
39
static int hf_chdlc_addr;
40
static int hf_chdlc_control;
41
static int hf_chdlc_proto;
42
static int hf_chdlc_clns_padding;
43
44
static int ett_chdlc;
45
46
static int proto_slarp;
47
static int hf_slarp_ptype;
48
static int hf_slarp_address;
49
static int hf_slarp_netmask;
50
static int hf_slarp_mysequence;
51
static int hf_slarp_yoursequence;
52
static int hf_slarp_reliability;
53
54
static expert_field ei_slarp_reliability;
55
static int ett_slarp;
56
57
/*
58
 * Protocol types for the Cisco HDLC format.
59
 *
60
 * As per the above, according to RFC 1547, these are "standard 16 bit
61
 * Ethernet protocol type code[s]", but 0x8035 is Reverse ARP, and
62
 * that is (at least according to the Linux ISDN code) not the
63
 * same as Cisco SLARP.
64
 *
65
 * In addition, 0x2000 is apparently the Cisco Discovery Protocol, but
66
 * on Ethernet those are encapsulated inside SNAP with an OUI of
67
 * OUI_CISCO, not OUI_ENCAP_ETHER.
68
 *
69
 * We thus have a separate dissector table for Cisco HDLC types.
70
 * We could perhaps have that table hold only type values that
71
 * wouldn't be in the Ethernet dissector table, and check that
72
 * table first and the Ethernet dissector table if that fails.
73
 */
74
16
#define CISCO_SLARP     0x8035  /* Cisco SLARP protocol */
75
76
static dissector_table_t subdissector_table;
77
78
static dissector_handle_t chdlc_handle;
79
80
static capture_dissector_handle_t ip_cap_handle;
81
82
static const value_string chdlc_address_vals[] = {
83
  {CHDLC_ADDR_UNICAST,   "Unicast"},
84
  {CHDLC_ADDR_MULTICAST, "Multicast"},
85
  {0,                    NULL}
86
};
87
88
const value_string chdlc_vals[] = {
89
  {0x2000,               "Cisco Discovery Protocol"},
90
  {ETHERTYPE_IP,         "IP"},
91
  {ETHERTYPE_IPv6,       "IPv6"},
92
  {CISCO_SLARP,          "SLARP"},
93
  {ETHERTYPE_DEC_LB,     "DEC LanBridge"},
94
  {CHDLCTYPE_BPDU,       "Spanning Tree BPDU"},
95
  {ETHERTYPE_ATALK,      "Appletalk"},
96
  {ETHERTYPE_AARP,       "AARP"},
97
  {ETHERTYPE_IPX,        "Netware IPX/SPX"},
98
  {ETHERTYPE_ETHBRIDGE,  "Transparent Ethernet bridging" },
99
  {CHDLCTYPE_OSI,        "OSI" },
100
  {ETHERTYPE_MPLS,       "MPLS unicast"},
101
  {ETHERTYPE_MPLS_MULTI, "MPLS multicast"},
102
  {0,                     NULL}
103
};
104
105
static bool
106
0
capture_chdlc( const unsigned char *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header) {
107
0
  if (!BYTES_ARE_IN_FRAME(offset, len, 4))
108
0
    return false;
109
110
0
  switch (pntohu16(&pd[offset + 2])) {
111
0
    case ETHERTYPE_IP:
112
0
      return call_capture_dissector(ip_cap_handle, pd, offset + 4, len, cpinfo, pseudo_header);
113
0
  }
114
115
0
  return false;
116
0
}
117
118
void
119
chdlctype(dissector_handle_t sub_dissector, uint16_t chdlc_type,
120
          tvbuff_t *tvb, int offset_after_chdlctype,
121
          packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree,
122
          int chdlctype_id)
123
0
{
124
0
  tvbuff_t *next_tvb;
125
0
  int       padbyte;
126
127
0
  proto_tree_add_uint(fh_tree, chdlctype_id, tvb,
128
0
                        offset_after_chdlctype - 2, 2, chdlc_type);
129
130
  /* Only CLNS protocols can have a padding byte */
131
0
  padbyte = chdlc_type == CHDLCTYPE_OSI ? tvb_get_uint8(tvb, offset_after_chdlctype) : 0;
132
0
  if (chdlc_type == CHDLCTYPE_OSI &&
133
0
    !( padbyte == NLPID_ISO8473_CLNP || /* older Juniper SW does not send a padbyte */
134
0
       padbyte == NLPID_ISO9542_ESIS ||
135
0
       padbyte == NLPID_ISO10589_ISIS)) {
136
    /* There is a Padding Byte for CLNS protocols over Cisco HDLC */
137
0
    proto_tree_add_item(fh_tree, hf_chdlc_clns_padding, tvb, offset_after_chdlctype, 1, ENC_BIG_ENDIAN);
138
0
    next_tvb = tvb_new_subset_remaining(tvb, offset_after_chdlctype + 1);
139
0
  } else {
140
0
    next_tvb = tvb_new_subset_remaining(tvb, offset_after_chdlctype);
141
0
  }
142
143
  /* dissect with the handle; if there's no handle, it's just data */
144
0
  if (sub_dissector != NULL) {
145
0
    call_dissector(sub_dissector, next_tvb, pinfo, tree);
146
0
  } else {
147
0
    col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "0x%04x", chdlc_type);
148
0
    call_data_dissector(next_tvb, pinfo, tree);
149
0
  }
150
0
}
151
152
static int chdlc_fcs_decode; /* 0 = No FCS, 1 = 16 bit FCS, 2 = 32 bit FCS */
153
154
static int
155
dissect_chdlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
156
0
{
157
0
  proto_item *ti;
158
0
  proto_tree *fh_tree = NULL;
159
0
  uint16_t    proto;
160
0
  dissector_handle_t sub_dissector;
161
162
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "CHDLC");
163
0
  col_clear(pinfo->cinfo, COL_INFO);
164
165
0
  switch (pinfo->p2p_dir) {
166
167
0
  case P2P_DIR_SENT:
168
0
    col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DTE");
169
0
    col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DCE");
170
0
    break;
171
172
0
  case P2P_DIR_RECV:
173
0
    col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DCE");
174
0
    col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DTE");
175
0
    break;
176
177
0
  default:
178
0
    col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "N/A");
179
0
    col_set_str(pinfo->cinfo, COL_RES_DL_DST, "N/A");
180
0
    break;
181
0
  }
182
183
0
  proto = tvb_get_ntohs(tvb, 2);
184
185
0
  if (tree) {
186
0
    ti = proto_tree_add_item(tree, proto_chdlc, tvb, 0, 4, ENC_NA);
187
0
    fh_tree = proto_item_add_subtree(ti, ett_chdlc);
188
189
0
    proto_tree_add_item(fh_tree, hf_chdlc_addr, tvb, 0, 1, ENC_NA);
190
0
    proto_tree_add_item(fh_tree, hf_chdlc_control, tvb, 1, 1, ENC_NA);
191
0
  }
192
193
0
  decode_fcs(tvb, pinfo, fh_tree, chdlc_fcs_decode, 2);
194
195
0
  sub_dissector = dissector_get_uint_handle(subdissector_table, proto);
196
0
  chdlctype(sub_dissector, proto, tvb, 4, pinfo, tree, fh_tree, hf_chdlc_proto);
197
0
  return tvb_captured_length(tvb);
198
0
}
199
200
void
201
proto_register_chdlc(void)
202
16
{
203
16
  static hf_register_info hf[] = {
204
16
    { &hf_chdlc_addr,
205
16
      { "Address", "chdlc.address", FT_UINT8, BASE_HEX,
206
16
        VALS(chdlc_address_vals), 0x0, NULL, HFILL }},
207
16
    { &hf_chdlc_control,
208
16
      { "Control", "chdlc.control", FT_UINT8, BASE_HEX,
209
16
        NULL, 0x0, NULL, HFILL }},
210
16
    { &hf_chdlc_proto,
211
16
      { "Protocol", "chdlc.protocol", FT_UINT16, BASE_HEX,
212
16
        VALS(chdlc_vals), 0x0, NULL, HFILL }},
213
16
    { &hf_chdlc_clns_padding,
214
16
      { "CLNS Padding", "chdlc.clns_padding", FT_UINT8, BASE_HEX,
215
16
        NULL, 0x0, NULL, HFILL }},
216
16
  };
217
218
16
  static int *ett[] = {
219
16
    &ett_chdlc,
220
16
  };
221
222
16
  module_t *chdlc_module;
223
224
16
  proto_chdlc = proto_register_protocol("Cisco HDLC", "CHDLC", "chdlc");
225
16
  proto_register_field_array(proto_chdlc, hf, array_length(hf));
226
16
  proto_register_subtree_array(ett, array_length(ett));
227
228
  /* subdissector code */
229
16
  subdissector_table = register_dissector_table("chdlc.protocol",
230
16
                                                "Cisco HDLC protocol", proto_chdlc,
231
16
                                                FT_UINT16, BASE_HEX);
232
233
16
  chdlc_handle = register_dissector("chdlc", dissect_chdlc, proto_chdlc);
234
235
  /* Register the preferences for the chdlc protocol */
236
16
  chdlc_module = prefs_register_protocol(proto_chdlc, NULL);
237
238
16
  prefs_register_enum_preference(chdlc_module,
239
16
        "fcs_type",
240
16
        "CHDLC Frame Checksum Type",
241
16
        "The type of CHDLC frame checksum (none, 16-bit, 32-bit)",
242
16
        &chdlc_fcs_decode,
243
16
        fcs_options, ENC_BIG_ENDIAN);
244
245
16
  register_capture_dissector("chdlc", capture_chdlc, proto_chdlc);
246
247
16
}
248
249
void
250
proto_reg_handoff_chdlc(void)
251
16
{
252
16
  capture_dissector_handle_t chdlc_cap_handle;
253
254
16
  dissector_add_uint("wtap_encap", WTAP_ENCAP_CHDLC, chdlc_handle);
255
16
  dissector_add_uint("wtap_encap", WTAP_ENCAP_CHDLC_WITH_PHDR, chdlc_handle);
256
16
  dissector_add_uint("juniper.proto", JUNIPER_PROTO_CHDLC, chdlc_handle);
257
16
  dissector_add_uint("l2tp.pw_type", L2TPv3_PW_CHDLC, chdlc_handle);
258
259
16
  chdlc_cap_handle = find_capture_dissector("chdlc");
260
16
  capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_CHDLC, chdlc_cap_handle);
261
262
16
  ip_cap_handle = find_capture_dissector("ip");
263
16
}
264
265
266
267
268
0
#define SLARP_REQUEST   0
269
0
#define SLARP_REPLY     1
270
0
#define SLARP_LINECHECK 2
271
272
static const value_string slarp_ptype_vals[] = {
273
  {SLARP_REQUEST,   "Request"},
274
  {SLARP_REPLY,     "Reply"},
275
  {SLARP_LINECHECK, "Line keepalive"},
276
  {0,               NULL}
277
};
278
279
static int
280
dissect_slarp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
281
0
{
282
0
  proto_item *ti;
283
0
  proto_tree *slarp_tree;
284
0
  uint32_t    code;
285
0
  uint32_t    addr;
286
0
  uint32_t    mysequence;
287
0
  uint32_t    yoursequence;
288
0
  proto_item* reliability_item;
289
290
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "SLARP");
291
0
  col_clear(pinfo->cinfo, COL_INFO);
292
293
0
  code = tvb_get_ntohl(tvb, 0);
294
295
0
  ti = proto_tree_add_item(tree, proto_slarp, tvb, 0, 14, ENC_NA);
296
0
  slarp_tree = proto_item_add_subtree(ti, ett_slarp);
297
298
0
  switch (code) {
299
300
0
  case SLARP_REQUEST:
301
0
  case SLARP_REPLY:
302
0
    addr = tvb_get_ipv4(tvb, 4);
303
0
    col_add_fstr(pinfo->cinfo, COL_INFO, "%s, from %s, mask %s",
304
0
                     val_to_str(pinfo->pool, code, slarp_ptype_vals, "Unknown (%d)"),
305
0
                     get_hostname(addr), tvb_ip_to_str(pinfo->pool, tvb, 8));
306
0
    if (tree) {
307
0
      proto_tree_add_uint(slarp_tree, hf_slarp_ptype, tvb, 0, 4, code);
308
0
      proto_tree_add_item(slarp_tree, hf_slarp_address, tvb, 4, 4, ENC_BIG_ENDIAN);
309
0
      proto_tree_add_item(slarp_tree, hf_slarp_netmask, tvb, 8, 4, ENC_BIG_ENDIAN);
310
0
    }
311
0
    break;
312
313
0
  case SLARP_LINECHECK:
314
0
    mysequence = tvb_get_ntohl(tvb, 4);
315
0
    yoursequence = tvb_get_ntohl(tvb, 8);
316
0
        col_add_fstr(pinfo->cinfo, COL_INFO,
317
0
                     "%s, outgoing sequence %u, returned sequence %u",
318
0
                     val_to_str(pinfo->pool, code, slarp_ptype_vals, "Unknown (%d)"),
319
0
                     mysequence, yoursequence);
320
321
0
    proto_tree_add_uint(slarp_tree, hf_slarp_ptype, tvb, 0, 4, code);
322
0
    proto_tree_add_uint(slarp_tree, hf_slarp_mysequence, tvb, 4, 4,
323
0
                          mysequence);
324
0
    proto_tree_add_uint(slarp_tree, hf_slarp_yoursequence, tvb, 8, 4,
325
0
                          yoursequence);
326
0
    reliability_item = proto_tree_add_item(slarp_tree, hf_slarp_reliability, tvb,
327
0
        12, 2, ENC_BIG_ENDIAN);
328
0
    if (tvb_get_ntohs(tvb, 12) != 0xFFFF) {
329
0
        expert_add_info(pinfo, reliability_item, &ei_slarp_reliability);
330
0
    }
331
0
    break;
332
333
0
  default:
334
0
    col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown packet type 0x%08X", code);
335
336
0
    proto_tree_add_uint(slarp_tree, hf_slarp_ptype, tvb, 0, 4, code);
337
0
    call_data_dissector(tvb_new_subset_remaining(tvb, 4), pinfo, slarp_tree);
338
0
    break;
339
0
  }
340
0
  return tvb_captured_length(tvb);
341
0
}
342
343
void
344
proto_register_slarp(void)
345
16
{
346
16
  expert_module_t* expert_slarp;
347
348
16
  static hf_register_info hf[] = {
349
16
    { &hf_slarp_ptype,
350
16
      { "Packet type", "slarp.ptype", FT_UINT32, BASE_DEC,
351
16
        VALS(slarp_ptype_vals), 0x0, NULL, HFILL }},
352
16
    { &hf_slarp_address,
353
16
      { "Address", "slarp.address", FT_IPv4, BASE_NONE,
354
16
        NULL, 0x0, NULL, HFILL }},
355
    /* XXX - need an FT_ for netmasks, which is like FT_IPV4 but doesn't
356
       get translated to a host name. */
357
16
    { &hf_slarp_netmask,
358
16
      { "Netmask", "slarp.netmask", FT_IPv4, BASE_NETMASK,
359
16
        NULL, 0x0, NULL, HFILL }},
360
16
    { &hf_slarp_mysequence,
361
16
      { "Outgoing sequence number", "slarp.mysequence", FT_UINT32, BASE_DEC,
362
16
        NULL, 0x0, NULL, HFILL }},
363
16
    { &hf_slarp_yoursequence,
364
16
      { "Returned sequence number", "slarp.yoursequence", FT_UINT32, BASE_DEC,
365
16
        NULL, 0x0, NULL, HFILL }},
366
16
    { &hf_slarp_reliability,
367
16
      { "Reliability", "slarp.reliability", FT_UINT16, BASE_HEX,
368
16
        NULL, 0x0, NULL, HFILL }},
369
16
  };
370
16
  static int *ett[] = {
371
16
    &ett_slarp,
372
16
  };
373
374
16
  static ei_register_info ei[] = {
375
16
    { &ei_slarp_reliability, { "slarp.reliability.invalid", PI_MALFORMED, PI_ERROR,
376
16
      "Reliability must be 0xFFFF", EXPFILL }}
377
16
  };
378
379
16
  proto_slarp = proto_register_protocol("Cisco SLARP", "SLARP", "slarp");
380
16
  register_dissector("slarp", dissect_slarp, proto_slarp);
381
16
  proto_register_field_array(proto_slarp, hf, array_length(hf));
382
16
  proto_register_subtree_array(ett, array_length(ett));
383
384
16
  expert_slarp = expert_register_protocol(proto_slarp);
385
16
  expert_register_field_array(expert_slarp, ei, array_length(ei));
386
16
}
387
388
void
389
proto_reg_handoff_slarp(void)
390
16
{
391
16
  dissector_add_uint("chdlc.protocol", CISCO_SLARP, find_dissector("slarp"));
392
16
}
393
394
/*
395
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
396
 *
397
 * Local Variables:
398
 * c-basic-offset: 2
399
 * tab-width: 8
400
 * indent-tabs-mode: nil
401
 * End:
402
 *
403
 * ex: set shiftwidth=2 tabstop=8 expandtab:
404
 * :indentSize=2:tabSize=8:noTabs=true:
405
 */