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