2 * Routines for V5 data link frame disassembly
3 * Rolf Fiedler <rolf.fiedler@innoventif.de> using the LAPD code of
4 * Gilbert Ramirez <gram@alumni.rice.edu>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
10 * SPDX-License-Identifier: GPL-2.0-or-later
23 #include <epan/packet.h>
24 #include <epan/expert.h>
25 #include <epan/xdlc.h>
27 #include <wsutil/array.h>
29 void proto_register_v5dl(void);
31 static int proto_v5dl
;
32 static int hf_v5dl_direction
;
33 /* static int hf_v5dl_address; */
34 static int hf_v5dl_ef
;
35 static int hf_v5dl_eah
;
36 static int hf_v5dl_cr
;
37 static int hf_v5dl_ea1
;
38 static int hf_v5dl_eal
;
39 static int hf_v5dl_ea2
;
40 static int hf_v5dl_control
;
41 static int hf_v5dl_n_r
;
42 static int hf_v5dl_n_s
;
44 static int hf_v5dl_p_ext
;
46 static int hf_v5dl_f_ext
;
47 static int hf_v5dl_s_ftype
;
48 static int hf_v5dl_u_modifier_cmd
;
49 static int hf_v5dl_u_modifier_resp
;
50 static int hf_v5dl_ftype_i
;
51 static int hf_v5dl_ftype_s_u
;
52 static int hf_v5dl_ftype_s_u_ext
;
54 static int hf_v5dl_checksum
;
55 static int hf_v5dl_checksum_status
;
58 static int ett_v5dl_address
;
59 static int ett_v5dl_control
;
60 /* static int ett_v5dl_checksum; */
62 static expert_field ei_v5dl_checksum
;
64 static dissector_handle_t v52_handle
;
67 * Bits in the address field.
69 #define V5DL_EAH 0xfc00 /* Service Access Point Identifier */
70 #define V5DL_EAH_SHIFT 10
71 #define V5DL_CR 0x0200 /* Command/Response bit */
72 #define V5DL_EA1 0x0100 /* First Address Extension bit */
73 #define V5DL_EAL 0x00fe /* Terminal Endpoint Identifier */
74 #define V5DL_EAL_SHIFT 1
75 #define V5DL_EA2 0x0001 /* Second Address Extension bit */
77 static const value_string v5dl_direction_vals
[] = {
78 { P2P_DIR_RECV
, "Network->User"},
79 { P2P_DIR_SENT
, "User->Network"},
83 static const value_string v5dl_addr_vals
[] = {
84 { 8175, "ISDN Protocol" },
85 { 8176, "PSTN Protocol" },
86 { 8177, "CONTROL Protocol" },
87 { 8178, "BCC Protocol" },
88 { 8179, "PROT Protocol" },
89 { 8180, "Link Control Protocol" },
90 { 8191, "VALUE RESERVED" },
93 /* Used only for U frames */
94 static const xdlc_cf_items v5dl_cf_items
= {
100 &hf_v5dl_u_modifier_cmd
,
101 &hf_v5dl_u_modifier_resp
,
106 /* Used only for I and S frames */
107 static const xdlc_cf_items v5dl_cf_items_ext
= {
116 &hf_v5dl_ftype_s_u_ext
120 #define MAX_V5DL_PACKET_LEN 1024
123 dissect_v5dl(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
125 proto_tree
*v5dl_tree
, *addr_tree
;
126 proto_item
*v5dl_ti
, *addr_ti
;
128 unsigned v5dl_header_len
;
131 proto_tree
*checksum_tree
;
132 proto_item
*checksum_ti
;
133 uint16_t checksum
, checksum_calculated
;
134 unsigned checksum_offset
;
136 uint16_t addr
, cr
, eah
, eal
, v5addr
;
137 bool is_response
= 0;
139 unsigned length
, reported_length
;
142 const char *srcname
= "?";
143 const char *dstname
= "?";
145 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "V5DL");
146 col_clear(pinfo
->cinfo
, COL_INFO
);
148 addr
= tvb_get_ntohs(tvb
, 0);
150 eal
= (addr
& V5DL_EAL
) >> V5DL_EAL_SHIFT
;
151 eah
= (addr
& V5DL_EAH
) >> V5DL_EAH_SHIFT
;
152 v5addr
= (eah
<< 7) + eal
;
153 v5dl_header_len
= 2; /* addr */
155 direction
= pinfo
->p2p_dir
;
156 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
157 is_response
= cr
? false : true;
161 else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
162 is_response
= cr
? true : false;
167 col_set_str(pinfo
->cinfo
, COL_RES_DL_SRC
, srcname
);
168 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, dstname
);
171 proto_item
*direction_ti
;
173 v5dl_ti
= proto_tree_add_item(tree
, proto_v5dl
, tvb
, 0, -1,
175 v5dl_tree
= proto_item_add_subtree(v5dl_ti
, ett_v5dl
);
178 * Don't show the direction if we don't know it.
180 if (direction
!= P2P_DIR_UNKNOWN
) {
181 direction_ti
= proto_tree_add_uint(v5dl_tree
, hf_v5dl_direction
,
182 tvb
, 0, 0, pinfo
->p2p_dir
);
183 proto_item_set_generated(direction_ti
);
186 addr_ti
= proto_tree_add_uint(v5dl_tree
, hf_v5dl_ef
, tvb
,
188 addr_tree
= proto_item_add_subtree(addr_ti
, ett_v5dl_address
);
189 proto_tree_add_uint(addr_tree
, hf_v5dl_eah
, tvb
, 0, 1, addr
);
190 proto_tree_add_uint(addr_tree
, hf_v5dl_cr
, tvb
, 0, 1, addr
);
191 proto_tree_add_uint(addr_tree
, hf_v5dl_ea1
, tvb
, 0, 1, addr
);
192 proto_tree_add_uint(addr_tree
, hf_v5dl_eal
, tvb
, 1, 1, addr
);
193 proto_tree_add_uint(addr_tree
, hf_v5dl_ea2
, tvb
, 1, 1, addr
);
200 control
= dissect_xdlc_control(tvb
, 2, pinfo
, v5dl_tree
, hf_v5dl_control
,
201 ett_v5dl_control
, &v5dl_cf_items
, &v5dl_cf_items_ext
, NULL
, NULL
,
202 is_response
, true, false);
203 v5dl_header_len
+= XDLC_CONTROL_LEN(control
, true);
206 proto_item_set_len(v5dl_ti
, v5dl_header_len
);
209 * XXX - the sample capture supplied with bug 7027 does not
210 * appear to include checksums in the packets.
214 * Check the checksum, if available.
215 * The checksum is a CCITT CRC-16 at the end of the packet, so
216 * if we don't have the entire packet in the capture - i.e., if
217 * tvb_captured_length(tvb) != tvb_reported_length(tvb) we can't check it.
219 length
= tvb_captured_length(tvb
);
220 reported_length
= tvb_reported_length(tvb
);
223 * If the reported length isn't big enough for the V5DL header
224 * and 2 bytes of checksum, the packet is malformed, as the
225 * checksum overlaps the header.
227 if (reported_length
< v5dl_header_len
+ 2)
230 if (length
== reported_length
) {
232 * There's no snapshot length cutting off any of the
235 checksum_offset
= reported_length
- 2;
236 checksum_calculated
= crc16_ccitt_tvb(tvb
, checksum_offset
);
237 checksum_calculated
= g_htons(checksum_calculated
); /* Note: g_htons() macro may eval arg multiple times */
239 proto_tree_add_checksum(v5dl_tree
, tvb
, checksum_offset
, hf_v5dl_checksum
, hf_v5dl_checksum_status
, &ei_v5dl_checksum
,
240 pinfo
, checksum_calculated
, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_VERIFY
);
242 * Remove the V5DL header *and* the checksum.
244 next_tvb
= tvb_new_subset_length_caplen(tvb
, v5dl_header_len
,
245 tvb_captured_length_remaining(tvb
, v5dl_header_len
) - 2,
246 tvb_reported_length_remaining(tvb
, v5dl_header_len
) - 2);
249 * Some or all of the packet is cut off by a snapshot
252 if (length
== reported_length
- 1) {
254 * One byte is cut off, so there's only one
255 * byte of checksum in the captured data.
256 * Remove that byte from the captured length
257 * and both bytes from the reported length.
259 next_tvb
= tvb_new_subset_length_caplen(tvb
, v5dl_header_len
,
260 tvb_captured_length_remaining(tvb
, v5dl_header_len
) - 1,
261 tvb_reported_length_remaining(tvb
, v5dl_header_len
) - 2);
264 * Two or more bytes are cut off, so there are
265 * no bytes of checksum in the captured data.
266 * Just remove the checksum from the reported
269 next_tvb
= tvb_new_subset_length_caplen(tvb
, v5dl_header_len
,
270 tvb_captured_length_remaining(tvb
, v5dl_header_len
),
271 tvb_reported_length_remaining(tvb
, v5dl_header_len
) - 2);
275 next_tvb
= tvb_new_subset_remaining(tvb
, v5dl_header_len
);
278 if (XDLC_IS_INFORMATION(control
)) {
279 /* call V5.2 dissector */
280 call_dissector(v52_handle
, next_tvb
, pinfo
, tree
);
282 return tvb_captured_length(tvb
);
286 proto_reg_handoff_v5dl(void);
289 proto_register_v5dl(void)
291 static hf_register_info hf
[] = {
293 { &hf_v5dl_direction
,
294 { "Direction", "v5dl.direction", FT_UINT8
, BASE_DEC
, VALS(v5dl_direction_vals
), 0x0,
299 { "Address Field", "v5dl.address", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
304 { "EF", "v5dl.ef", FT_UINT16
, BASE_DEC
, VALS(v5dl_addr_vals
), 0x0,
305 "Envelope Function Address", HFILL
}},
308 { "EAH", "v5dl.eah", FT_UINT16
, BASE_DEC
, NULL
, V5DL_EAH
,
309 "Envelope Address High", HFILL
}},
312 { "C/R", "v5dl.cr", FT_UINT16
, BASE_DEC
, NULL
, V5DL_CR
,
313 "Command/Response bit", HFILL
}},
316 { "EA1", "v5dl.ea1", FT_UINT16
, BASE_DEC
, NULL
, V5DL_EA1
,
317 "First Address Extension bit", HFILL
}},
320 { "EAL", "v5dl.eal", FT_UINT16
, BASE_DEC
, NULL
, V5DL_EAL
,
321 "Envelope Address Low", HFILL
}},
324 { "EA2", "v5dl.ea2", FT_UINT16
, BASE_DEC
, NULL
, V5DL_EA2
,
325 "Second Address Extension bit", HFILL
}},
328 { "Control Field", "v5dl.control", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
332 { "N(R)", "v5dl.control.n_r", FT_UINT16
, BASE_DEC
,
333 NULL
, XDLC_N_R_EXT_MASK
, NULL
, HFILL
}},
336 { "N(S)", "v5dl.control.n_s", FT_UINT16
, BASE_DEC
,
337 NULL
, XDLC_N_S_EXT_MASK
, NULL
, HFILL
}},
340 { "Poll", "v5dl.control.p", FT_BOOLEAN
, 8,
341 TFS(&tfs_set_notset
), XDLC_P_F
, NULL
, HFILL
}},
344 { "Poll", "v5dl.control.p", FT_BOOLEAN
, 16,
345 TFS(&tfs_set_notset
), XDLC_P_F_EXT
, NULL
, HFILL
}},
348 { "Final", "v5dl.control.f", FT_BOOLEAN
, 8,
349 TFS(&tfs_set_notset
), XDLC_P_F
, NULL
, HFILL
}},
352 { "Final", "v5dl.control.f", FT_BOOLEAN
, 16,
353 TFS(&tfs_set_notset
), XDLC_P_F_EXT
, NULL
, HFILL
}},
356 { "Supervisory frame type", "v5dl.control.s_ftype", FT_UINT16
, BASE_HEX
,
357 VALS(stype_vals
), XDLC_S_FTYPE_MASK
, NULL
, HFILL
}},
359 { &hf_v5dl_u_modifier_cmd
,
360 { "Command", "v5dl.control.u_modifier_cmd", FT_UINT8
, BASE_HEX
,
361 VALS(modifier_vals_cmd
), XDLC_U_MODIFIER_MASK
, NULL
, HFILL
}},
363 { &hf_v5dl_u_modifier_resp
,
364 { "Response", "v5dl.control.u_modifier_resp", FT_UINT8
, BASE_HEX
,
365 VALS(modifier_vals_resp
), XDLC_U_MODIFIER_MASK
, NULL
, HFILL
}},
368 { "Frame type", "v5dl.control.ftype", FT_UINT16
, BASE_HEX
,
369 VALS(ftype_vals
), XDLC_I_MASK
, NULL
, HFILL
}},
371 { &hf_v5dl_ftype_s_u
,
372 { "Frame type", "v5dl.control.ftype", FT_UINT8
, BASE_HEX
,
373 VALS(ftype_vals
), XDLC_S_U_MASK
, NULL
, HFILL
}},
375 { &hf_v5dl_ftype_s_u_ext
,
376 { "Frame type", "v5dl.control.ftype", FT_UINT16
, BASE_HEX
,
377 VALS(ftype_vals
), XDLC_S_U_MASK
, NULL
, HFILL
}},
381 { "Checksum", "v5dl.checksum", FT_UINT16
, BASE_HEX
,
382 NULL
, 0x0, "Details at: https://www.wireshark.org/docs/wsug_html_chunked/ChAdvChecksums.html", HFILL
}},
384 { &hf_v5dl_checksum_status
,
385 { "Checksum Status", "v5dl.checksum.status", FT_UINT8
, BASE_NONE
,
386 VALS(proto_checksum_vals
), 0x0, NULL
, HFILL
}},
390 static int *ett
[] = {
394 /* &ett_v5dl_checksum */
397 static ei_register_info ei
[] = {
398 { &ei_v5dl_checksum
, { "v5dl.bad_checksum", PI_CHECKSUM
, PI_ERROR
, "Bad checksum", EXPFILL
}},
401 expert_module_t
* expert_v5dl
;
403 proto_v5dl
= proto_register_protocol("V5 Data Link Layer", "V5DL", "v5dl");
404 proto_register_field_array (proto_v5dl
, hf
, array_length(hf
));
405 proto_register_subtree_array(ett
, array_length(ett
));
406 expert_v5dl
= expert_register_protocol(proto_v5dl
);
407 expert_register_field_array(expert_v5dl
, ei
, array_length(ei
));
409 register_dissector("v5dl", dissect_v5dl
, proto_v5dl
);
413 proto_reg_handoff_v5dl(void)
415 v52_handle
= find_dissector_add_dependency("v52", proto_v5dl
);
419 * Editor modelines - https://www.wireshark.org/tools/modelines.html
424 * indent-tabs-mode: t
427 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
428 * :indentSize=8:tabSize=8:noTabs=false: