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