2 * Routines for Cisco HDLC packet disassembly
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
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/chdlctypes.h>
19 #include <epan/nlpid.h>
20 #include <epan/addr_resolv.h>
21 #include "packet-chdlc.h"
22 #include "packet-ppp.h"
23 #include "packet-ip.h"
24 #include "packet-juniper.h"
25 #include "packet-l2tp.h"
26 #include <epan/expert.h>
29 * See section 4.3.1 of RFC 1547, and
31 * http://www.nethelp.no/net/cisco-hdlc.txt
34 void proto_register_chdlc(void);
35 void proto_reg_handoff_chdlc(void);
36 void proto_register_slarp(void);
37 void proto_reg_handoff_slarp(void);
39 static int proto_chdlc
;
40 static int hf_chdlc_addr
;
41 static int hf_chdlc_control
;
42 static int hf_chdlc_proto
;
43 static int hf_chdlc_clns_padding
;
47 static int proto_slarp
;
48 static int hf_slarp_ptype
;
49 static int hf_slarp_address
;
50 static int hf_slarp_netmask
;
51 static int hf_slarp_mysequence
;
52 static int hf_slarp_yoursequence
;
53 static int hf_slarp_reliability
;
55 static expert_field ei_slarp_reliability
;
59 * Protocol types for the Cisco HDLC format.
61 * As per the above, according to RFC 1547, these are "standard 16 bit
62 * Ethernet protocol type code[s]", but 0x8035 is Reverse ARP, and
63 * that is (at least according to the Linux ISDN code) not the
64 * same as Cisco SLARP.
66 * In addition, 0x2000 is apparently the Cisco Discovery Protocol, but
67 * on Ethernet those are encapsulated inside SNAP with an OUI of
68 * OUI_CISCO, not OUI_ENCAP_ETHER.
70 * We thus have a separate dissector table for Cisco HDLC types.
71 * We could perhaps have that table hold only type values that
72 * wouldn't be in the Ethernet dissector table, and check that
73 * table first and the Ethernet dissector table if that fails.
75 #define CISCO_SLARP 0x8035 /* Cisco SLARP protocol */
77 static dissector_table_t subdissector_table
;
79 static dissector_handle_t chdlc_handle
;
81 static capture_dissector_handle_t ip_cap_handle
;
83 static const value_string chdlc_address_vals
[] = {
84 {CHDLC_ADDR_UNICAST
, "Unicast"},
85 {CHDLC_ADDR_MULTICAST
, "Multicast"},
89 const value_string chdlc_vals
[] = {
90 {0x2000, "Cisco Discovery Protocol"},
92 {ETHERTYPE_IPv6
, "IPv6"},
93 {CISCO_SLARP
, "SLARP"},
94 {ETHERTYPE_DEC_LB
, "DEC LanBridge"},
95 {CHDLCTYPE_BPDU
, "Spanning Tree BPDU"},
96 {ETHERTYPE_ATALK
, "Appletalk"},
97 {ETHERTYPE_AARP
, "AARP"},
98 {ETHERTYPE_IPX
, "Netware IPX/SPX"},
99 {ETHERTYPE_ETHBRIDGE
, "Transparent Ethernet bridging" },
100 {CHDLCTYPE_OSI
, "OSI" },
101 {ETHERTYPE_MPLS
, "MPLS unicast"},
102 {ETHERTYPE_MPLS_MULTI
, "MPLS multicast"},
107 capture_chdlc( const unsigned char *pd
, int offset
, int len
, capture_packet_info_t
*cpinfo
, const union wtap_pseudo_header
*pseudo_header
) {
108 if (!BYTES_ARE_IN_FRAME(offset
, len
, 4))
111 switch (pntoh16(&pd
[offset
+ 2])) {
113 return call_capture_dissector(ip_cap_handle
, pd
, offset
+ 4, len
, cpinfo
, pseudo_header
);
120 chdlctype(dissector_handle_t sub_dissector
, uint16_t chdlc_type
,
121 tvbuff_t
*tvb
, int offset_after_chdlctype
,
122 packet_info
*pinfo
, proto_tree
*tree
, proto_tree
*fh_tree
,
128 proto_tree_add_uint(fh_tree
, chdlctype_id
, tvb
,
129 offset_after_chdlctype
- 2, 2, chdlc_type
);
131 padbyte
= tvb_get_uint8(tvb
, offset_after_chdlctype
);
132 if (chdlc_type
== CHDLCTYPE_OSI
&&
133 !( padbyte
== NLPID_ISO8473_CLNP
|| /* older Juniper SW does not send a padbyte */
134 padbyte
== NLPID_ISO9542_ESIS
||
135 padbyte
== NLPID_ISO10589_ISIS
)) {
136 /* There is a Padding Byte for CLNS protocols over Cisco HDLC */
137 proto_tree_add_item(fh_tree
, hf_chdlc_clns_padding
, tvb
, offset_after_chdlctype
, 1, ENC_BIG_ENDIAN
);
138 next_tvb
= tvb_new_subset_remaining(tvb
, offset_after_chdlctype
+ 1);
140 next_tvb
= tvb_new_subset_remaining(tvb
, offset_after_chdlctype
);
143 /* dissect with the handle; if there's no handle, it's just data */
144 if (sub_dissector
!= NULL
) {
145 call_dissector(sub_dissector
, next_tvb
, pinfo
, tree
);
147 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "0x%04x", chdlc_type
);
148 call_data_dissector(next_tvb
, pinfo
, tree
);
152 static int chdlc_fcs_decode
; /* 0 = No FCS, 1 = 16 bit FCS, 2 = 32 bit FCS */
155 dissect_chdlc(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
158 proto_tree
*fh_tree
= NULL
;
160 dissector_handle_t sub_dissector
;
162 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "CHDLC");
163 col_clear(pinfo
->cinfo
, COL_INFO
);
165 switch (pinfo
->p2p_dir
) {
168 col_set_str(pinfo
->cinfo
, COL_RES_DL_SRC
, "DTE");
169 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, "DCE");
173 col_set_str(pinfo
->cinfo
, COL_RES_DL_SRC
, "DCE");
174 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, "DTE");
178 col_set_str(pinfo
->cinfo
, COL_RES_DL_SRC
, "N/A");
179 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, "N/A");
183 proto
= tvb_get_ntohs(tvb
, 2);
186 ti
= proto_tree_add_item(tree
, proto_chdlc
, tvb
, 0, 4, ENC_NA
);
187 fh_tree
= proto_item_add_subtree(ti
, ett_chdlc
);
189 proto_tree_add_item(fh_tree
, hf_chdlc_addr
, tvb
, 0, 1, ENC_NA
);
190 proto_tree_add_item(fh_tree
, hf_chdlc_control
, tvb
, 1, 1, ENC_NA
);
193 decode_fcs(tvb
, pinfo
, fh_tree
, chdlc_fcs_decode
, 2);
195 sub_dissector
= dissector_get_uint_handle(subdissector_table
, proto
);
196 chdlctype(sub_dissector
, proto
, tvb
, 4, pinfo
, tree
, fh_tree
, hf_chdlc_proto
);
197 return tvb_captured_length(tvb
);
201 proto_register_chdlc(void)
203 static hf_register_info hf
[] = {
205 { "Address", "chdlc.address", FT_UINT8
, BASE_HEX
,
206 VALS(chdlc_address_vals
), 0x0, NULL
, HFILL
}},
208 { "Control", "chdlc.control", FT_UINT8
, BASE_HEX
,
209 NULL
, 0x0, NULL
, HFILL
}},
211 { "Protocol", "chdlc.protocol", FT_UINT16
, BASE_HEX
,
212 VALS(chdlc_vals
), 0x0, NULL
, HFILL
}},
213 { &hf_chdlc_clns_padding
,
214 { "CLNS Padding", "chdlc.clns_padding", FT_UINT8
, BASE_HEX
,
215 NULL
, 0x0, NULL
, HFILL
}},
218 static int *ett
[] = {
222 module_t
*chdlc_module
;
224 proto_chdlc
= proto_register_protocol("Cisco HDLC", "CHDLC", "chdlc");
225 proto_register_field_array(proto_chdlc
, hf
, array_length(hf
));
226 proto_register_subtree_array(ett
, array_length(ett
));
228 /* subdissector code */
229 subdissector_table
= register_dissector_table("chdlc.protocol",
230 "Cisco HDLC protocol", proto_chdlc
,
231 FT_UINT16
, BASE_HEX
);
233 chdlc_handle
= register_dissector("chdlc", dissect_chdlc
, proto_chdlc
);
235 /* Register the preferences for the chdlc protocol */
236 chdlc_module
= prefs_register_protocol(proto_chdlc
, NULL
);
238 prefs_register_enum_preference(chdlc_module
,
240 "CHDLC Frame Checksum Type",
241 "The type of CHDLC frame checksum (none, 16-bit, 32-bit)",
243 fcs_options
, ENC_BIG_ENDIAN
);
245 register_capture_dissector("chdlc", capture_chdlc
, proto_chdlc
);
250 proto_reg_handoff_chdlc(void)
252 capture_dissector_handle_t chdlc_cap_handle
;
254 dissector_add_uint("wtap_encap", WTAP_ENCAP_CHDLC
, chdlc_handle
);
255 dissector_add_uint("wtap_encap", WTAP_ENCAP_CHDLC_WITH_PHDR
, chdlc_handle
);
256 dissector_add_uint("juniper.proto", JUNIPER_PROTO_CHDLC
, chdlc_handle
);
257 dissector_add_uint("l2tp.pw_type", L2TPv3_PW_CHDLC
, chdlc_handle
);
259 chdlc_cap_handle
= find_capture_dissector("chdlc");
260 capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_CHDLC
, chdlc_cap_handle
);
262 ip_cap_handle
= find_capture_dissector("ip");
268 #define SLARP_REQUEST 0
269 #define SLARP_REPLY 1
270 #define SLARP_LINECHECK 2
272 static const value_string slarp_ptype_vals
[] = {
273 {SLARP_REQUEST
, "Request"},
274 {SLARP_REPLY
, "Reply"},
275 {SLARP_LINECHECK
, "Line keepalive"},
280 dissect_slarp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
283 proto_tree
*slarp_tree
;
287 uint32_t yoursequence
;
288 proto_item
* reliability_item
;
290 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "SLARP");
291 col_clear(pinfo
->cinfo
, COL_INFO
);
293 code
= tvb_get_ntohl(tvb
, 0);
295 ti
= proto_tree_add_item(tree
, proto_slarp
, tvb
, 0, 14, ENC_NA
);
296 slarp_tree
= proto_item_add_subtree(ti
, ett_slarp
);
302 addr
= tvb_get_ipv4(tvb
, 4);
303 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s, from %s, mask %s",
304 val_to_str(code
, slarp_ptype_vals
, "Unknown (%d)"),
305 get_hostname(addr
), tvb_ip_to_str(pinfo
->pool
, tvb
, 8));
307 proto_tree_add_uint(slarp_tree
, hf_slarp_ptype
, tvb
, 0, 4, code
);
308 proto_tree_add_item(slarp_tree
, hf_slarp_address
, tvb
, 4, 4, ENC_BIG_ENDIAN
);
309 proto_tree_add_item(slarp_tree
, hf_slarp_netmask
, tvb
, 8, 4, ENC_BIG_ENDIAN
);
313 case SLARP_LINECHECK
:
314 mysequence
= tvb_get_ntohl(tvb
, 4);
315 yoursequence
= tvb_get_ntohl(tvb
, 8);
316 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
317 "%s, outgoing sequence %u, returned sequence %u",
318 val_to_str(code
, slarp_ptype_vals
, "Unknown (%d)"),
319 mysequence
, yoursequence
);
321 proto_tree_add_uint(slarp_tree
, hf_slarp_ptype
, tvb
, 0, 4, code
);
322 proto_tree_add_uint(slarp_tree
, hf_slarp_mysequence
, tvb
, 4, 4,
324 proto_tree_add_uint(slarp_tree
, hf_slarp_yoursequence
, tvb
, 8, 4,
326 reliability_item
= proto_tree_add_item(slarp_tree
, hf_slarp_reliability
, tvb
,
327 12, 2, ENC_BIG_ENDIAN
);
328 if (tvb_get_ntohs(tvb
, 12) != 0xFFFF) {
329 expert_add_info(pinfo
, reliability_item
, &ei_slarp_reliability
);
334 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Unknown packet type 0x%08X", code
);
336 proto_tree_add_uint(slarp_tree
, hf_slarp_ptype
, tvb
, 0, 4, code
);
337 call_data_dissector(tvb_new_subset_remaining(tvb
, 4), pinfo
, slarp_tree
);
340 return tvb_captured_length(tvb
);
344 proto_register_slarp(void)
346 expert_module_t
* expert_slarp
;
348 static hf_register_info hf
[] = {
350 { "Packet type", "slarp.ptype", FT_UINT32
, BASE_DEC
,
351 VALS(slarp_ptype_vals
), 0x0, NULL
, HFILL
}},
353 { "Address", "slarp.address", FT_IPv4
, BASE_NONE
,
354 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. */
358 { "Netmask", "slarp.netmask", FT_IPv4
, BASE_NETMASK
,
359 NULL
, 0x0, NULL
, HFILL
}},
360 { &hf_slarp_mysequence
,
361 { "Outgoing sequence number", "slarp.mysequence", FT_UINT32
, BASE_DEC
,
362 NULL
, 0x0, NULL
, HFILL
}},
363 { &hf_slarp_yoursequence
,
364 { "Returned sequence number", "slarp.yoursequence", FT_UINT32
, BASE_DEC
,
365 NULL
, 0x0, NULL
, HFILL
}},
366 { &hf_slarp_reliability
,
367 { "Reliability", "slarp.reliability", FT_UINT16
, BASE_HEX
,
368 NULL
, 0x0, NULL
, HFILL
}},
370 static int *ett
[] = {
374 static ei_register_info ei
[] = {
375 { &ei_slarp_reliability
, { "slarp.reliability.invalid", PI_MALFORMED
, PI_ERROR
,
376 "Reliability must be 0xFFFF", EXPFILL
}}
379 proto_slarp
= proto_register_protocol("Cisco SLARP", "SLARP", "slarp");
380 register_dissector("slarp", dissect_slarp
, proto_slarp
);
381 proto_register_field_array(proto_slarp
, hf
, array_length(hf
));
382 proto_register_subtree_array(ett
, array_length(ett
));
384 expert_slarp
= expert_register_protocol(proto_slarp
);
385 expert_register_field_array(expert_slarp
, ei
, array_length(ei
));
389 proto_reg_handoff_slarp(void)
391 dissector_add_uint("chdlc.protocol", CISCO_SLARP
, find_dissector("slarp"));
395 * Editor modelines - https://www.wireshark.org/tools/modelines.html
400 * indent-tabs-mode: nil
403 * ex: set shiftwidth=2 tabstop=8 expandtab:
404 * :indentSize=2:tabSize=8:noTabs=true: