6e20624abd96d879b5babf5460be4d0fe2729dd7
[obnox/wireshark/wip.git] / packet-dsi.c
1 /* packet-dsi.c
2  * Routines for dsi packet dissection
3  * Copyright 2001, Randy McEoin <rmceoin@pe.com>
4  *
5  * $Id: packet-dsi.c,v 1.13 2002/04/28 19:21:39 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-pop.c
12  *
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.
17  * 
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.
22  * 
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.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41
42 #include <glib.h>
43 #include <epan/packet.h>
44
45 #include "prefs.h"
46 #include "packet-frame.h"
47
48 #include "packet-afp.h"
49
50 /* The information in this module (DSI) comes from:
51
52   AFP 2.1 & 2.2.pdf contained in AppleShare_IP_6.3_SDK
53   available from http://www.apple.com
54
55   The netatalk source code by Wesley Craig & Adrian Sun
56
57  * What a Data Stream Interface packet looks like:
58  * 0                               32
59  * |-------------------------------|
60  * |flags  |command| requestID     |
61  * |-------------------------------|
62  * |error code/enclosed data offset|
63  * |-------------------------------|
64  * |total data length              |
65  * |-------------------------------|
66  * |reserved field                 |
67  * |-------------------------------|
68  */
69
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;
78
79 static gint ett_dsi = -1;
80
81 /* desegmentation of DSI */
82 static gboolean dsi_desegment = TRUE;
83
84 static dissector_handle_t data_handle;
85 static dissector_handle_t afp_handle;
86
87 #define TCP_PORT_DSI                    548
88
89 #define DSI_BLOCKSIZ            16
90
91 /* DSI flags */
92 #define DSIFL_REQUEST    0x00
93 #define DSIFL_REPLY      0x01
94 #define DSIFL_MAX        0x01
95
96 /* DSI Commands */
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 */
105
106 static const value_string flag_vals[] = {
107   {DSIFL_REQUEST,       "Request" },
108   {DSIFL_REPLY,         "Reply" },
109   {0,                   NULL } };
110
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" },
119   {0,                   NULL } };
120
121 static void
122 dissect_dsi_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
123 {
124         proto_tree      *dsi_tree;
125         proto_item      *ti;
126         guint8          dsi_flags,dsi_command;
127         guint16         dsi_requestid;
128         gint32          dsi_code;
129         guint32         dsi_length;
130         guint32         dsi_reserved;
131         struct          aspinfo aspinfo;
132  
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);
137
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);
144
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)"),
151                         dsi_requestid);
152         }
153
154
155         if (tree) {
156                 ti = proto_tree_add_item(tree, proto_dsi, tvb, 0, -1, FALSE);
157                 dsi_tree = proto_item_add_subtree(ti, ett_dsi);
158
159                 proto_tree_add_uint(dsi_tree, hf_dsi_flags, tvb,
160                         0, 1, dsi_flags);
161                 proto_tree_add_uint(dsi_tree, hf_dsi_command, tvb,
162                         1, 1, dsi_command);
163                 proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb,
164                         2, 2, dsi_requestid);
165                 if (dsi_code < 0) {
166                         proto_tree_add_int(dsi_tree, hf_dsi_error, tvb,
167                                 4, 4, dsi_code);
168                 }
169                 else {
170                         proto_tree_add_int(dsi_tree, hf_dsi_code, tvb,
171                                 4, 4, dsi_code);
172                 }
173                 proto_tree_add_uint_format(dsi_tree, hf_dsi_length, tvb,
174                         8, 4, dsi_length,
175                         "Length: %u bytes", dsi_length);
176                 proto_tree_add_uint(dsi_tree, hf_dsi_reserved, tvb,
177                         12, 4, dsi_reserved);
178         }
179         else 
180                 dsi_tree = tree;
181
182         if (dsi_command == DSIFUNC_CMD || dsi_command == DSIFUNC_WRITE) {
183                 tvbuff_t   *new_tvb;
184                 int len = tvb_reported_length_remaining(tvb,DSI_BLOCKSIZ);
185
186                 if (len) {
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);
193
194                         new_tvb = tvb_new_subset(tvb, DSI_BLOCKSIZ,-1,len);
195                         call_dissector(afp_handle, new_tvb, pinfo, tree);
196                 }
197         }
198         else if (tree) {        
199                 call_dissector(data_handle,tvb_new_subset(tvb, DSI_BLOCKSIZ,-1,tvb_reported_length_remaining(tvb,DSI_BLOCKSIZ)), pinfo, dsi_tree); 
200         }
201 }
202
203 static void
204 dissect_dsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
205 {
206         volatile int offset = 0;
207         int length_remaining;
208         guint32 plen;
209         int length;
210         tvbuff_t *next_tvb;
211
212         while (tvb_reported_length_remaining(tvb, offset) != 0) {
213                 length_remaining = tvb_length_remaining(tvb, offset);
214
215                 /*
216                  * Can we do reassembly?
217                  */
218                 if (dsi_desegment && pinfo->can_desegment) {
219                         /*
220                          * Yes - is the DSI header split across segment
221                          * boundaries?
222                          */
223                         if (length_remaining < 12) {
224                                 /*
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.
229                                  */
230                                 pinfo->desegment_offset = offset;
231                                 pinfo->desegment_len = 12 - length_remaining;
232                                 return;
233                         }
234                 }
235
236                 /*
237                  * Get the length of the DSI packet.
238                  */
239                 plen = tvb_get_ntohl(tvb, offset+8);
240
241                 /*
242                  * Can we do reassembly?
243                  */
244                 if (dsi_desegment && pinfo->can_desegment) {
245                         /*
246                          * Yes - is the DSI packet split across segment
247                          * boundaries?
248                          */
249                         if ((guint32)length_remaining < plen + 16) {
250                                 /*
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.
255                                  */
256                                 pinfo->desegment_offset = offset;
257                                 pinfo->desegment_len =
258                                     (plen + 16) - length_remaining;
259                                 return;
260                         }
261                 }
262
263                 /*
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.
267                  *
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"
278                  * error.
279                  */
280                 length = length_remaining;
281                 if ((guint32)length > plen + 16)
282                         length = plen + 16;
283                 next_tvb = tvb_new_subset(tvb, offset, length, plen + 16);
284
285                 /*
286                  * Dissect the DSI packet.
287                  *
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.
293                  *
294                  * If it gets a BoundsError, we can stop, as there's nothing
295                  * more to see, so we just re-throw it.
296                  */
297                 TRY {
298                         dissect_dsi_packet(next_tvb, pinfo, tree);
299                 }
300                 CATCH(BoundsError) {
301                         RETHROW;
302                 }
303                 CATCH(ReportedBoundsError) {
304                         show_reported_bounds_error(tvb, pinfo, tree);
305                 }
306                 ENDTRY;
307
308                 /*
309                  * Skip the DSI header and the payload.
310                  */
311                 offset += plen + 16;
312         }
313 }
314
315 void
316 proto_register_dsi(void)
317 {
318
319   static hf_register_info hf[] = {
320     { &hf_dsi_flags,
321       { "Flags",            "dsi.flags",
322         FT_UINT8, BASE_HEX, VALS(flag_vals), 0x0,
323         "Indicates request or reply.", HFILL }},
324
325     { &hf_dsi_command,
326       { "Command",          "dsi.command",
327         FT_UINT8, BASE_DEC, VALS(func_vals), 0x0,
328         "Represents a DSI command.", HFILL }},
329
330     { &hf_dsi_requestid,
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 }},
334
335     { &hf_dsi_code,
336       { "Data offset",      "dsi.data_offset",
337         FT_INT32, BASE_DEC, NULL, 0x0,
338         "Data offset.", HFILL }},
339
340     { &hf_dsi_error,
341       { "Error code",       "dsi.error_code",
342         FT_INT32, BASE_DEC, VALS(asp_error_vals), 0x0,
343         "Error code", HFILL }},
344
345     { &hf_dsi_length,
346       { "Length",           "dsi.length",
347         FT_UINT32, BASE_DEC, NULL, 0x0,
348         "Total length of the data that follows the DSI header.", HFILL }},
349
350     { &hf_dsi_reserved,
351       { "Reserved",         "dsi.reserved",
352         FT_UINT32, BASE_HEX, NULL, 0x0,
353         "Reserved for future use.  Should be set to zero.", HFILL }},
354
355   };
356   static gint *ett[] = {
357     &ett_dsi,
358   };
359   module_t *dsi_module;
360
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));
364
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",
369     &dsi_desegment);
370 }
371
372 void
373 proto_reg_handoff_dsi(void)
374 {
375   static dissector_handle_t dsi_handle;
376
377   dsi_handle = create_dissector_handle(dissect_dsi, proto_dsi);
378   dissector_add("tcp.port", TCP_PORT_DSI, dsi_handle);
379
380   data_handle = find_dissector("data");
381   afp_handle = find_dissector("afp");
382 }