HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-v5dl.c
blob8d4f06af3f55dce4fc1a4ee6895e1df44322b57e
1 /* packet-v5dl.c
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 * $Id$
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998
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.
27 * V5 Data Link Layer
29 * V5 references:
30 * ETS 300 324-1
31 * ETS 300 347-1
35 #include "config.h"
37 #include <glib.h>
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;
66 #if 0
67 static int hf_v5dl_checksum = -1;
68 static int hf_v5dl_checksum_good = -1;
69 static int hf_v5dl_checksum_bad = -1;
70 #endif
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"},
92 { 0, NULL }
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" },
103 { 0, NULL } };
105 /* Used only for U frames */
106 static const xdlc_cf_items v5dl_cf_items = {
107 NULL,
108 NULL,
109 &hf_v5dl_p,
110 &hf_v5dl_f,
111 NULL,
112 &hf_v5dl_u_modifier_cmd,
113 &hf_v5dl_u_modifier_resp,
114 NULL,
115 &hf_v5dl_ftype_s_u
118 /* Used only for I and S frames */
119 static const xdlc_cf_items v5dl_cf_items_ext = {
120 &hf_v5dl_n_r,
121 &hf_v5dl_n_s,
122 &hf_v5dl_p_ext,
123 &hf_v5dl_f_ext,
124 &hf_v5dl_s_ftype,
125 NULL,
126 NULL,
127 &hf_v5dl_ftype_i,
128 &hf_v5dl_ftype_s_u_ext
132 #define MAX_V5DL_PACKET_LEN 1024
134 static void
135 dissect_v5dl(tvbuff_t*, packet_info*, proto_tree*);
137 static void
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;
142 int direction;
143 guint v5dl_header_len;
144 guint16 control;
145 #if 0
146 proto_tree *checksum_tree;
147 proto_item *checksum_ti;
148 guint16 checksum, checksum_calculated;
149 guint checksum_offset;
150 #endif
151 guint16 addr, cr, eah, eal, v5addr;
152 gboolean is_response = 0;
153 #if 0
154 guint length, reported_length;
155 #endif
156 tvbuff_t *next_tvb;
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);
164 cr = addr & V5DL_CR;
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;
173 srcname = "Network";
174 dstname = "User";
176 else if (pinfo->p2p_dir == P2P_DIR_SENT) {
177 is_response = cr ? TRUE : FALSE;
178 srcname = "User";
179 dstname = "Network";
182 col_set_str(pinfo->cinfo, COL_RES_DL_SRC, srcname);
183 col_set_str(pinfo->cinfo, COL_RES_DL_DST, dstname);
185 if (tree) {
186 proto_item *direction_ti;
188 v5dl_ti = proto_tree_add_item(tree, proto_v5dl, tvb, 0, -1,
189 ENC_NA);
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,
202 0, 2, v5addr);
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);
210 else {
211 v5dl_ti = NULL;
212 v5dl_tree = NULL;
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);
220 if (tree)
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.
227 #if 0
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
248 * packet.
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,
257 2, 0,
258 "0x%04x [correct]",
259 checksum);
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);
263 } else {
264 checksum_ti = proto_tree_add_uint_format_value(v5dl_tree, hf_v5dl_checksum, tvb, checksum_offset,
265 2, 0,
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);
279 } else {
281 * Some or all of the packet is cut off by a snapshot
282 * length.
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);
294 } else {
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
299 * length.
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);
306 #else
307 next_tvb = tvb_new_subset_remaining(tvb, v5dl_header_len);
308 #endif
310 if (XDLC_IS_INFORMATION(control)) {
311 /* call V5.2 dissector */
312 call_dissector(v52_handle, next_tvb, pinfo, tree);
316 void
317 proto_reg_handoff_v5dl(void);
319 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,
326 NULL, HFILL }},
328 #if 0
329 { &hf_v5dl_address,
330 { "Address Field", "v5dl.address", FT_UINT16, BASE_HEX, NULL, 0x0,
331 "Address", HFILL }},
332 #endif
334 { &hf_v5dl_ef,
335 { "EF", "v5dl.ef", FT_UINT16, BASE_DEC, VALS(v5dl_addr_vals), 0x0,
336 "Envelope Function Address", HFILL }},
338 { &hf_v5dl_eah,
339 { "EAH", "v5dl.eah", FT_UINT16, BASE_DEC, NULL, V5DL_EAH,
340 "Envelope Address High", HFILL }},
342 { &hf_v5dl_cr,
343 { "C/R", "v5dl.cr", FT_UINT16, BASE_DEC, NULL, V5DL_CR,
344 "Command/Response bit", HFILL }},
346 { &hf_v5dl_ea1,
347 { "EA1", "v5dl.ea1", FT_UINT16, BASE_DEC, NULL, V5DL_EA1,
348 "First Address Extension bit", HFILL }},
350 { &hf_v5dl_eal,
351 { "EAL", "v5dl.eal", FT_UINT16, BASE_DEC, NULL, V5DL_EAL,
352 "Envelope Address Low", HFILL }},
354 { &hf_v5dl_ea2,
355 { "EA2", "v5dl.ea2", FT_UINT16, BASE_DEC, NULL, V5DL_EA2,
356 "Second Address Extension bit", HFILL }},
358 { &hf_v5dl_control,
359 { "Control Field", "v5dl.control", FT_UINT16, BASE_HEX, NULL, 0x0,
360 NULL, HFILL }},
362 { &hf_v5dl_n_r,
363 { "N(R)", "v5dl.control.n_r", FT_UINT16, BASE_DEC,
364 NULL, XDLC_N_R_EXT_MASK, NULL, HFILL }},
366 { &hf_v5dl_n_s,
367 { "N(S)", "v5dl.control.n_s", FT_UINT16, BASE_DEC,
368 NULL, XDLC_N_S_EXT_MASK, NULL, HFILL }},
370 { &hf_v5dl_p,
371 { "Poll", "v5dl.control.p", FT_BOOLEAN, 8,
372 TFS(&tfs_set_notset), XDLC_P_F, NULL, HFILL }},
374 { &hf_v5dl_p_ext,
375 { "Poll", "v5dl.control.p", FT_BOOLEAN, 16,
376 TFS(&tfs_set_notset), XDLC_P_F_EXT, NULL, HFILL }},
378 { &hf_v5dl_f,
379 { "Final", "v5dl.control.f", FT_BOOLEAN, 8,
380 TFS(&tfs_set_notset), XDLC_P_F, NULL, HFILL }},
382 { &hf_v5dl_f_ext,
383 { "Final", "v5dl.control.f", FT_BOOLEAN, 16,
384 TFS(&tfs_set_notset), XDLC_P_F_EXT, NULL, HFILL }},
386 { &hf_v5dl_s_ftype,
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 }},
398 { &hf_v5dl_ftype_i,
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 }},
410 #if 0
411 { &hf_v5dl_checksum,
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 }}
422 #endif
425 static gint *ett[] = {
426 &ett_v5dl,
427 &ett_v5dl_address,
428 &ett_v5dl_control,
429 /* &ett_v5dl_checksum */
432 proto_v5dl = proto_register_protocol("V5 Data Link Layer",
433 "V5DL", "v5dl");
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);
440 void
441 proto_reg_handoff_v5dl(void)
443 v52_handle = find_dissector("v52");