Fix up a bunch of arguments to "dissect_ber_identifier()" to match its
[obnox/wireshark/wip.git] / epan / dissectors / packet-dsi.c
1 /* packet-dsi.c
2  * Routines for dsi packet dissection
3  * Copyright 2001, Randy McEoin <rmceoin@pe.com>
4  *
5  * $Id$
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 #include <glib.h>
35 #include <epan/packet.h>
36
37 #include <epan/prefs.h>
38 #include "packet-tcp.h"
39 #include "packet-afp.h"
40
41 /* The information in this module (DSI) comes from:
42
43   AFP 2.1 & 2.2.pdf contained in AppleShare_IP_6.3_SDK
44   available from http://www.apple.com
45
46   The netatalk source code by Wesley Craig & Adrian Sun
47
48   The Data Stream Interface description from
49   http://developer.apple.com/documentation/Networking/Conceptual/AFPClient/AFPClient-6.html
50
51  * What a Data Stream Interface packet looks like:
52  * 0                               32
53  * |-------------------------------|
54  * |flags  |command| requestID     |
55  * |-------------------------------|
56  * |error code/enclosed data offset|
57  * |-------------------------------|
58  * |total data length              |
59  * |-------------------------------|
60  * |reserved field                 |
61  * |-------------------------------|
62  */
63 #define INET6_ADDRLEN   16
64
65 static int proto_dsi = -1;
66 static int hf_dsi_flags = -1;
67 static int hf_dsi_command = -1;
68 static int hf_dsi_requestid = -1;
69 static int hf_dsi_offset = -1;
70 static int hf_dsi_error = -1;
71 static int hf_dsi_length = -1;
72 static int hf_dsi_reserved = -1;
73
74 static gint ett_dsi = -1;
75
76 static int hf_dsi_open_type     = -1;
77 static int hf_dsi_open_len      = -1;
78 static int hf_dsi_open_quantum  = -1;
79 static int hf_dsi_open_option   = -1;
80
81 static int hf_dsi_attn_flag             = -1;
82 static int hf_dsi_attn_flag_shutdown    = -1;
83 static int hf_dsi_attn_flag_crash       = -1;
84 static int hf_dsi_attn_flag_msg         = -1;
85 static int hf_dsi_attn_flag_reconnect   = -1;
86 static int hf_dsi_attn_flag_time        = -1;
87 static int hf_dsi_attn_flag_bitmap      = -1;
88
89 static gint ett_dsi_open        = -1;
90 static gint ett_dsi_attn        = -1;
91 static gint ett_dsi_attn_flag   = -1;
92
93 static const value_string dsi_attn_flag_vals[] = {
94   {0x0, "Reserved" },                                           /* 0000 */
95   {0x1, "Reserved" },                                           /* 0001 */
96   {0x2, "Server message" },                                     /* 0010 */
97   {0x3, "Server notification, cf. extended bitmap" },           /* 0011 */
98   {0x4, "Server is shutting down, internal error" },            /* 0100 */
99   {0x8, "Server is shutting down" },                            /* 1000 */
100   {0x9, "Server disconnects user" },                            /* 1001 */
101   {0x10,"Server is shutting down, message" },                   /* 1010 */
102   {0x11,"Server is shutting down, message,no reconnect"},       /* 1011 */
103   {0,                   NULL } };
104
105 static const value_string dsi_open_type_vals[] = {
106   {0,   "Server quantum" },
107   {1,   "Attention quantum" },
108   {0,                   NULL } };
109
110 /* status stuff same for asp and afp */
111 static int hf_dsi_server_name = -1;
112 static int hf_dsi_utf8_server_name_len = -1;
113 static int hf_dsi_utf8_server_name = -1;
114 static int hf_dsi_server_type = -1;
115 static int hf_dsi_server_vers = -1;
116 static int hf_dsi_server_uams = -1;
117 static int hf_dsi_server_icon = -1;
118 static int hf_dsi_server_directory = -1;
119
120 static int hf_dsi_server_flag = -1;
121 static int hf_dsi_server_flag_copyfile = -1;
122 static int hf_dsi_server_flag_passwd   = -1;
123 static int hf_dsi_server_flag_no_save_passwd = -1;
124 static int hf_dsi_server_flag_srv_msg   = -1;
125 static int hf_dsi_server_flag_srv_sig   = -1;
126 static int hf_dsi_server_flag_tcpip     = -1;
127 static int hf_dsi_server_flag_notify    = -1;
128 static int hf_dsi_server_flag_reconnect = -1;
129 static int hf_dsi_server_flag_directory = -1;
130 static int hf_dsi_server_flag_utf8_name = -1;
131 static int hf_dsi_server_flag_uuid      = -1;
132 static int hf_dsi_server_flag_fast_copy = -1;
133 static int hf_dsi_server_signature      = -1;
134
135 static int hf_dsi_server_addr_len       = -1;
136 static int hf_dsi_server_addr_type      = -1;
137 static int hf_dsi_server_addr_value     = -1;
138
139 static gint ett_dsi_status = -1;
140 static gint ett_dsi_uams   = -1;
141 static gint ett_dsi_vers   = -1;
142 static gint ett_dsi_addr   = -1;
143 static gint ett_dsi_addr_line = -1;
144 static gint ett_dsi_directory = -1;
145 static gint ett_dsi_utf8_name = -1;
146 static gint ett_dsi_status_server_flag = -1;
147
148 const value_string afp_server_addr_type_vals[] = {
149   {1,   "IP address" },
150   {2,   "IP+port address" },
151   {3,   "DDP address" },
152   {4,   "DNS name" },
153   {5,   "IP+port ssh tunnel" },
154   {6,   "IP6 address" },
155   {7,   "IP6+port address" },
156   {0,                   NULL } };
157
158 /* end status stuff */
159
160 /* desegmentation of DSI */
161 static gboolean dsi_desegment = TRUE;
162
163 static dissector_handle_t data_handle;
164 static dissector_handle_t afp_handle;
165
166 #define TCP_PORT_DSI                    548
167
168 #define DSI_BLOCKSIZ            16
169
170 /* DSI flags */
171 #define DSIFL_REQUEST    0x00
172 #define DSIFL_REPLY      0x01
173 #define DSIFL_MAX        0x01
174
175 /* DSI Commands */
176 #define DSIFUNC_CLOSE   1       /* DSICloseSession */
177 #define DSIFUNC_CMD     2       /* DSICommand */
178 #define DSIFUNC_STAT    3       /* DSIGetStatus */
179 #define DSIFUNC_OPEN    4       /* DSIOpenSession */
180 #define DSIFUNC_TICKLE  5       /* DSITickle */
181 #define DSIFUNC_WRITE   6       /* DSIWrite */
182 #define DSIFUNC_ATTN    8       /* DSIAttention */
183 #define DSIFUNC_MAX     8       /* largest command */
184
185 static const value_string flag_vals[] = {
186   {DSIFL_REQUEST,       "Request" },
187   {DSIFL_REPLY,         "Reply" },
188   {0,                   NULL } };
189
190 static const value_string func_vals[] = {
191   {DSIFUNC_CLOSE,       "CloseSession" },
192   {DSIFUNC_CMD,         "Command" },
193   {DSIFUNC_STAT,        "GetStatus" },
194   {DSIFUNC_OPEN,        "OpenSession" },
195   {DSIFUNC_TICKLE,      "Tickle" },
196   {DSIFUNC_WRITE,       "Write" },
197   {DSIFUNC_ATTN,        "Attention" },
198   {0,                   NULL } };
199
200 static gint
201 dissect_dsi_open_session(tvbuff_t *tvb, proto_tree *dsi_tree, gint offset)
202 {
203         proto_tree      *tree;
204         proto_item      *ti;
205         guint8          type;
206         guint8          len;
207
208         ti = proto_tree_add_text(dsi_tree, tvb, offset, -1, "Open Session");
209         tree = proto_item_add_subtree(ti, ett_dsi_open);
210         type = tvb_get_guint8(tvb, offset);
211         proto_tree_add_item(tree, hf_dsi_open_type, tvb, offset, 1, FALSE);
212         offset++;
213         len = tvb_get_guint8(tvb, offset);
214         proto_tree_add_item(tree, hf_dsi_open_len, tvb, offset, 1, FALSE);
215         offset++;
216         if (type <= 1) {
217                 proto_tree_add_item(tree, hf_dsi_open_quantum, tvb, offset, 4, FALSE);
218         }
219         else {
220                 proto_tree_add_item(tree, hf_dsi_open_option, tvb, offset, len, FALSE);
221         }
222         offset += len;
223         return offset;
224 }
225
226 static gint
227 dissect_dsi_attention(tvbuff_t *tvb, proto_tree *dsi_tree, gint offset)
228 {
229         proto_tree      *tree;
230         proto_item      *ti;
231         guint16         flag;
232
233         if (!tvb_reported_length_remaining(tvb,offset))
234                 return offset;
235
236         flag = tvb_get_ntohs(tvb, offset);
237         ti = proto_tree_add_text(dsi_tree, tvb, offset, -1, "Attention");
238         tree = proto_item_add_subtree(ti, ett_dsi_attn);
239
240         ti = proto_tree_add_item(tree, hf_dsi_attn_flag, tvb, offset, 2, FALSE);
241         tree = proto_item_add_subtree(ti, ett_dsi_attn_flag);
242         proto_tree_add_item(tree, hf_dsi_attn_flag_shutdown, tvb, offset, 2, FALSE);
243         proto_tree_add_item(tree, hf_dsi_attn_flag_crash, tvb, offset, 2, FALSE);
244         proto_tree_add_item(tree, hf_dsi_attn_flag_msg, tvb, offset, 2, FALSE);
245         proto_tree_add_item(tree, hf_dsi_attn_flag_reconnect, tvb, offset, 2, FALSE);
246         /* FIXME */
247         if ((flag & 0xf000) != 0x3000)
248                 proto_tree_add_item(tree, hf_dsi_attn_flag_time, tvb, offset, 2, FALSE);
249         else
250                 proto_tree_add_item(tree, hf_dsi_attn_flag_bitmap, tvb, offset, 2, FALSE);
251         offset += 2;
252         return offset;
253 }
254
255 /* -----------------------------
256         from netatalk/etc/afpd/status.c
257 */
258 static gint
259 dissect_dsi_reply_get_status(tvbuff_t *tvb, proto_tree *tree, gint offset)
260 {
261         proto_tree      *sub_tree;
262         proto_item      *ti;
263
264         guint16 ofs;
265         guint16 flag;
266         guint16 sign_ofs = 0;
267         guint16 adr_ofs = 0;
268         guint16 dir_ofs = 0;
269         guint16 utf_ofs = 0;
270         guint8  nbe;
271         guint8  len;
272         guint8  i;
273
274         if (!tree)
275                 return offset;
276
277         ti = proto_tree_add_text(tree, tvb, offset, -1, "Get Status");
278         tree = proto_item_add_subtree(ti, ett_dsi_status);
279
280         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_MACHOFF);
281         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_MACHOFF, 2, "Machine offset: %d", ofs);
282
283         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_VERSOFF);
284         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_VERSOFF, 2, "Version offset: %d", ofs);
285
286         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_UAMSOFF);
287         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_UAMSOFF, 2, "UAMS offset: %d", ofs);
288
289         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_ICONOFF);
290         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_ICONOFF, 2, "Icon offset: %d", ofs);
291
292         ofs = offset +AFPSTATUS_FLAGOFF;
293         ti = proto_tree_add_item(tree, hf_dsi_server_flag, tvb, ofs, 2, FALSE);
294         sub_tree = proto_item_add_subtree(ti, ett_dsi_status_server_flag);
295         proto_tree_add_item(sub_tree, hf_dsi_server_flag_copyfile      , tvb, ofs, 2, FALSE);
296         proto_tree_add_item(sub_tree, hf_dsi_server_flag_passwd        , tvb, ofs, 2, FALSE);
297         proto_tree_add_item(sub_tree, hf_dsi_server_flag_no_save_passwd, tvb, ofs, 2, FALSE);
298         proto_tree_add_item(sub_tree, hf_dsi_server_flag_srv_msg       , tvb, ofs, 2, FALSE);
299         proto_tree_add_item(sub_tree, hf_dsi_server_flag_srv_sig       , tvb, ofs, 2, FALSE);
300         proto_tree_add_item(sub_tree, hf_dsi_server_flag_tcpip         , tvb, ofs, 2, FALSE);
301         proto_tree_add_item(sub_tree, hf_dsi_server_flag_notify        , tvb, ofs, 2, FALSE);
302         proto_tree_add_item(sub_tree, hf_dsi_server_flag_reconnect     , tvb, ofs, 2, FALSE);
303         proto_tree_add_item(sub_tree, hf_dsi_server_flag_directory     , tvb, ofs, 2, FALSE);
304         proto_tree_add_item(sub_tree, hf_dsi_server_flag_utf8_name     , tvb, ofs, 2, FALSE);
305         proto_tree_add_item(sub_tree, hf_dsi_server_flag_uuid          , tvb, ofs, 2, FALSE);
306         proto_tree_add_item(sub_tree, hf_dsi_server_flag_fast_copy     , tvb, ofs, 2, FALSE);
307
308         proto_tree_add_item(tree, hf_dsi_server_name, tvb, offset +AFPSTATUS_PRELEN, 1, FALSE);
309
310         flag = tvb_get_ntohs(tvb, ofs);
311         if ((flag & AFPSRVRINFO_SRVSIGNATURE)) {
312                 ofs = offset +AFPSTATUS_PRELEN +tvb_get_guint8(tvb, offset +AFPSTATUS_PRELEN) +1;
313                 if ((ofs & 1))
314                         ofs++;
315
316                 sign_ofs = tvb_get_ntohs(tvb, ofs);
317                 proto_tree_add_text(tree, tvb, ofs, 2, "Signature offset: %d", sign_ofs);
318                 sign_ofs += offset;
319
320                 if ((flag & AFPSRVRINFO_TCPIP)) {
321                         ofs += 2;
322                         adr_ofs =  tvb_get_ntohs(tvb, ofs);
323                         proto_tree_add_text(tree, tvb, ofs, 2, "Network address offset: %d", adr_ofs);
324                         adr_ofs += offset;
325                 }
326
327                 if ((flag & AFPSRVRINFO_SRVDIRECTORY)) {
328                         ofs += 2;
329                         dir_ofs =  tvb_get_ntohs(tvb, ofs);
330                         proto_tree_add_text(tree, tvb, ofs, 2, "Directory services offset: %d", dir_ofs);
331                         dir_ofs += offset;
332                 }
333                 if ((flag & AFPSRVRINFO_SRVUTF8)) {
334                         ofs += 2;
335                         utf_ofs =  tvb_get_ntohs(tvb, ofs);
336                         proto_tree_add_text(tree, tvb, ofs, 2, "UTF8 server name offset: %d", utf_ofs);
337                         utf_ofs += offset;
338                 }
339         }
340
341         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_MACHOFF);
342         if (ofs)
343                 proto_tree_add_item(tree, hf_dsi_server_type, tvb, ofs, 1, FALSE);
344
345         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_VERSOFF);
346         if (ofs) {
347                 nbe = tvb_get_guint8(tvb, ofs);
348                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "Version list: %d", nbe);
349                 ofs++;
350                 sub_tree = proto_item_add_subtree(ti, ett_dsi_vers);
351                 for (i = 0; i < nbe; i++) {
352                         len = tvb_get_guint8(tvb, ofs);
353                         proto_tree_add_item(sub_tree, hf_dsi_server_vers, tvb, ofs, 1, FALSE);
354                         ofs += len + 1;
355                 }
356         }
357
358         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_UAMSOFF);
359         if (ofs) {
360                 nbe = tvb_get_guint8(tvb, ofs);
361                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "UAMS list: %d", nbe);
362                 ofs++;
363                 sub_tree = proto_item_add_subtree(ti, ett_dsi_uams);
364                 for (i = 0; i < nbe; i++) {
365                         len = tvb_get_guint8(tvb, ofs);
366                         proto_tree_add_item(sub_tree, hf_dsi_server_uams, tvb, ofs, 1, FALSE);
367                         ofs += len + 1;
368                 }
369         }
370
371         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_ICONOFF);
372         if (ofs)
373                 proto_tree_add_item(tree, hf_dsi_server_icon, tvb, ofs, 256, FALSE);
374
375         if (sign_ofs) {
376                 proto_tree_add_item(tree, hf_dsi_server_signature, tvb, sign_ofs, 16, FALSE);
377         }
378
379         if (adr_ofs) {
380                 proto_tree *adr_tree;
381                 unsigned char *tmp;
382                 const guint8 *ip;
383                 guint16 net;
384                 guint8  node;
385                 guint16 port;
386
387                 ofs = adr_ofs;
388                 nbe = tvb_get_guint8(tvb, ofs);
389                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "Address list: %d", nbe);
390                 ofs++;
391                 adr_tree = proto_item_add_subtree(ti, ett_dsi_addr);
392                 for (i = 0; i < nbe; i++) {
393                         guint8 type;
394
395                         len = tvb_get_guint8(tvb, ofs);
396                         type =  tvb_get_guint8(tvb, ofs +1);
397                         switch (type) {
398                         case 1: /* IP */
399                                 ip = tvb_get_ptr(tvb, ofs+2, 4);
400                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip: %s", ip_to_str(ip));
401                                 break;
402                         case 2: /* IP + port */
403                                 ip = tvb_get_ptr(tvb, ofs+2, 4);
404                                 port = tvb_get_ntohs(tvb, ofs+6);
405                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip %s:%d",ip_to_str(ip),port);
406                                 break;
407                         case 3: /* DDP, atalk_addr_to_str want host order not network */
408                                 net  = tvb_get_ntohs(tvb, ofs+2);
409                                 node = tvb_get_guint8(tvb, ofs +4);
410                                 port = tvb_get_guint8(tvb, ofs +5);
411                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ddp: %u.%u:%u",
412                                         net, node, port);
413                                 break;
414                         case 4: /* DNS */
415                         case 5: /* SSH tunnel */
416                                 if (len > 2) {
417                                         tmp = tvb_get_string(tvb, ofs +2, len -2);
418                                         ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "%s: %s", 
419                                                                 (type==4)?"dns":"ssh tunnel", tmp);
420                                         g_free(tmp);
421                                         break;
422                                 }
423                                 else {
424                                         ti = proto_tree_add_text(adr_tree, tvb, ofs, len,"Malformed address type %d", type);
425                                 }
426                                 break;
427                         case 6: /* IP6 */
428                                 ip = tvb_get_ptr(tvb, ofs+2, INET6_ADDRLEN);
429                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip6: %s", 
430                                                 ip6_to_str((const struct e_in6_addr *)ip));
431                                 break;
432                         case 7: /* IP6 + 2bytes port */
433                                 ip = tvb_get_ptr(tvb, ofs+2, INET6_ADDRLEN);
434                                 port = tvb_get_ntohs(tvb, ofs+ 2+INET6_ADDRLEN);
435                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip6 %s:%d",
436                                                 ip6_to_str((const struct e_in6_addr *)ip),port);
437                                 break;
438                         default:
439                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len,"Unknow type : %d", type);
440                                 break;
441                         }
442                         len -= 2;
443                         sub_tree = proto_item_add_subtree(ti,ett_dsi_addr_line);
444                         proto_tree_add_item(sub_tree, hf_dsi_server_addr_len, tvb, ofs, 1, FALSE);
445                         ofs++;
446                         proto_tree_add_item(sub_tree, hf_dsi_server_addr_type, tvb, ofs, 1, FALSE);
447                         ofs++;
448                         proto_tree_add_item(sub_tree, hf_dsi_server_addr_value,tvb, ofs, len, FALSE);
449                         ofs += len;
450                 }
451         }
452
453         if (dir_ofs) {
454                 ofs = dir_ofs;
455                 nbe = tvb_get_guint8(tvb, ofs);
456                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "Directory services list: %d", nbe);
457                 ofs++;
458                 sub_tree = proto_item_add_subtree(ti, ett_dsi_directory);
459                 for (i = 0; i < nbe; i++) {
460                         len = tvb_get_guint8(tvb, ofs);
461                         proto_tree_add_item(sub_tree, hf_dsi_server_directory, tvb, ofs, 1, FALSE);
462                         ofs += len + 1;
463                 }
464         }
465         if (utf_ofs) {
466                 guint16 ulen;
467                 char *tmp;
468
469                 ofs = utf_ofs;
470                 ulen = tvb_get_ntohs(tvb, ofs);
471                 tmp = tvb_get_string(tvb, ofs + 2, ulen);
472                 ti = proto_tree_add_text(tree, tvb, ofs, ulen + 2, "UTF8 server name: %s", tmp);
473                 sub_tree = proto_item_add_subtree(ti, ett_dsi_utf8_name);
474                 proto_tree_add_uint(sub_tree, hf_dsi_utf8_server_name_len, tvb, ofs, 2, ulen);
475                 ofs += 2;
476                 proto_tree_add_string(sub_tree, hf_dsi_utf8_server_name, tvb, ofs, ulen, tmp);
477                 ofs += ulen;
478                 g_free(tmp);
479         }
480
481         return offset;
482 }
483
484 static void
485 dissect_dsi_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
486 {
487         proto_tree      *dsi_tree;
488         proto_item      *ti;
489         guint8          dsi_flags,dsi_command;
490         guint16         dsi_requestid;
491         gint32          dsi_code;
492         guint32         dsi_length;
493         guint32         dsi_reserved;
494         struct          aspinfo aspinfo;
495         gint            col_info;
496         
497
498         if (check_col(pinfo->cinfo, COL_PROTOCOL))
499                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DSI");
500         col_info = check_col(pinfo->cinfo, COL_INFO);
501         if (col_info)
502                 col_clear(pinfo->cinfo, COL_INFO);
503
504         dsi_flags = tvb_get_guint8(tvb, 0);
505         dsi_command = tvb_get_guint8(tvb, 1);
506         dsi_requestid = tvb_get_ntohs(tvb, 2);
507         dsi_code = tvb_get_ntohl(tvb, 4);
508         dsi_length = tvb_get_ntohl(tvb, 8);
509         dsi_reserved = tvb_get_ntohl(tvb, 12);
510
511         if (col_info) {
512                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s (%u)",
513                         val_to_str(dsi_flags, flag_vals,
514                                    "Unknown flag (0x%02x)"),
515                         val_to_str(dsi_command, func_vals,
516                                    "Unknown function (0x%02x)"),
517                         dsi_requestid);
518         }
519
520
521         if (tree) {
522                 ti = proto_tree_add_item(tree, proto_dsi, tvb, 0, -1, FALSE);
523                 dsi_tree = proto_item_add_subtree(ti, ett_dsi);
524
525                 proto_tree_add_uint(dsi_tree, hf_dsi_flags, tvb,
526                         0, 1, dsi_flags);
527                 proto_tree_add_uint(dsi_tree, hf_dsi_command, tvb,
528                         1, 1, dsi_command);
529                 proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb,
530                         2, 2, dsi_requestid);
531                 switch (dsi_flags) {
532
533                 case DSIFL_REQUEST:
534                         proto_tree_add_int(dsi_tree, hf_dsi_offset, tvb,
535                                 4, 4, dsi_code);
536                         break;
537
538                 case DSIFL_REPLY:
539                         proto_tree_add_int(dsi_tree, hf_dsi_error, tvb,
540                                 4, 4, dsi_code);
541                         break;
542                 }
543                 proto_tree_add_uint_format(dsi_tree, hf_dsi_length, tvb,
544                         8, 4, dsi_length,
545                         "Length: %u bytes", dsi_length);
546                 proto_tree_add_uint(dsi_tree, hf_dsi_reserved, tvb,
547                         12, 4, dsi_reserved);
548         }
549         else
550                 dsi_tree = tree;
551         switch (dsi_command) {
552         case DSIFUNC_OPEN:
553                 if (tree) {
554                         dissect_dsi_open_session(tvb, dsi_tree, DSI_BLOCKSIZ);
555                 }
556                 break;
557         case DSIFUNC_ATTN:
558                 if (tree) {
559                         dissect_dsi_attention(tvb, dsi_tree, DSI_BLOCKSIZ);
560                 }
561                 break;
562         case DSIFUNC_STAT:
563                 if (tree && (dsi_flags == DSIFL_REPLY)) {
564                         dissect_dsi_reply_get_status(tvb, dsi_tree, DSI_BLOCKSIZ);
565                 }
566                 break;
567         case DSIFUNC_CMD:
568         case DSIFUNC_WRITE:
569                 {
570                         tvbuff_t   *new_tvb;
571                         int len = tvb_reported_length_remaining(tvb,DSI_BLOCKSIZ);
572
573                         aspinfo.reply = (dsi_flags == DSIFL_REPLY);
574                         aspinfo.command = dsi_command;
575                         aspinfo.seq = dsi_requestid;
576                         aspinfo.code = dsi_code;
577                         pinfo->private_data = &aspinfo;
578                         proto_item_set_len(dsi_tree, DSI_BLOCKSIZ);
579
580                         new_tvb = tvb_new_subset(tvb, DSI_BLOCKSIZ,-1,len);
581                         call_dissector(afp_handle, new_tvb, pinfo, tree);
582                 }
583                 break;
584         default:
585                 if (tree) {
586                         call_dissector(data_handle,
587                             tvb_new_subset(tvb, DSI_BLOCKSIZ, -1, -1),
588                             pinfo, dsi_tree);
589                 }
590                 break;
591         }
592 }
593
594 static guint
595 get_dsi_pdu_len(tvbuff_t *tvb, int offset)
596 {
597         guint32 plen;
598         guint8  dsi_flags,dsi_command;
599
600         dsi_flags = tvb_get_guint8(tvb, offset);
601         dsi_command = tvb_get_guint8(tvb, offset+ 1);
602         if ( dsi_flags > DSIFL_MAX || !dsi_command || dsi_command > DSIFUNC_MAX) 
603         {
604             /* it's not a known dsi pdu start sequence */
605             return tvb_length_remaining(tvb, offset);
606         }
607
608         /*
609          * Get the length of the DSI packet.
610          */
611         plen = tvb_get_ntohl(tvb, offset+8);
612
613         /*
614          * That length doesn't include the length of the header itself;
615          * add that in.
616          */
617         return plen + 16;
618 }
619
620 static void
621 dissect_dsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
622 {
623         tcp_dissect_pdus(tvb, pinfo, tree, dsi_desegment, 12,
624             get_dsi_pdu_len, dissect_dsi_packet);
625 }
626
627 void
628 proto_register_dsi(void)
629 {
630
631   static hf_register_info hf[] = {
632     { &hf_dsi_flags,
633       { "Flags",            "dsi.flags",
634         FT_UINT8, BASE_HEX, VALS(flag_vals), 0x0,
635         "Indicates request or reply.", HFILL }},
636
637     { &hf_dsi_command,
638       { "Command",          "dsi.command",
639         FT_UINT8, BASE_DEC, VALS(func_vals), 0x0,
640         "Represents a DSI command.", HFILL }},
641
642     { &hf_dsi_requestid,
643       { "Request ID",       "dsi.requestid",
644         FT_UINT16, BASE_DEC, NULL, 0x0,
645         "Keeps track of which request this is.  Replies must match a Request.  IDs must be generated in sequential order.", HFILL }},
646
647     { &hf_dsi_offset,
648       { "Data offset",      "dsi.data_offset",
649         FT_INT32, BASE_DEC, NULL, 0x0,
650         "Data offset", HFILL }},
651
652     { &hf_dsi_error,
653       { "Error code",       "dsi.error_code",
654         FT_INT32, BASE_DEC, VALS(asp_error_vals), 0x0,
655         "Error code", HFILL }},
656
657     { &hf_dsi_length,
658       { "Length",           "dsi.length",
659         FT_UINT32, BASE_DEC, NULL, 0x0,
660         "Total length of the data that follows the DSI header.", HFILL }},
661
662     { &hf_dsi_reserved,
663       { "Reserved",         "dsi.reserved",
664         FT_UINT32, BASE_HEX, NULL, 0x0,
665         "Reserved for future use.  Should be set to zero.", HFILL }},
666         /* asp , afp */
667     { &hf_dsi_utf8_server_name_len,
668       { "Length",          "dsi.utf8_server_name_len",
669         FT_UINT16, BASE_DEC, NULL, 0x0,
670         "UTF8 server name length.", HFILL }},
671     { &hf_dsi_utf8_server_name,
672       { "UTF8 Server name",         "dsi.utf8_server_name",
673         FT_STRING, BASE_NONE, NULL, 0x0,
674         "UTF8 Server name", HFILL }},
675
676     { &hf_dsi_server_name,
677       { "Server name",         "dsi.server_name",
678         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
679         "Server name", HFILL }},
680
681     { &hf_dsi_server_type,
682       { "Server type",         "dsi.server_type",
683         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
684         "Server type", HFILL }},
685
686     { &hf_dsi_server_vers,
687       { "AFP version",         "dsi.server_vers",
688         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
689         "AFP version", HFILL }},
690
691     { &hf_dsi_server_uams,
692       { "UAM",         "dsi.server_uams",
693         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
694         "UAM", HFILL }},
695
696     { &hf_dsi_server_icon,
697       { "Icon bitmap",         "dsi.server_icon",
698         FT_BYTES, BASE_HEX, NULL, 0x0,
699         "Server icon bitmap", HFILL }},
700
701     { &hf_dsi_server_directory,
702       { "Directory service",         "dsi.server_directory",
703         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
704         "Server directory service", HFILL }},
705
706     { &hf_dsi_server_signature,
707       { "Server signature",         "dsi.server_signature",
708         FT_BYTES, BASE_HEX, NULL, 0x0,
709         "Server signature", HFILL }},
710
711     { &hf_dsi_server_flag,
712       { "Flag",         "dsi.server_flag",
713         FT_UINT16, BASE_HEX, NULL, 0x0,
714         "Server capabilities flag", HFILL }},
715     { &hf_dsi_server_flag_copyfile,
716       { "Support copyfile",      "dsi.server_flag.copyfile",
717                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_COPY,
718         "Server support copyfile", HFILL }},
719     { &hf_dsi_server_flag_passwd,
720       { "Support change password",      "dsi.server_flag.passwd",
721                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_PASSWD,
722         "Server support change password", HFILL }},
723     { &hf_dsi_server_flag_no_save_passwd,
724       { "Don't allow save password",      "dsi.server_flag.no_save_passwd",
725                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_NOSAVEPASSWD,
726         "Don't allow save password", HFILL }},
727     { &hf_dsi_server_flag_srv_msg,
728       { "Support server message",      "dsi.server_flag.srv_msg",
729                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVMSGS,
730         "Support server message", HFILL }},
731     { &hf_dsi_server_flag_srv_sig,
732       { "Support server signature",      "dsi.server_flag.srv_sig",
733                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVSIGNATURE,
734         "Support server signature", HFILL }},
735     { &hf_dsi_server_flag_tcpip,
736       { "Support TCP/IP",      "dsi.server_flag.tcpip",
737                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_TCPIP,
738         "Server support TCP/IP", HFILL }},
739     { &hf_dsi_server_flag_notify,
740       { "Support server notifications",      "dsi.server_flag.notify",
741                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVNOTIFY,
742         "Server support notifications", HFILL }},
743     { &hf_dsi_server_flag_reconnect,
744       { "Support server reconnect",      "dsi.server_flag.reconnect",
745                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVRECONNECT,
746         "Server support reconnect", HFILL }},
747     { &hf_dsi_server_flag_directory,
748       { "Support directory services",      "dsi.server_flag.directory",
749                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVDIRECTORY,
750         "Server support directory services", HFILL }},
751     { &hf_dsi_server_flag_utf8_name,
752       { "Support UTF8 server name",      "dsi.server_flag.utf8_name",
753                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVUTF8,
754         "Server support UTF8 server name", HFILL }},
755     { &hf_dsi_server_flag_uuid,
756       { "Support UUIDs",      "dsi.server_flag.uuids",
757                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_UUID,
758         "Server supports UUIDs", HFILL }},
759     { &hf_dsi_server_flag_fast_copy,
760       { "Support fast copy",      "dsi.server_flag.fast_copy",
761                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_FASTBOZO,
762         "Server support fast copy", HFILL }},
763
764
765     { &hf_dsi_server_addr_len,
766       { "Length",          "dsi.server_addr.len",
767         FT_UINT8, BASE_DEC, NULL, 0x0,
768         "Address length.", HFILL }},
769
770     { &hf_dsi_server_addr_type,
771       { "Type",          "dsi.server_addr.type",
772         FT_UINT8, BASE_DEC, VALS(afp_server_addr_type_vals), 0x0,
773         "Address type.", HFILL }},
774
775     { &hf_dsi_server_addr_value,
776       { "Value",          "dsi.server_addr.value",
777         FT_BYTES, BASE_HEX, NULL, 0x0,
778         "Address value", HFILL }},
779
780     { &hf_dsi_open_type,
781       { "Flags",          "dsi.open_type",
782         FT_UINT8, BASE_DEC, VALS(dsi_open_type_vals), 0x0,
783         "Open session option type.", HFILL }},
784
785     { &hf_dsi_open_len,
786       { "Length",          "dsi.open_len",
787         FT_UINT8, BASE_DEC, NULL, 0x0,
788         "Open session option len", HFILL }},
789
790     { &hf_dsi_open_quantum,
791       { "Quantum",       "dsi.open_quantum",
792         FT_UINT32, BASE_DEC, NULL, 0x0,
793         "Server/Attention quantum", HFILL }},
794
795     { &hf_dsi_open_option,
796       { "Option",          "dsi.open_option",
797         FT_BYTES, BASE_HEX, NULL, 0x0,
798         "Open session options (undecoded)", HFILL }},
799
800     { &hf_dsi_attn_flag,
801       { "Flags",          "dsi.attn_flag",
802         FT_UINT16, BASE_HEX, VALS(dsi_attn_flag_vals), 0xf000,
803         "Server attention flag", HFILL }},
804     { &hf_dsi_attn_flag_shutdown,
805       { "Shutdown",      "dsi.attn_flag.shutdown",
806                 FT_BOOLEAN, 16, NULL, 1<<15,
807         "Attention flag, server is shutting down", HFILL }},
808     { &hf_dsi_attn_flag_crash,
809       { "Crash",      "dsi.attn_flag.crash",
810                 FT_BOOLEAN, 16, NULL, 1<<14,
811         "Attention flag, server crash bit", HFILL }},
812     { &hf_dsi_attn_flag_msg,
813       { "Message",      "dsi.attn_flag.msg",
814                 FT_BOOLEAN, 16, NULL, 1<<13,
815         "Attention flag, server message bit", HFILL }},
816     { &hf_dsi_attn_flag_reconnect,
817       { "Don't reconnect",      "dsi.attn_flag.reconnect",
818                 FT_BOOLEAN, 16, NULL, 1<<12,
819         "Attention flag, don't reconnect bit", HFILL }},
820     { &hf_dsi_attn_flag_time,
821      { "Minutes",          "dsi.attn_flag.time",
822         FT_UINT16, BASE_DEC, NULL, 0xfff,
823         "Number of minutes", HFILL }},
824     { &hf_dsi_attn_flag_bitmap,
825      { "Bitmap",          "dsi.attn_flag.time",
826         FT_UINT16, BASE_HEX, NULL, 0xfff,
827         "Attention extended bitmap", HFILL }},
828
829   };
830
831   static gint *ett[] = {
832     &ett_dsi,
833     &ett_dsi_open,
834     &ett_dsi_attn,
835     &ett_dsi_attn_flag,
836     /* asp afp */
837     &ett_dsi_status,
838     &ett_dsi_status_server_flag,
839     &ett_dsi_vers,
840     &ett_dsi_uams,
841     &ett_dsi_addr,
842     &ett_dsi_addr_line,
843     &ett_dsi_directory,
844     &ett_dsi_utf8_name,
845   };
846   module_t *dsi_module;
847
848   proto_dsi = proto_register_protocol("Data Stream Interface", "DSI", "dsi");
849   proto_register_field_array(proto_dsi, hf, array_length(hf));
850   proto_register_subtree_array(ett, array_length(ett));
851
852   dsi_module = prefs_register_protocol(proto_dsi, NULL);
853   prefs_register_bool_preference(dsi_module, "desegment",
854     "Reassemble DSI messages spanning multiple TCP segments",
855     "Whether the DSI dissector should reassemble messages spanning multiple TCP segments."
856     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
857     &dsi_desegment);
858 }
859
860 void
861 proto_reg_handoff_dsi(void)
862 {
863   static dissector_handle_t dsi_handle;
864
865   dsi_handle = create_dissector_handle(dissect_dsi, proto_dsi);
866   dissector_add("tcp.port", TCP_PORT_DSI, dsi_handle);
867
868   data_handle = find_dissector("data");
869   afp_handle = find_dissector("afp");
870 }