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