2 * Routines for dsi packet dissection
3 * Copyright 2001, Randy McEoin <rmceoin@pe.com>
5 * $Id: packet-dsi.c,v 1.11 2002/04/22 08:50:49 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * Copied from packet-pop.c
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
43 #include <epan/packet.h>
46 #include "packet-frame.h"
48 /* The information in this module (DSI) comes from:
50 AFP 2.1 & 2.2.pdf contained in AppleShare_IP_6.3_SDK
51 available from http://www.apple.com
53 The netatalk source code by Wesley Craig & Adrian Sun
55 * What a Data Stream Interface packet looks like:
57 * |-------------------------------|
58 * |flags |command| requestID |
59 * |-------------------------------|
60 * |error code/enclosed data offset|
61 * |-------------------------------|
62 * |total data length |
63 * |-------------------------------|
65 * |-------------------------------|
68 static int proto_dsi = -1;
69 static int hf_dsi_flags = -1;
70 static int hf_dsi_command = -1;
71 static int hf_dsi_requestid = -1;
72 static int hf_dsi_code = -1;
73 static int hf_dsi_length = -1;
74 static int hf_dsi_reserved = -1;
76 static gint ett_dsi = -1;
78 /* desegmentation of DSI */
79 static gboolean dsi_desegment = TRUE;
81 static dissector_handle_t data_handle;
83 #define TCP_PORT_DSI 548
86 #define DSIFL_REQUEST 0x00
87 #define DSIFL_REPLY 0x01
88 #define DSIFL_MAX 0x01
91 #define DSIFUNC_CLOSE 1 /* DSICloseSession */
92 #define DSIFUNC_CMD 2 /* DSICommand */
93 #define DSIFUNC_STAT 3 /* DSIGetStatus */
94 #define DSIFUNC_OPEN 4 /* DSIOpenSession */
95 #define DSIFUNC_TICKLE 5 /* DSITickle */
96 #define DSIFUNC_WRITE 6 /* DSIWrite */
97 #define DSIFUNC_ATTN 8 /* DSIAttention */
98 #define DSIFUNC_MAX 8 /* largest command */
100 static const value_string flag_vals[] = {
101 {DSIFL_REQUEST, "Request" },
102 {DSIFL_REPLY, "Reply" },
105 static const value_string func_vals[] = {
106 {DSIFUNC_CLOSE, "CloseSession" },
107 {DSIFUNC_CMD, "Command" },
108 {DSIFUNC_STAT, "GetStatus" },
109 {DSIFUNC_OPEN, "OpenSession" },
110 {DSIFUNC_TICKLE, "Tickle" },
111 {DSIFUNC_WRITE, "Write" },
112 {DSIFUNC_ATTN, "Attention" },
116 dissect_dsi_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
118 proto_tree *dsi_tree;
120 guint8 dsi_flags,dsi_command;
121 guint16 dsi_requestid;
124 guint32 dsi_reserved;
126 if (check_col(pinfo->cinfo, COL_PROTOCOL))
127 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DSI");
128 if (check_col(pinfo->cinfo, COL_INFO))
129 col_clear(pinfo->cinfo, COL_INFO);
131 dsi_flags = tvb_get_guint8(tvb, 0);
132 dsi_command = tvb_get_guint8(tvb, 1);
133 dsi_requestid = tvb_get_ntohs(tvb, 2);
134 dsi_code = tvb_get_ntohl(tvb, 4);
135 dsi_length = tvb_get_ntohl(tvb, 8);
136 dsi_reserved = tvb_get_ntohl(tvb, 12);
138 if (check_col(pinfo->cinfo, COL_INFO)) {
139 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s (%u)",
140 val_to_str(dsi_flags, flag_vals,
141 "Unknown flag (0x%02x)"),
142 val_to_str(dsi_command, func_vals,
143 "Unknown function (0x%02x)"),
149 ti = proto_tree_add_item(tree, proto_dsi, tvb, 0, -1, FALSE);
150 dsi_tree = proto_item_add_subtree(ti, ett_dsi);
152 proto_tree_add_uint(dsi_tree, hf_dsi_flags, tvb,
154 proto_tree_add_uint(dsi_tree, hf_dsi_command, tvb,
156 proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb,
157 2, 2, dsi_requestid);
158 proto_tree_add_int(dsi_tree, hf_dsi_code, tvb,
160 proto_tree_add_uint_format(dsi_tree, hf_dsi_length, tvb,
162 "Length: %u bytes", dsi_length);
163 proto_tree_add_uint(dsi_tree, hf_dsi_reserved, tvb,
164 12, 4, dsi_reserved);
165 call_dissector(data_handle,tvb_new_subset(tvb, 16,-1,tvb_reported_length_remaining(tvb,16)), pinfo, dsi_tree);
170 dissect_dsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
172 volatile int offset = 0;
173 int length_remaining;
178 while (tvb_reported_length_remaining(tvb, offset) != 0) {
179 length_remaining = tvb_length_remaining(tvb, offset);
182 * Can we do reassembly?
184 if (dsi_desegment && pinfo->can_desegment) {
186 * Yes - is the DSI header split across segment
189 if (length_remaining < 12) {
191 * Yes. Tell the TCP dissector where
192 * the data for this message starts in
193 * the data it handed us, and how many
194 * more bytes we need, and return.
196 pinfo->desegment_offset = offset;
197 pinfo->desegment_len = 12 - length_remaining;
203 * Get the length of the DSI packet.
205 plen = tvb_get_ntohl(tvb, offset+8);
208 * Can we do reassembly?
210 if (dsi_desegment && pinfo->can_desegment) {
212 * Yes - is the DSI packet split across segment
215 if ((guint32)length_remaining < plen + 16) {
217 * Yes. Tell the TCP dissector where
218 * the data for this message starts in
219 * the data it handed us, and how many
220 * more bytes we need, and return.
222 pinfo->desegment_offset = offset;
223 pinfo->desegment_len =
224 (plen + 16) - length_remaining;
230 * Construct a tvbuff containing the amount of the payload
231 * we have available. Make its reported length the
232 * amount of data in the DSI packet.
234 * XXX - if reassembly isn't enabled. the subdissector
235 * will throw a BoundsError exception, rather than a
236 * ReportedBoundsError exception. We really want
237 * a tvbuff where the length is "length", the reported
238 * length is "plen + 16", and the "if the snapshot length
239 * were infinite" length is the minimum of the
240 * reported length of the tvbuff handed to us and "plen+16",
241 * with a new type of exception thrown if the offset is
242 * within the reported length but beyond that third length,
243 * with that exception getting the "Unreassembled Packet"
246 length = length_remaining;
247 if ((guint32)length > plen + 16)
249 next_tvb = tvb_new_subset(tvb, offset, length, plen + 16);
252 * Dissect the DSI packet.
254 * Catch the ReportedBoundsError exception; if this
255 * particular message happens to get a ReportedBoundsError
256 * exception, that doesn't mean that we should stop
257 * dissecting DSI messages within this frame or chunk
258 * of reassembled data.
260 * If it gets a BoundsError, we can stop, as there's nothing
261 * more to see, so we just re-throw it.
264 dissect_dsi_packet(next_tvb, pinfo, tree);
269 CATCH(ReportedBoundsError) {
270 show_reported_bounds_error(tvb, pinfo, tree);
275 * Skip the DSI header and the payload.
282 proto_register_dsi(void)
285 static hf_register_info hf[] = {
287 { "Flags", "dsi.flags",
288 FT_UINT8, BASE_HEX, VALS(flag_vals), 0x0,
289 "Indicates request or reply.", HFILL }},
292 { "Command", "dsi.command",
293 FT_UINT8, BASE_DEC, VALS(func_vals), 0x0,
294 "Represents a DSI command.", HFILL }},
297 { "Request ID", "dsi.requestid",
298 FT_UINT16, BASE_DEC, NULL, 0x0,
299 "Keeps track of which request this is. Replies must match a Request. IDs must be generated in sequential order.", HFILL }},
302 { "Code", "dsi.code",
303 FT_INT32, BASE_DEC, NULL, 0x0,
304 "In Reply packets this is an error code. In Request Write packets this is a data offset.", HFILL }},
307 { "Length", "dsi.length",
308 FT_UINT32, BASE_DEC, NULL, 0x0,
309 "Total length of the data that follows the DSI header.", HFILL }},
312 { "Reserved", "dsi.reserved",
313 FT_UINT32, BASE_HEX, NULL, 0x0,
314 "Reserved for future use. Should be set to zero.", HFILL }},
317 static gint *ett[] = {
320 module_t *dsi_module;
322 proto_dsi = proto_register_protocol("Data Stream Interface", "DSI", "dsi");
323 proto_register_field_array(proto_dsi, hf, array_length(hf));
324 proto_register_subtree_array(ett, array_length(ett));
326 dsi_module = prefs_register_protocol(proto_dsi, NULL);
327 prefs_register_bool_preference(dsi_module, "desegment",
328 "Desegment all DSI messages spanning multiple TCP segments",
329 "Whether the DSI dissector should desegment all messages spanning multiple TCP segments",
334 proto_reg_handoff_dsi(void)
336 static dissector_handle_t dsi_handle;
338 dsi_handle = create_dissector_handle(dissect_dsi, proto_dsi);
339 dissector_add("tcp.port", TCP_PORT_DSI, dsi_handle);
341 data_handle = find_dissector("data");