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