2 * Routines for dsi packet dissection
3 * Copyright 2001, Randy McEoin <rmceoin@pe.com>
5 * $Id: packet-dsi.c,v 1.13 2002/04/28 19:21:39 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 #include "packet-afp.h"
50 /* The information in this module (DSI) comes from:
52 AFP 2.1 & 2.2.pdf contained in AppleShare_IP_6.3_SDK
53 available from http://www.apple.com
55 The netatalk source code by Wesley Craig & Adrian Sun
57 * What a Data Stream Interface packet looks like:
59 * |-------------------------------|
60 * |flags |command| requestID |
61 * |-------------------------------|
62 * |error code/enclosed data offset|
63 * |-------------------------------|
64 * |total data length |
65 * |-------------------------------|
67 * |-------------------------------|
70 static int proto_dsi = -1;
71 static int hf_dsi_flags = -1;
72 static int hf_dsi_command = -1;
73 static int hf_dsi_requestid = -1;
74 static int hf_dsi_code = -1;
75 static int hf_dsi_error = -1;
76 static int hf_dsi_length = -1;
77 static int hf_dsi_reserved = -1;
79 static gint ett_dsi = -1;
81 /* desegmentation of DSI */
82 static gboolean dsi_desegment = TRUE;
84 static dissector_handle_t data_handle;
85 static dissector_handle_t afp_handle;
87 #define TCP_PORT_DSI 548
89 #define DSI_BLOCKSIZ 16
92 #define DSIFL_REQUEST 0x00
93 #define DSIFL_REPLY 0x01
94 #define DSIFL_MAX 0x01
97 #define DSIFUNC_CLOSE 1 /* DSICloseSession */
98 #define DSIFUNC_CMD 2 /* DSICommand */
99 #define DSIFUNC_STAT 3 /* DSIGetStatus */
100 #define DSIFUNC_OPEN 4 /* DSIOpenSession */
101 #define DSIFUNC_TICKLE 5 /* DSITickle */
102 #define DSIFUNC_WRITE 6 /* DSIWrite */
103 #define DSIFUNC_ATTN 8 /* DSIAttention */
104 #define DSIFUNC_MAX 8 /* largest command */
106 static const value_string flag_vals[] = {
107 {DSIFL_REQUEST, "Request" },
108 {DSIFL_REPLY, "Reply" },
111 static const value_string func_vals[] = {
112 {DSIFUNC_CLOSE, "CloseSession" },
113 {DSIFUNC_CMD, "Command" },
114 {DSIFUNC_STAT, "GetStatus" },
115 {DSIFUNC_OPEN, "OpenSession" },
116 {DSIFUNC_TICKLE, "Tickle" },
117 {DSIFUNC_WRITE, "Write" },
118 {DSIFUNC_ATTN, "Attention" },
122 dissect_dsi_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
124 proto_tree *dsi_tree;
126 guint8 dsi_flags,dsi_command;
127 guint16 dsi_requestid;
130 guint32 dsi_reserved;
131 struct aspinfo aspinfo;
133 if (check_col(pinfo->cinfo, COL_PROTOCOL))
134 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DSI");
135 if (check_col(pinfo->cinfo, COL_INFO))
136 col_clear(pinfo->cinfo, COL_INFO);
138 dsi_flags = tvb_get_guint8(tvb, 0);
139 dsi_command = tvb_get_guint8(tvb, 1);
140 dsi_requestid = tvb_get_ntohs(tvb, 2);
141 dsi_code = tvb_get_ntohl(tvb, 4);
142 dsi_length = tvb_get_ntohl(tvb, 8);
143 dsi_reserved = tvb_get_ntohl(tvb, 12);
145 if (check_col(pinfo->cinfo, COL_INFO)) {
146 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s (%u)",
147 val_to_str(dsi_flags, flag_vals,
148 "Unknown flag (0x%02x)"),
149 val_to_str(dsi_command, func_vals,
150 "Unknown function (0x%02x)"),
156 ti = proto_tree_add_item(tree, proto_dsi, tvb, 0, -1, FALSE);
157 dsi_tree = proto_item_add_subtree(ti, ett_dsi);
159 proto_tree_add_uint(dsi_tree, hf_dsi_flags, tvb,
161 proto_tree_add_uint(dsi_tree, hf_dsi_command, tvb,
163 proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb,
164 2, 2, dsi_requestid);
166 proto_tree_add_int(dsi_tree, hf_dsi_error, tvb,
170 proto_tree_add_int(dsi_tree, hf_dsi_code, tvb,
173 proto_tree_add_uint_format(dsi_tree, hf_dsi_length, tvb,
175 "Length: %u bytes", dsi_length);
176 proto_tree_add_uint(dsi_tree, hf_dsi_reserved, tvb,
177 12, 4, dsi_reserved);
182 if (dsi_command == DSIFUNC_CMD || dsi_command == DSIFUNC_WRITE) {
184 int len = tvb_reported_length_remaining(tvb,DSI_BLOCKSIZ);
187 aspinfo.reply = dsi_flags & 1;
188 aspinfo.command = dsi_command;
189 aspinfo.seq = dsi_requestid;
190 aspinfo.code = dsi_code;
191 pinfo->private_data = &aspinfo;
192 proto_item_set_len(dsi_tree, DSI_BLOCKSIZ);
194 new_tvb = tvb_new_subset(tvb, DSI_BLOCKSIZ,-1,len);
195 call_dissector(afp_handle, new_tvb, pinfo, tree);
199 call_dissector(data_handle,tvb_new_subset(tvb, DSI_BLOCKSIZ,-1,tvb_reported_length_remaining(tvb,DSI_BLOCKSIZ)), pinfo, dsi_tree);
204 dissect_dsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
206 volatile int offset = 0;
207 int length_remaining;
212 while (tvb_reported_length_remaining(tvb, offset) != 0) {
213 length_remaining = tvb_length_remaining(tvb, offset);
216 * Can we do reassembly?
218 if (dsi_desegment && pinfo->can_desegment) {
220 * Yes - is the DSI header split across segment
223 if (length_remaining < 12) {
225 * Yes. Tell the TCP dissector where
226 * the data for this message starts in
227 * the data it handed us, and how many
228 * more bytes we need, and return.
230 pinfo->desegment_offset = offset;
231 pinfo->desegment_len = 12 - length_remaining;
237 * Get the length of the DSI packet.
239 plen = tvb_get_ntohl(tvb, offset+8);
242 * Can we do reassembly?
244 if (dsi_desegment && pinfo->can_desegment) {
246 * Yes - is the DSI packet split across segment
249 if ((guint32)length_remaining < plen + 16) {
251 * Yes. Tell the TCP dissector where
252 * the data for this message starts in
253 * the data it handed us, and how many
254 * more bytes we need, and return.
256 pinfo->desegment_offset = offset;
257 pinfo->desegment_len =
258 (plen + 16) - length_remaining;
264 * Construct a tvbuff containing the amount of the payload
265 * we have available. Make its reported length the
266 * amount of data in the DSI packet.
268 * XXX - if reassembly isn't enabled. the subdissector
269 * will throw a BoundsError exception, rather than a
270 * ReportedBoundsError exception. We really want
271 * a tvbuff where the length is "length", the reported
272 * length is "plen + 16", and the "if the snapshot length
273 * were infinite" length is the minimum of the
274 * reported length of the tvbuff handed to us and "plen+16",
275 * with a new type of exception thrown if the offset is
276 * within the reported length but beyond that third length,
277 * with that exception getting the "Unreassembled Packet"
280 length = length_remaining;
281 if ((guint32)length > plen + 16)
283 next_tvb = tvb_new_subset(tvb, offset, length, plen + 16);
286 * Dissect the DSI packet.
288 * Catch the ReportedBoundsError exception; if this
289 * particular message happens to get a ReportedBoundsError
290 * exception, that doesn't mean that we should stop
291 * dissecting DSI messages within this frame or chunk
292 * of reassembled data.
294 * If it gets a BoundsError, we can stop, as there's nothing
295 * more to see, so we just re-throw it.
298 dissect_dsi_packet(next_tvb, pinfo, tree);
303 CATCH(ReportedBoundsError) {
304 show_reported_bounds_error(tvb, pinfo, tree);
309 * Skip the DSI header and the payload.
316 proto_register_dsi(void)
319 static hf_register_info hf[] = {
321 { "Flags", "dsi.flags",
322 FT_UINT8, BASE_HEX, VALS(flag_vals), 0x0,
323 "Indicates request or reply.", HFILL }},
326 { "Command", "dsi.command",
327 FT_UINT8, BASE_DEC, VALS(func_vals), 0x0,
328 "Represents a DSI command.", HFILL }},
331 { "Request ID", "dsi.requestid",
332 FT_UINT16, BASE_DEC, NULL, 0x0,
333 "Keeps track of which request this is. Replies must match a Request. IDs must be generated in sequential order.", HFILL }},
336 { "Data offset", "dsi.data_offset",
337 FT_INT32, BASE_DEC, NULL, 0x0,
338 "Data offset.", HFILL }},
341 { "Error code", "dsi.error_code",
342 FT_INT32, BASE_DEC, VALS(asp_error_vals), 0x0,
343 "Error code", HFILL }},
346 { "Length", "dsi.length",
347 FT_UINT32, BASE_DEC, NULL, 0x0,
348 "Total length of the data that follows the DSI header.", HFILL }},
351 { "Reserved", "dsi.reserved",
352 FT_UINT32, BASE_HEX, NULL, 0x0,
353 "Reserved for future use. Should be set to zero.", HFILL }},
356 static gint *ett[] = {
359 module_t *dsi_module;
361 proto_dsi = proto_register_protocol("Data Stream Interface", "DSI", "dsi");
362 proto_register_field_array(proto_dsi, hf, array_length(hf));
363 proto_register_subtree_array(ett, array_length(ett));
365 dsi_module = prefs_register_protocol(proto_dsi, NULL);
366 prefs_register_bool_preference(dsi_module, "desegment",
367 "Desegment all DSI messages spanning multiple TCP segments",
368 "Whether the DSI dissector should desegment all messages spanning multiple TCP segments",
373 proto_reg_handoff_dsi(void)
375 static dissector_handle_t dsi_handle;
377 dsi_handle = create_dissector_handle(dissect_dsi, proto_dsi);
378 dissector_add("tcp.port", TCP_PORT_DSI, dsi_handle);
380 data_handle = find_dissector("data");
381 afp_handle = find_dissector("afp");