2 * Routines for dsi packet dissection
3 * Copyright 2001, Randy McEoin <rmceoin@pe.com>
5 * $Id: packet-dsi.c,v 1.12 2002/04/25 23:58:02 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_length = -1;
76 static int hf_dsi_reserved = -1;
78 static gint ett_dsi = -1;
80 /* desegmentation of DSI */
81 static gboolean dsi_desegment = TRUE;
83 static dissector_handle_t data_handle;
84 static dissector_handle_t afp_handle;
86 #define TCP_PORT_DSI 548
88 #define DSI_BLOCKSIZ 16
91 #define DSIFL_REQUEST 0x00
92 #define DSIFL_REPLY 0x01
93 #define DSIFL_MAX 0x01
96 #define DSIFUNC_CLOSE 1 /* DSICloseSession */
97 #define DSIFUNC_CMD 2 /* DSICommand */
98 #define DSIFUNC_STAT 3 /* DSIGetStatus */
99 #define DSIFUNC_OPEN 4 /* DSIOpenSession */
100 #define DSIFUNC_TICKLE 5 /* DSITickle */
101 #define DSIFUNC_WRITE 6 /* DSIWrite */
102 #define DSIFUNC_ATTN 8 /* DSIAttention */
103 #define DSIFUNC_MAX 8 /* largest command */
105 static const value_string flag_vals[] = {
106 {DSIFL_REQUEST, "Request" },
107 {DSIFL_REPLY, "Reply" },
110 static const value_string func_vals[] = {
111 {DSIFUNC_CLOSE, "CloseSession" },
112 {DSIFUNC_CMD, "Command" },
113 {DSIFUNC_STAT, "GetStatus" },
114 {DSIFUNC_OPEN, "OpenSession" },
115 {DSIFUNC_TICKLE, "Tickle" },
116 {DSIFUNC_WRITE, "Write" },
117 {DSIFUNC_ATTN, "Attention" },
121 dissect_dsi_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
123 proto_tree *dsi_tree;
125 guint8 dsi_flags,dsi_command;
126 guint16 dsi_requestid;
129 guint32 dsi_reserved;
130 struct aspinfo aspinfo;
132 if (check_col(pinfo->cinfo, COL_PROTOCOL))
133 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DSI");
134 if (check_col(pinfo->cinfo, COL_INFO))
135 col_clear(pinfo->cinfo, COL_INFO);
137 dsi_flags = tvb_get_guint8(tvb, 0);
138 dsi_command = tvb_get_guint8(tvb, 1);
139 dsi_requestid = tvb_get_ntohs(tvb, 2);
140 dsi_code = tvb_get_ntohl(tvb, 4);
141 dsi_length = tvb_get_ntohl(tvb, 8);
142 dsi_reserved = tvb_get_ntohl(tvb, 12);
144 if (check_col(pinfo->cinfo, COL_INFO)) {
145 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s (%u)",
146 val_to_str(dsi_flags, flag_vals,
147 "Unknown flag (0x%02x)"),
148 val_to_str(dsi_command, func_vals,
149 "Unknown function (0x%02x)"),
155 ti = proto_tree_add_item(tree, proto_dsi, tvb, 0, -1, FALSE);
156 dsi_tree = proto_item_add_subtree(ti, ett_dsi);
158 proto_tree_add_uint(dsi_tree, hf_dsi_flags, tvb,
160 proto_tree_add_uint(dsi_tree, hf_dsi_command, tvb,
162 proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb,
163 2, 2, dsi_requestid);
164 proto_tree_add_int(dsi_tree, hf_dsi_code, tvb,
166 proto_tree_add_uint_format(dsi_tree, hf_dsi_length, tvb,
168 "Length: %u bytes", dsi_length);
169 proto_tree_add_uint(dsi_tree, hf_dsi_reserved, tvb,
170 12, 4, dsi_reserved);
175 if (dsi_command == DSIFUNC_CMD || dsi_command == DSIFUNC_WRITE) {
177 int len = tvb_reported_length_remaining(tvb,DSI_BLOCKSIZ);
180 aspinfo.reply = dsi_flags & 1;
181 aspinfo.command = dsi_command;
182 aspinfo.seq = dsi_requestid;
183 aspinfo.code = dsi_code;
184 pinfo->private_data = &aspinfo;
185 proto_item_set_len(dsi_tree, DSI_BLOCKSIZ);
187 new_tvb = tvb_new_subset(tvb, DSI_BLOCKSIZ,-1,len);
188 call_dissector(afp_handle, new_tvb, pinfo, tree);
192 call_dissector(data_handle,tvb_new_subset(tvb, DSI_BLOCKSIZ,-1,tvb_reported_length_remaining(tvb,DSI_BLOCKSIZ)), pinfo, dsi_tree);
197 dissect_dsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
199 volatile int offset = 0;
200 int length_remaining;
205 while (tvb_reported_length_remaining(tvb, offset) != 0) {
206 length_remaining = tvb_length_remaining(tvb, offset);
209 * Can we do reassembly?
211 if (dsi_desegment && pinfo->can_desegment) {
213 * Yes - is the DSI header split across segment
216 if (length_remaining < 12) {
218 * Yes. Tell the TCP dissector where
219 * the data for this message starts in
220 * the data it handed us, and how many
221 * more bytes we need, and return.
223 pinfo->desegment_offset = offset;
224 pinfo->desegment_len = 12 - length_remaining;
230 * Get the length of the DSI packet.
232 plen = tvb_get_ntohl(tvb, offset+8);
235 * Can we do reassembly?
237 if (dsi_desegment && pinfo->can_desegment) {
239 * Yes - is the DSI packet split across segment
242 if ((guint32)length_remaining < plen + 16) {
244 * Yes. Tell the TCP dissector where
245 * the data for this message starts in
246 * the data it handed us, and how many
247 * more bytes we need, and return.
249 pinfo->desegment_offset = offset;
250 pinfo->desegment_len =
251 (plen + 16) - length_remaining;
257 * Construct a tvbuff containing the amount of the payload
258 * we have available. Make its reported length the
259 * amount of data in the DSI packet.
261 * XXX - if reassembly isn't enabled. the subdissector
262 * will throw a BoundsError exception, rather than a
263 * ReportedBoundsError exception. We really want
264 * a tvbuff where the length is "length", the reported
265 * length is "plen + 16", and the "if the snapshot length
266 * were infinite" length is the minimum of the
267 * reported length of the tvbuff handed to us and "plen+16",
268 * with a new type of exception thrown if the offset is
269 * within the reported length but beyond that third length,
270 * with that exception getting the "Unreassembled Packet"
273 length = length_remaining;
274 if ((guint32)length > plen + 16)
276 next_tvb = tvb_new_subset(tvb, offset, length, plen + 16);
279 * Dissect the DSI packet.
281 * Catch the ReportedBoundsError exception; if this
282 * particular message happens to get a ReportedBoundsError
283 * exception, that doesn't mean that we should stop
284 * dissecting DSI messages within this frame or chunk
285 * of reassembled data.
287 * If it gets a BoundsError, we can stop, as there's nothing
288 * more to see, so we just re-throw it.
291 dissect_dsi_packet(next_tvb, pinfo, tree);
296 CATCH(ReportedBoundsError) {
297 show_reported_bounds_error(tvb, pinfo, tree);
302 * Skip the DSI header and the payload.
309 proto_register_dsi(void)
312 static hf_register_info hf[] = {
314 { "Flags", "dsi.flags",
315 FT_UINT8, BASE_HEX, VALS(flag_vals), 0x0,
316 "Indicates request or reply.", HFILL }},
319 { "Command", "dsi.command",
320 FT_UINT8, BASE_DEC, VALS(func_vals), 0x0,
321 "Represents a DSI command.", HFILL }},
324 { "Request ID", "dsi.requestid",
325 FT_UINT16, BASE_DEC, NULL, 0x0,
326 "Keeps track of which request this is. Replies must match a Request. IDs must be generated in sequential order.", HFILL }},
329 { "Code", "dsi.code",
330 FT_INT32, BASE_DEC, NULL, 0x0,
331 "In Reply packets this is an error code. In Request Write packets this is a data offset.", HFILL }},
334 { "Length", "dsi.length",
335 FT_UINT32, BASE_DEC, NULL, 0x0,
336 "Total length of the data that follows the DSI header.", HFILL }},
339 { "Reserved", "dsi.reserved",
340 FT_UINT32, BASE_HEX, NULL, 0x0,
341 "Reserved for future use. Should be set to zero.", HFILL }},
344 static gint *ett[] = {
347 module_t *dsi_module;
349 proto_dsi = proto_register_protocol("Data Stream Interface", "DSI", "dsi");
350 proto_register_field_array(proto_dsi, hf, array_length(hf));
351 proto_register_subtree_array(ett, array_length(ett));
353 dsi_module = prefs_register_protocol(proto_dsi, NULL);
354 prefs_register_bool_preference(dsi_module, "desegment",
355 "Desegment all DSI messages spanning multiple TCP segments",
356 "Whether the DSI dissector should desegment all messages spanning multiple TCP segments",
361 proto_reg_handoff_dsi(void)
363 static dissector_handle_t dsi_handle;
365 dsi_handle = create_dissector_handle(dissect_dsi, proto_dsi);
366 dissector_add("tcp.port", TCP_PORT_DSI, dsi_handle);
368 data_handle = find_dissector("data");
369 afp_handle = find_dissector("afp");