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