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>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
39 #include <epan/packet.h>
40 #include <epan/conversation.h>
41 #include <epan/xdlc.h>
42 #include <epan/crc16-tvb.h>
44 static int proto_v5dl
= -1;
45 static int hf_v5dl_direction
= -1;
46 /* static int hf_v5dl_address = -1; */
47 static int hf_v5dl_ef
= -1;
48 static int hf_v5dl_eah
= -1;
49 static int hf_v5dl_cr
= -1;
50 static int hf_v5dl_ea1
= -1;
51 static int hf_v5dl_eal
= -1;
52 static int hf_v5dl_ea2
= -1;
53 static int hf_v5dl_control
= -1;
54 static int hf_v5dl_n_r
= -1;
55 static int hf_v5dl_n_s
= -1;
56 static int hf_v5dl_p
= -1;
57 static int hf_v5dl_p_ext
= -1;
58 static int hf_v5dl_f
= -1;
59 static int hf_v5dl_f_ext
= -1;
60 static int hf_v5dl_s_ftype
= -1;
61 static int hf_v5dl_u_modifier_cmd
= -1;
62 static int hf_v5dl_u_modifier_resp
= -1;
63 static int hf_v5dl_ftype_i
= -1;
64 static int hf_v5dl_ftype_s_u
= -1;
65 static int hf_v5dl_ftype_s_u_ext
= -1;
67 static int hf_v5dl_checksum
= -1;
68 static int hf_v5dl_checksum_good
= -1;
69 static int hf_v5dl_checksum_bad
= -1;
71 static gint ett_v5dl
= -1;
72 static gint ett_v5dl_address
= -1;
73 static gint ett_v5dl_control
= -1;
74 /* static gint ett_v5dl_checksum = -1; */
76 static dissector_handle_t v52_handle
;
79 * Bits in the address field.
81 #define V5DL_EAH 0xfc00 /* Service Access Point Identifier */
82 #define V5DL_EAH_SHIFT 10
83 #define V5DL_CR 0x0200 /* Command/Response bit */
84 #define V5DL_EA1 0x0100 /* First Address Extension bit */
85 #define V5DL_EAL 0x00fe /* Terminal Endpoint Identifier */
86 #define V5DL_EAL_SHIFT 1
87 #define V5DL_EA2 0x0001 /* Second Address Extension bit */
89 static const value_string v5dl_direction_vals
[] = {
90 { P2P_DIR_RECV
, "Network->User"},
91 { P2P_DIR_SENT
, "User->Network"},
95 static const value_string v5dl_addr_vals
[] = {
96 { 8175, "ISDN Protocol" },
97 { 8176, "PSTN Protocol" },
98 { 8177, "CONTROL Protocol" },
99 { 8178, "BCC Protocol" },
100 { 8179, "PROT Protocol" },
101 { 8180, "Link Control Protocol" },
102 { 8191, "VALUE RESERVED" },
105 /* Used only for U frames */
106 static const xdlc_cf_items v5dl_cf_items
= {
112 &hf_v5dl_u_modifier_cmd
,
113 &hf_v5dl_u_modifier_resp
,
118 /* Used only for I and S frames */
119 static const xdlc_cf_items v5dl_cf_items_ext
= {
128 &hf_v5dl_ftype_s_u_ext
132 #define MAX_V5DL_PACKET_LEN 1024
135 dissect_v5dl(tvbuff_t
*, packet_info
*, proto_tree
*);
138 dissect_v5dl(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
140 proto_tree
*v5dl_tree
, *addr_tree
;
141 proto_item
*v5dl_ti
, *addr_ti
;
143 guint v5dl_header_len
;
146 proto_tree
*checksum_tree
;
147 proto_item
*checksum_ti
;
148 guint16 checksum
, checksum_calculated
;
149 guint checksum_offset
;
151 guint16 addr
, cr
, eah
, eal
, v5addr
;
152 gboolean is_response
= 0;
154 guint length
, reported_length
;
157 const char *srcname
= "?";
158 const char *dstname
= "?";
160 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "V5DL");
161 col_clear(pinfo
->cinfo
, COL_INFO
);
163 addr
= tvb_get_ntohs(tvb
, 0);
165 eal
= (addr
& V5DL_EAL
) >> V5DL_EAL_SHIFT
;
166 eah
= (addr
& V5DL_EAH
) >> V5DL_EAH_SHIFT
;
167 v5addr
= (eah
<< 7) + eal
;
168 v5dl_header_len
= 2; /* addr */
170 direction
= pinfo
->p2p_dir
;
171 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
172 is_response
= cr
? FALSE
: TRUE
;
176 else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
177 is_response
= cr
? TRUE
: FALSE
;
182 col_set_str(pinfo
->cinfo
, COL_RES_DL_SRC
, srcname
);
183 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, dstname
);
186 proto_item
*direction_ti
;
188 v5dl_ti
= proto_tree_add_item(tree
, proto_v5dl
, tvb
, 0, -1,
190 v5dl_tree
= proto_item_add_subtree(v5dl_ti
, ett_v5dl
);
193 * Don't show the direction if we don't know it.
195 if (direction
!= P2P_DIR_UNKNOWN
) {
196 direction_ti
= proto_tree_add_uint(v5dl_tree
, hf_v5dl_direction
,
197 tvb
, 0, 0, pinfo
->p2p_dir
);
198 PROTO_ITEM_SET_GENERATED(direction_ti
);
201 addr_ti
= proto_tree_add_uint(v5dl_tree
, hf_v5dl_ef
, tvb
,
203 addr_tree
= proto_item_add_subtree(addr_ti
, ett_v5dl_address
);
204 proto_tree_add_uint(addr_tree
, hf_v5dl_eah
, tvb
, 0, 1, addr
);
205 proto_tree_add_uint(addr_tree
, hf_v5dl_cr
, tvb
, 0, 1, addr
);
206 proto_tree_add_uint(addr_tree
, hf_v5dl_ea1
, tvb
, 0, 1, addr
);
207 proto_tree_add_uint(addr_tree
, hf_v5dl_eal
, tvb
, 1, 1, addr
);
208 proto_tree_add_uint(addr_tree
, hf_v5dl_ea2
, tvb
, 1, 1, addr
);
215 control
= dissect_xdlc_control(tvb
, 2, pinfo
, v5dl_tree
, hf_v5dl_control
,
216 ett_v5dl_control
, &v5dl_cf_items
, &v5dl_cf_items_ext
, NULL
, NULL
,
217 is_response
, TRUE
, FALSE
);
218 v5dl_header_len
+= XDLC_CONTROL_LEN(control
, TRUE
);
221 proto_item_set_len(v5dl_ti
, v5dl_header_len
);
224 * XXX - the sample capture supplied with bug 7027 does not
225 * appear to include checksums in the packets.
229 * Check the checksum, if available.
230 * The checksum is a CCITT CRC-16 at the end of the packet, so
231 * if we don't have the entire packet in the capture - i.e., if
232 * tvb_length(tvb) != tvb_reported_length(tvb) we can't check it.
234 length
= tvb_length(tvb
);
235 reported_length
= tvb_reported_length(tvb
);
238 * If the reported length isn't big enough for the V5DL header
239 * and 2 bytes of checksum, the packet is malformed, as the
240 * checksum overlaps the header.
242 if (reported_length
< v5dl_header_len
+ 2)
243 THROW(ReportedBoundsError
);
245 if (length
== reported_length
) {
247 * There's no snapshot length cutting off any of the
250 checksum_offset
= reported_length
- 2;
251 checksum
= tvb_get_ntohs(tvb
, checksum_offset
);
252 checksum_calculated
= crc16_ccitt_tvb(tvb
, checksum_offset
);
253 checksum_calculated
= g_htons(checksum_calculated
); /* Note: g_htons() macro may eval arg multiple times */
255 if (checksum
== checksum_calculated
) {
256 checksum_ti
= proto_tree_add_uint_format_value(v5dl_tree
, hf_v5dl_checksum
, tvb
, checksum_offset
,
260 checksum_tree
= proto_item_add_subtree(checksum_ti
, ett_v5dl_checksum
);
261 proto_tree_add_boolean(checksum_tree
, hf_v5dl_checksum_good
, tvb
, checksum_offset
, 2, TRUE
);
262 proto_tree_add_boolean(checksum_tree
, hf_v5dl_checksum_bad
, tvb
, checksum_offset
, 2, FALSE
);
264 checksum_ti
= proto_tree_add_uint_format_value(v5dl_tree
, hf_v5dl_checksum
, tvb
, checksum_offset
,
266 "0x%04x [incorrect, should be 0x%04x]",
267 checksum
, checksum_calculated
);
268 checksum_tree
= proto_item_add_subtree(checksum_ti
, ett_v5dl_checksum
);
269 proto_tree_add_boolean(checksum_tree
, hf_v5dl_checksum_good
, tvb
, checksum_offset
, 2, FALSE
);
270 proto_tree_add_boolean(checksum_tree
, hf_v5dl_checksum_bad
, tvb
, checksum_offset
, 2, TRUE
);
274 * Remove the V5DL header *and* the checksum.
276 next_tvb
= tvb_new_subset(tvb
, v5dl_header_len
,
277 tvb_length_remaining(tvb
, v5dl_header_len
) - 2,
278 tvb_reported_length_remaining(tvb
, v5dl_header_len
) - 2);
281 * Some or all of the packet is cut off by a snapshot
284 if (length
== reported_length
- 1) {
286 * One byte is cut off, so there's only one
287 * byte of checksum in the captured data.
288 * Remove that byte from the captured length
289 * and both bytes from the reported length.
291 next_tvb
= tvb_new_subset(tvb
, v5dl_header_len
,
292 tvb_length_remaining(tvb
, v5dl_header_len
) - 1,
293 tvb_reported_length_remaining(tvb
, v5dl_header_len
) - 2);
296 * Two or more bytes are cut off, so there are
297 * no bytes of checksum in the captured data.
298 * Just remove the checksum from the reported
301 next_tvb
= tvb_new_subset(tvb
, v5dl_header_len
,
302 tvb_length_remaining(tvb
, v5dl_header_len
),
303 tvb_reported_length_remaining(tvb
, v5dl_header_len
) - 2);
307 next_tvb
= tvb_new_subset_remaining(tvb
, v5dl_header_len
);
310 if (XDLC_IS_INFORMATION(control
)) {
311 /* call V5.2 dissector */
312 call_dissector(v52_handle
, next_tvb
, pinfo
, tree
);
317 proto_reg_handoff_v5dl(void);
320 proto_register_v5dl(void)
322 static hf_register_info hf
[] = {
324 { &hf_v5dl_direction
,
325 { "Direction", "v5dl.direction", FT_UINT8
, BASE_DEC
, VALS(v5dl_direction_vals
), 0x0,
330 { "Address Field", "v5dl.address", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
335 { "EF", "v5dl.ef", FT_UINT16
, BASE_DEC
, VALS(v5dl_addr_vals
), 0x0,
336 "Envelope Function Address", HFILL
}},
339 { "EAH", "v5dl.eah", FT_UINT16
, BASE_DEC
, NULL
, V5DL_EAH
,
340 "Envelope Address High", HFILL
}},
343 { "C/R", "v5dl.cr", FT_UINT16
, BASE_DEC
, NULL
, V5DL_CR
,
344 "Command/Response bit", HFILL
}},
347 { "EA1", "v5dl.ea1", FT_UINT16
, BASE_DEC
, NULL
, V5DL_EA1
,
348 "First Address Extension bit", HFILL
}},
351 { "EAL", "v5dl.eal", FT_UINT16
, BASE_DEC
, NULL
, V5DL_EAL
,
352 "Envelope Address Low", HFILL
}},
355 { "EA2", "v5dl.ea2", FT_UINT16
, BASE_DEC
, NULL
, V5DL_EA2
,
356 "Second Address Extension bit", HFILL
}},
359 { "Control Field", "v5dl.control", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
363 { "N(R)", "v5dl.control.n_r", FT_UINT16
, BASE_DEC
,
364 NULL
, XDLC_N_R_EXT_MASK
, NULL
, HFILL
}},
367 { "N(S)", "v5dl.control.n_s", FT_UINT16
, BASE_DEC
,
368 NULL
, XDLC_N_S_EXT_MASK
, NULL
, HFILL
}},
371 { "Poll", "v5dl.control.p", FT_BOOLEAN
, 8,
372 TFS(&tfs_set_notset
), XDLC_P_F
, NULL
, HFILL
}},
375 { "Poll", "v5dl.control.p", FT_BOOLEAN
, 16,
376 TFS(&tfs_set_notset
), XDLC_P_F_EXT
, NULL
, HFILL
}},
379 { "Final", "v5dl.control.f", FT_BOOLEAN
, 8,
380 TFS(&tfs_set_notset
), XDLC_P_F
, NULL
, HFILL
}},
383 { "Final", "v5dl.control.f", FT_BOOLEAN
, 16,
384 TFS(&tfs_set_notset
), XDLC_P_F_EXT
, NULL
, HFILL
}},
387 { "Supervisory frame type", "v5dl.control.s_ftype", FT_UINT16
, BASE_HEX
,
388 VALS(stype_vals
), XDLC_S_FTYPE_MASK
, NULL
, HFILL
}},
390 { &hf_v5dl_u_modifier_cmd
,
391 { "Command", "v5dl.control.u_modifier_cmd", FT_UINT8
, BASE_HEX
,
392 VALS(modifier_vals_cmd
), XDLC_U_MODIFIER_MASK
, NULL
, HFILL
}},
394 { &hf_v5dl_u_modifier_resp
,
395 { "Response", "v5dl.control.u_modifier_resp", FT_UINT8
, BASE_HEX
,
396 VALS(modifier_vals_resp
), XDLC_U_MODIFIER_MASK
, NULL
, HFILL
}},
399 { "Frame type", "v5dl.control.ftype", FT_UINT16
, BASE_HEX
,
400 VALS(ftype_vals
), XDLC_I_MASK
, NULL
, HFILL
}},
402 { &hf_v5dl_ftype_s_u
,
403 { "Frame type", "v5dl.control.ftype", FT_UINT8
, BASE_HEX
,
404 VALS(ftype_vals
), XDLC_S_U_MASK
, NULL
, HFILL
}},
406 { &hf_v5dl_ftype_s_u_ext
,
407 { "Frame type", "v5dl.control.ftype", FT_UINT16
, BASE_HEX
,
408 VALS(ftype_vals
), XDLC_S_U_MASK
, NULL
, HFILL
}},
412 { "Checksum", "v5dl.checksum", FT_UINT16
, BASE_HEX
,
413 NULL
, 0x0, "Details at: http://www.wireshark.org/docs/wsug_html_chunked/ChAdvChecksums.html", HFILL
}},
415 { &hf_v5dl_checksum_good
,
416 { "Good Checksum", "v5dl.checksum_good", FT_BOOLEAN
, BASE_NONE
,
417 NULL
, 0x0, "True: checksum matches packet content; False: doesn't match content or not checked", HFILL
}},
419 { &hf_v5dl_checksum_bad
,
420 { "Bad Checksum", "v5dl.checksum_bad", FT_BOOLEAN
, BASE_NONE
,
421 NULL
, 0x0, "True: checksum doesn't match packet content; False: matches content or not checked", HFILL
}}
425 static gint
*ett
[] = {
429 /* &ett_v5dl_checksum */
432 proto_v5dl
= proto_register_protocol("V5 Data Link Layer",
434 proto_register_field_array (proto_v5dl
, hf
, array_length(hf
));
435 proto_register_subtree_array(ett
, array_length(ett
));
437 register_dissector("v5dl", dissect_v5dl
, proto_v5dl
);
441 proto_reg_handoff_v5dl(void)
443 v52_handle
= find_dissector("v52");