- some radcom files seem to have a different magic key than the one we
[obnox/wireshark/wip.git] / packet-atalk.c
1 /* packet-atalk.c
2  * Routines for AppleTalk packet disassembly: LLAP, DDP, NBP, ATP, ASP,
3  * RTMP.
4  *
5  * $Id: packet-atalk.c,v 1.84 2002/11/28 03:57:49 guy Exp $
6  *
7  * Simon Wilkinson <sxw@dcs.ed.ac.uk>
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
11  * Copyright 1998
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 #include <string.h>
35
36 #include "etypes.h"
37 #include "ppptypes.h"
38 #include "aftypes.h"
39 #include <epan/atalk-utils.h>
40 #include <epan/conversation.h>
41
42 #include "prefs.h"
43 #include "reassemble.h"
44
45 #include "packet-afp.h"
46
47 /* Tables for reassembly of fragments. */
48 static GHashTable *atp_fragment_table = NULL;
49 static GHashTable *atp_reassembled_table = NULL;
50
51 /* desegmentation of ATP */
52 static gboolean atp_defragment = TRUE;
53
54 static dissector_handle_t afp_handle;
55
56 static int proto_llap = -1;
57 static int hf_llap_dst = -1;
58 static int hf_llap_src = -1;
59 static int hf_llap_type = -1;
60
61 static int proto_ddp = -1;
62 static int hf_ddp_hopcount = -1;
63 static int hf_ddp_len = -1;
64 static int hf_ddp_checksum = -1;
65 static int hf_ddp_dst = -1;
66 static int hf_ddp_dst_net = -1;
67 static int hf_ddp_src = -1;
68 static int hf_ddp_src_net = -1;
69 static int hf_ddp_dst_node = -1;
70 static int hf_ddp_src_node = -1;
71 static int hf_ddp_dst_socket = -1;
72 static int hf_ddp_src_socket = -1;
73 static int hf_ddp_type = -1;
74
75
76 /* --------------------------------------
77  * ATP protocol parameters
78  * from netatalk/include/atalk/atp.h
79  */
80 #define ATP_MAXDATA     (578+4)         /* maximum ATP data size */
81 #define ATP_BUFSIZ      587             /* maximum packet size */
82 #define ATP_HDRSIZE     5               /* includes DDP type field */
83
84 #define ATP_TRELMASK    0x07            /* mask all but TREL */
85 #define ATP_RELTIME     30              /* base release timer (in secs) */
86
87 #define ATP_TREL30      0x0             /* release time codes */
88 #define ATP_TREL1M      0x1             /* these are passed in flags of */
89 #define ATP_TREL2M      0x2             /* atp_sreq call, and set in the */
90 #define ATP_TREL4M      0x3             /* packet control info. */
91 #define ATP_TREL8M      0x4
92
93 /* flags for ATP options (and control byte)
94 */
95 #define ATP_XO          0x20 /* (1<<5)          eXactly Once mode */
96 #define ATP_EOM         0x10 /* (1<<4)          End Of Message */
97 #define ATP_STS         0x08 /* (1<<3)          Transaction Status */
98
99 /* function codes
100 */
101 #define ATP_FUNCMASK    (3<<6)          /* mask all but function */
102
103 #define ATP_TREQ        1 /* (1<<6)        Trans. REQuest */
104 #define ATP_TRESP       2 /* (2<<6)        Trans. RESPonse */
105 #define ATP_TREL        3 /* (3<<6)        Trans. RELease */
106
107 /* ------------------------- */
108 static dissector_handle_t asp_handle;
109
110 static int proto_atp = -1;
111 static int hf_atp_ctrlinfo  = -1; /* guint8_t    control information */
112 static int hf_atp_function  = -1; /* bits 7,6    function */
113 static int hf_atp_xo        = -1; /* bit 5       exactly-once */
114 static int hf_atp_eom       = -1; /* bit 4       end-of-message */
115 static int hf_atp_sts       = -1; /* bit 3       send transaction status */
116 static int hf_atp_treltimer = -1; /* bits 2,1,0  TRel timeout indicator */
117
118 static int hf_atp_bitmap = -1;   /* guint8_t  bitmap or sequence number */
119 static int hf_atp_tid = -1;      /* guint16_t transaction id. */
120 static int hf_atp_user_bytes = -1;
121
122 static int hf_atp_segments = -1;
123 static int hf_atp_segment = -1;
124 static int hf_atp_segment_overlap = -1;
125 static int hf_atp_segment_overlap_conflict = -1;
126 static int hf_atp_segment_multiple_tails = -1;
127 static int hf_atp_segment_too_long_segment = -1;
128 static int hf_atp_segment_error = -1;
129
130 /* ------------------------- */
131 static int proto_zip = -1;
132 static dissector_handle_t zip_atp_handle;
133
134 static int hf_zip_function = -1;
135 static int hf_zip_atp_function = -1;
136 static int hf_zip_start_index = -1;
137 static int hf_zip_count = -1;
138 static int hf_zip_zero_value    = -1;
139
140 static int hf_zip_network_count = -1;
141 static int hf_zip_network = -1;
142 static int hf_zip_network_start = -1;
143 static int hf_zip_network_end = -1;
144
145 static int hf_zip_flags = -1;
146
147 static int hf_zip_flags_zone_invalid  = -1;
148 static int hf_zip_flags_use_broadcast = -1;
149 static int hf_zip_flags_only_one_zone = -1;
150
151 static int hf_zip_last_flag = -1;
152
153 static int hf_zip_zone_name    = -1;
154 static int hf_zip_default_zone = -1;
155
156 static int hf_zip_multicast_length  = -1;
157 static int hf_zip_multicast_address = -1;
158
159 static const value_string zip_function_vals[] = {
160   {1, "Query"},
161   {2, "Reply"},
162   {5, "GetNetInfo request"},
163   {6, "GetNetInfo reply"},
164   {7, "notify"},
165   {8, "Extended reply"},
166   {0, NULL}
167 };
168
169 static const value_string zip_atp_function_vals[] = {
170   {7, "GetMyZone"},
171   {8, "GetZoneList"},
172   {9, "GetLocalZones"},
173   {0, NULL}
174 };
175
176 static gint ett_zip              = -1;
177 static gint ett_zip_flags        = -1;
178 static gint ett_zip_zones_list   = -1;
179 static gint ett_zip_network_list = -1;
180
181 /* --------------------------------
182  * from netatalk/include/atalk/ats.h
183  */
184
185 #define ASPFUNC_CLOSE   1
186 #define ASPFUNC_CMD     2
187 #define ASPFUNC_STAT    3
188 #define ASPFUNC_OPEN    4
189 #define ASPFUNC_TICKLE  5
190 #define ASPFUNC_WRITE   6
191 #define ASPFUNC_WRTCONT 7
192 #define ASPFUNC_ATTN    8
193
194 #define ASP_HDRSIZ      4
195 #define ASPERR_OK       0x0000
196 #define ASPERR_BADVERS  0xfbd6
197 #define ASPERR_BUFSMALL 0xfbd5
198 #define ASPERR_NOSESS   0xfbd4
199 #define ASPERR_NOSERV   0xfbd3
200 #define ASPERR_PARM     0xfbd2
201 #define ASPERR_SERVBUSY 0xfbd1
202 #define ASPERR_SESSCLOS 0xfbd0
203 #define ASPERR_SIZERR   0xfbcf
204 #define ASPERR_TOOMANY  0xfbce
205 #define ASPERR_NOACK    0xfbcd
206
207 static int proto_asp = -1;
208 static int hf_asp_func = -1;
209 static int hf_asp_error = -1;
210 static int hf_asp_socket        = -1;
211 static int hf_asp_version       = -1;
212 static int hf_asp_session_id    = -1;
213 static int hf_asp_zero_value    = -1;
214 static int hf_asp_init_error    = -1;
215 static int hf_asp_attn_code     = -1;
216 static int hf_asp_seq           = -1;
217 static int hf_asp_size          = -1;
218
219 /* status stuff same for asp and afp */
220 static int hf_asp_server_name = -1;
221 static int hf_asp_server_type = -1;
222 static int hf_asp_server_vers = -1;
223 static int hf_asp_server_uams = -1;
224 static int hf_asp_server_icon = -1;
225 static int hf_asp_server_directory = -1;
226
227 static int hf_asp_server_flag = -1;
228 static int hf_asp_server_flag_copyfile = -1;
229 static int hf_asp_server_flag_passwd   = -1;
230 static int hf_asp_server_flag_no_save_passwd = -1;
231 static int hf_asp_server_flag_srv_msg   = -1;
232 static int hf_asp_server_flag_srv_sig   = -1;
233 static int hf_asp_server_flag_tcpip     = -1;
234 static int hf_asp_server_flag_notify    = -1;
235 static int hf_asp_server_flag_reconnect = -1;
236 static int hf_asp_server_flag_directory = -1;
237 static int hf_asp_server_flag_utf8_name = -1;
238 static int hf_asp_server_flag_fast_copy = -1;
239 static int hf_asp_server_signature      = -1;
240 static int hf_asp_server_utf8_name_len  = -1;
241 static int hf_asp_server_utf8_name      = -1;
242
243 static int hf_asp_server_addr_len       = -1;
244 static int hf_asp_server_addr_type      = -1;
245 static int hf_asp_server_addr_value     = -1;
246
247 static gint ett_asp_status = -1;
248 static gint ett_asp_uams   = -1;
249 static gint ett_asp_vers   = -1;
250 static gint ett_asp_addr   = -1;
251 static gint ett_asp_addr_line = -1;
252 static gint ett_asp_directory = -1;
253 static gint ett_asp_status_server_flag = -1;
254
255 static guint asp_packet_init_count = 200;
256
257 typedef struct {
258         guint32 conversation;
259         guint8  src[4];
260         guint16 seq;
261 } asp_request_key;
262
263 typedef struct {
264         guint8  value;  /* command for asp, bitmap for atp */
265 } asp_request_val;
266
267 static GHashTable *asp_request_hash = NULL;
268 static GMemChunk *asp_request_keys = NULL;
269 static GMemChunk *asp_request_vals = NULL;
270
271 /* Hash Functions */
272 static gint  asp_equal (gconstpointer v, gconstpointer v2)
273 {
274         const asp_request_key *val1 = (const asp_request_key*)v;
275         const asp_request_key *val2 = (const asp_request_key*)v2;
276
277         if (val1->conversation == val2->conversation &&
278                         val1->seq == val2->seq &&
279                         !memcmp(val1->src, val2->src, 4)) {
280                 return 1;
281         }
282         return 0;
283 }
284
285 static guint asp_hash  (gconstpointer v)
286 {
287         const asp_request_key *asp_key = (const asp_request_key*)v;
288         return asp_key->seq;
289 }
290
291 /* ------------------------------------ */
292 static GHashTable *atp_request_hash = NULL;
293 static GMemChunk *atp_request_keys = NULL;
294 static GMemChunk *atp_request_vals = NULL;
295
296
297 /* ------------------------------------ */
298 static int proto_nbp = -1;
299 static int hf_nbp_op = -1;
300 static int hf_nbp_info = -1;
301 static int hf_nbp_count = -1;
302 static int hf_nbp_tid = -1;
303
304 static int hf_nbp_node_net = -1;
305 static int hf_nbp_node_port = -1;
306 static int hf_nbp_node_node = -1;
307 static int hf_nbp_node_enum = -1;
308 static int hf_nbp_node_object = -1;
309 static int hf_nbp_node_type = -1;
310 static int hf_nbp_node_zone = -1;
311
312 static int proto_rtmp = -1;
313 static int hf_rtmp_net = -1;
314 static int hf_rtmp_node_len = -1;
315 static int hf_rtmp_node = -1;
316 static int hf_rtmp_tuple_net = -1;
317 static int hf_rtmp_tuple_range_start = -1;
318 static int hf_rtmp_tuple_range_end = -1;
319 static int hf_rtmp_tuple_dist = -1;
320 static int hf_rtmp_function = -1;
321
322 static gint ett_atp = -1;
323
324 static gint ett_atp_segments = -1;
325 static gint ett_atp_segment = -1;
326 static gint ett_atp_info = -1;
327 static gint ett_asp = -1;
328
329 static gint ett_nbp = -1;
330 static gint ett_nbp_info = -1;
331 static gint ett_nbp_node = -1;
332 static gint ett_rtmp = -1;
333 static gint ett_rtmp_tuple = -1;
334 static gint ett_ddp = -1;
335 static gint ett_llap = -1;
336 static gint ett_pstring = -1;
337
338 static const fragment_items atp_frag_items = {
339         &ett_atp_segment,
340         &ett_atp_segments,
341         &hf_atp_segments,
342         &hf_atp_segment,
343         &hf_atp_segment_overlap,
344         &hf_atp_segment_overlap_conflict,
345         &hf_atp_segment_multiple_tails,
346         &hf_atp_segment_too_long_segment,
347         &hf_atp_segment_error,
348         "segments"
349 };
350
351 static dissector_table_t ddp_dissector_table;
352
353 static dissector_handle_t data_handle;
354
355 #define DDP_SHORT_HEADER_SIZE 5
356
357 /*
358  * P = Padding, H = Hops, L = Len
359  *
360  * PPHHHHLL LLLLLLLL
361  *
362  * Assumes the argument is in host byte order.
363  */
364 #define ddp_hops(x)     ( ( x >> 10) & 0x3C )
365 #define ddp_len(x)              ( x & 0x03ff )
366 typedef struct _e_ddp {
367   guint16       hops_len; /* combines pad, hops, and len */
368   guint16       sum,dnet,snet;
369   guint8        dnode,snode;
370   guint8        dport,sport;
371   guint8        type;
372 } e_ddp;
373
374 #define DDP_HEADER_SIZE 13
375
376
377 static const value_string op_vals[] = {
378   {DDP_RTMPDATA, "AppleTalk Routing Table response or data" },
379   {DDP_NBP, "AppleTalk Name Binding Protocol packet"},
380   {DDP_ATP, "AppleTalk Transaction Protocol packet"},
381   {DDP_AEP, "AppleTalk Echo Protocol packet"},
382   {DDP_RTMPREQ, "AppleTalk Routing Table request"},
383   {DDP_ZIP, "AppleTalk Zone Information Protocol packet"},
384   {DDP_ADSP, "AppleTalk Data Stream Protocol"},
385   {DDP_EIGRP, "Cisco EIGRP for AppleTalk"},
386   {0, NULL}
387 };
388
389 static const value_string rtmp_function_vals[] = {
390   {1, "Request"},
391   {2, "Route Data Request (split horizon processed)"},
392   {3, "Route Data Request (no split horizon processing)"},
393   {0, NULL}
394 };
395
396 #define NBP_BROADCAST 1
397 #define NBP_LOOKUP 2
398 #define NBP_FORWARD 4
399 #define NBP_REPLY 3
400
401 static const value_string nbp_op_vals[] = {
402   {NBP_BROADCAST, "broadcast request"},
403   {NBP_LOOKUP, "lookup"},
404   {NBP_FORWARD, "forward request"},
405   {NBP_REPLY, "reply"},
406   {0, NULL}
407 };
408
409 static const value_string atp_function_vals[] = {
410   {ATP_TREQ        ,"REQuest"},
411   {ATP_TRESP       ,"RESPonse"},
412   {ATP_TREL        ,"RELease"},
413   {0, NULL}
414 };
415
416 static const value_string atp_trel_timer_vals[] = {
417   {0, "30 seconds"},
418   {1, "1 minute"},
419   {2, "2 minutes"},
420   {3, "4 minutes"},
421   {4, "8 minutes"},
422   {0, NULL}
423 };
424
425 /*
426 */
427 static const value_string asp_func_vals[] = {
428   {ASPFUNC_CLOSE,       "CloseSession" },
429   {ASPFUNC_CMD,         "Command" },
430   {ASPFUNC_STAT,        "GetStatus" },
431   {ASPFUNC_OPEN,        "OpenSession" },
432   {ASPFUNC_TICKLE,      "Tickle" },
433   {ASPFUNC_WRITE,       "Write" },
434   {ASPFUNC_WRTCONT,     "Write Cont" },
435   {ASPFUNC_ATTN,        "Attention" },
436   {0,                   NULL } };
437
438 const value_string asp_error_vals[] = {
439   {AFP_OK               , "success"},
440   {AFPERR_ACCESS        , "permission denied" },
441   {AFPERR_AUTHCONT      , "logincont" },
442   {AFPERR_BADUAM        , "uam doesn't exist" },
443   {AFPERR_BADVERS       , "bad afp version number" },
444   {AFPERR_BITMAP        , "invalid bitmap" },
445   {AFPERR_CANTMOVE      , "can't move file" },
446   {AFPERR_DENYCONF      , "file synchronization locks conflict" },
447   {AFPERR_DIRNEMPT      , "directory not empty" },
448   {AFPERR_DFULL         , "disk full" },
449   {AFPERR_EOF           , "end of file" },
450   {AFPERR_BUSY          , "FileBusy" },
451   {AFPERR_FLATVOL       , "volume doesn't support directories" },
452   {AFPERR_NOITEM        , "ItemNotFound" },
453   {AFPERR_LOCK          , "LockErr" },
454   {AFPERR_MISC          , "misc. err" },
455   {AFPERR_NLOCK         , "no more locks" },
456   {AFPERR_NOSRVR        , "no response by server at that address" },
457   {AFPERR_EXIST         , "object already exists" },
458   {AFPERR_NOOBJ         , "object not found" },
459   {AFPERR_PARAM         , "parameter error" },
460   {AFPERR_NORANGE       , "no range lock" },
461   {AFPERR_RANGEOVR      , "range overlap" },
462   {AFPERR_SESSCLOS      , "session closed" },
463   {AFPERR_NOTAUTH       , "user not authenticated" },
464   {AFPERR_NOOP          , "command not supported" },
465   {AFPERR_BADTYPE       , "object is the wrong type" },
466   {AFPERR_NFILE         , "too many files open" },
467   {AFPERR_SHUTDOWN      , "server is going down" },
468   {AFPERR_NORENAME      , "can't rename" },
469   {AFPERR_NODIR         , "couldn't find directory" },
470   {AFPERR_ITYPE         , "wrong icon type" },
471   {AFPERR_VLOCK         , "volume locked" },
472   {AFPERR_OLOCK         , "object locked" },
473   {AFPERR_CTNSHRD       , "share point contains a share point" },
474   {AFPERR_NOID          , "file thread not found" },
475   {AFPERR_EXISTID       , "file already has an id" },
476   {AFPERR_DIFFVOL       , "different volume" },
477   {AFPERR_CATCHNG       , "catalog has changed" },
478   {AFPERR_SAMEOBJ       , "source file == destination file" },
479   {AFPERR_BADID         , "non-existent file id" },
480   {AFPERR_PWDSAME       , "same password/can't change password" },
481   {AFPERR_PWDSHORT      , "password too short" },
482   {AFPERR_PWDEXPR       , "password expired" },
483   {AFPERR_INSHRD        , "folder being shared is inside a shared folder." },
484   {AFPERR_INTRASH   , "shared folder in trash." },
485   {AFPERR_PWDCHNG   , "password needs to be changed" },
486   {AFPERR_PWDPOLCY  , "password fails policy check" },
487   {AFPERR_USRLOGIN  , "user already logged on" },
488   {0,                   NULL } };
489
490 /*
491  * XXX - do this with an FT_UINT_STRING?
492  * Unfortunately, you can't extract from an FT_UINT_STRING the string,
493  * which we'd want to do in order to put it into the "Data:" portion.
494  *
495  * Are these always in the Mac extended character set?
496  */
497 static int dissect_pascal_string(tvbuff_t *tvb, int offset, proto_tree *tree,
498         int hf_index)
499 {
500         int len;
501
502         len = tvb_get_guint8(tvb, offset);
503         offset++;
504
505         if ( tree )
506         {
507                 char *tmp;
508                 proto_tree *item;
509                 proto_tree *subtree;
510
511                 /*
512                  * XXX - if we could do this inside the protocol tree
513                  * code, we could perhaps avoid allocating and freeing
514                  * this string buffer.
515                  */
516                 tmp = g_malloc( len+1 );
517                 tvb_memcpy(tvb, tmp, offset, len);
518                 tmp[len] = 0;
519                 item = proto_tree_add_string(tree, hf_index, tvb, offset-1, len+1, tmp);
520
521                 subtree = proto_item_add_subtree(item, ett_pstring);
522                 proto_tree_add_text(subtree, tvb, offset-1, 1, "Length: %d", len);
523                 proto_tree_add_text(subtree, tvb, offset, len, "Data: %s", tmp);
524
525                 g_free(tmp);
526         }
527         offset += len;
528
529         return offset;
530 }
531
532 static void
533 dissect_rtmp_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
534   proto_tree *rtmp_tree;
535   proto_item *ti;
536   guint8 function;
537
538   if (check_col(pinfo->cinfo, COL_PROTOCOL))
539     col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMP");
540   if (check_col(pinfo->cinfo, COL_INFO))
541     col_clear(pinfo->cinfo, COL_INFO);
542
543   function = tvb_get_guint8(tvb, 0);
544
545   if (check_col(pinfo->cinfo, COL_INFO))
546     col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
547         val_to_str(function, rtmp_function_vals, "Unknown function (%02x)"));
548
549   if (tree) {
550     ti = proto_tree_add_item(tree, proto_rtmp, tvb, 0, 1, FALSE);
551     rtmp_tree = proto_item_add_subtree(ti, ett_rtmp);
552
553     proto_tree_add_uint(rtmp_tree, hf_rtmp_function, tvb, 0, 1, function);
554   }
555 }
556
557 static void
558 dissect_rtmp_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
559   proto_tree *rtmp_tree;
560   proto_item *ti;
561   int offset = 0;
562   guint16 net;
563   guint8 nodelen,nodelen_bits;
564   guint16 node; /* might be more than 8 bits */
565   int i;
566
567   if (check_col(pinfo->cinfo, COL_PROTOCOL))
568     col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMP");
569   if (check_col(pinfo->cinfo, COL_INFO))
570     col_clear(pinfo->cinfo, COL_INFO);
571
572   net = tvb_get_ntohs(tvb, offset);
573   nodelen_bits = tvb_get_guint8(tvb, offset+2);
574   if ( nodelen_bits <= 8 ) {
575     node = tvb_get_guint8(tvb, offset)+1;
576     nodelen = 1;
577   } else {
578     node = tvb_get_ntohs(tvb, offset);
579     nodelen = 2;
580   }
581
582   if (check_col(pinfo->cinfo, COL_INFO))
583     col_add_fstr(pinfo->cinfo, COL_INFO, "Net: %u  Node Len: %u  Node: %u",
584                 net, nodelen_bits, node);
585
586   if (tree) {
587     ti = proto_tree_add_item(tree, proto_rtmp, tvb, offset, -1, FALSE);
588     rtmp_tree = proto_item_add_subtree(ti, ett_rtmp);
589
590     proto_tree_add_uint(rtmp_tree, hf_rtmp_net, tvb, offset, 2, net);
591     proto_tree_add_uint(rtmp_tree, hf_rtmp_node_len, tvb, offset+2, 1,
592                         nodelen_bits);
593     proto_tree_add_uint(rtmp_tree, hf_rtmp_node, tvb, offset+3, nodelen,
594                         node);
595     offset += 3 + nodelen;
596
597     i = 1;
598     while (tvb_offset_exists(tvb, offset)) {
599       proto_tree *tuple_item, *tuple_tree;
600       guint16 tuple_net;
601       guint8 tuple_dist;
602       guint16 tuple_range_end;
603
604       tuple_net = tvb_get_ntohs(tvb, offset);
605       tuple_dist = tvb_get_guint8(tvb, offset+2);
606
607       if (tuple_dist & 0x80) {
608         tuple_range_end = tvb_get_ntohs(tvb, offset+3);
609         tuple_item = proto_tree_add_text(rtmp_tree, tvb, offset, 6,
610                         "Tuple %d:  Range Start: %u  Dist: %u  Range End: %u",
611                         i, tuple_net, tuple_dist&0x7F, tuple_range_end);
612       } else {
613         tuple_item = proto_tree_add_text(rtmp_tree, tvb, offset, 3,
614                         "Tuple %d:  Net: %u  Dist: %u",
615                         i, tuple_net, tuple_dist);
616       }
617       tuple_tree = proto_item_add_subtree(tuple_item, ett_rtmp_tuple);
618
619       if (tuple_dist & 0x80) {
620         proto_tree_add_uint(tuple_tree, hf_rtmp_tuple_range_start, tvb, offset, 2,
621                         tuple_net);
622       } else {
623         proto_tree_add_uint(tuple_tree, hf_rtmp_tuple_net, tvb, offset, 2,
624                         tuple_net);
625       }
626       proto_tree_add_uint(tuple_tree, hf_rtmp_tuple_dist, tvb, offset+2, 1,
627                         tuple_dist & 0x7F);
628
629       if (tuple_dist & 0x80) {
630         /*
631          * Extended network tuple.
632          */
633         proto_tree_add_item(tuple_tree, hf_rtmp_tuple_range_end, tvb, offset+3, 2,
634                                 FALSE);
635         offset += 6;
636       } else
637         offset += 3;
638
639       i++;
640     }
641   }
642 }
643
644 static void
645 dissect_nbp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
646   proto_tree *nbp_tree;
647   proto_tree *nbp_info_tree;
648   proto_item *ti, *info_item;
649   int offset = 0;
650   guint8 info;
651   guint op, count;
652   unsigned int i;
653
654   if (check_col(pinfo->cinfo, COL_PROTOCOL))
655     col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBP");
656   if (check_col(pinfo->cinfo, COL_INFO))
657     col_clear(pinfo->cinfo, COL_INFO);
658
659   info = tvb_get_guint8(tvb, offset);
660   op = info >> 4;
661   count = info & 0x0F;
662
663   if (check_col(pinfo->cinfo, COL_INFO))
664     col_add_fstr(pinfo->cinfo, COL_INFO, "Op: %s  Count: %u",
665       val_to_str(op, nbp_op_vals, "Unknown (0x%01x)"), count);
666
667   if (tree) {
668     ti = proto_tree_add_item(tree, proto_nbp, tvb, offset, -1, FALSE);
669     nbp_tree = proto_item_add_subtree(ti, ett_nbp);
670
671     info_item = proto_tree_add_uint_format(nbp_tree, hf_nbp_info, tvb, offset, 1,
672                 info,
673                 "Info: 0x%01X  Operation: %s  Count: %u", info,
674                 val_to_str(op, nbp_op_vals, "Unknown (0x%01X)"),
675                 count);
676     nbp_info_tree = proto_item_add_subtree(info_item, ett_nbp_info);
677     proto_tree_add_uint(nbp_info_tree, hf_nbp_op, tvb, offset, 1, info);
678     proto_tree_add_uint(nbp_info_tree, hf_nbp_count, tvb, offset, 1, info);
679     proto_tree_add_item(nbp_tree, hf_nbp_tid, tvb, offset+1, 1, FALSE);
680     offset += 2;
681
682     for (i=0; i<count; i++) {
683       proto_tree *node_item,*node_tree;
684       int soffset = offset;
685
686       node_item = proto_tree_add_text(nbp_tree, tvb, offset, -1,
687                         "Node %u", i+1);
688       node_tree = proto_item_add_subtree(node_item, ett_nbp_node);
689
690       proto_tree_add_item(node_tree, hf_nbp_node_net, tvb, offset, 2, FALSE);
691       offset += 2;
692       proto_tree_add_item(node_tree, hf_nbp_node_node, tvb, offset, 1, FALSE);
693       offset++;
694       proto_tree_add_item(node_tree, hf_nbp_node_port, tvb, offset, 1, FALSE);
695       offset++;
696       proto_tree_add_item(node_tree, hf_nbp_node_enum, tvb, offset, 1, FALSE);
697       offset++;
698
699       offset = dissect_pascal_string(tvb, offset, node_tree, hf_nbp_node_object);
700       offset = dissect_pascal_string(tvb, offset, node_tree, hf_nbp_node_type);
701       offset = dissect_pascal_string(tvb, offset, node_tree, hf_nbp_node_zone);
702
703       proto_item_set_len(node_item, offset-soffset);
704     }
705   }
706
707   return;
708 }
709
710 /* -----------------------------
711    ATP protocol cf. inside appletalk chap. 9
712    desegmentation from packet-ieee80211.c
713 */
714 static void
715 dissect_atp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
716   proto_tree *atp_tree = NULL;
717   proto_item *ti;
718   proto_tree *atp_info_tree;
719   proto_item *info_item;
720   int offset = 0;
721   guint8 ctrlinfo;
722   guint8 frag_number = 0;
723   guint op;
724   guint16 tid;
725   guint8 query;
726   struct aspinfo aspinfo;
727   tvbuff_t   *new_tvb = NULL;
728   gboolean save_fragmented;
729   gboolean more_fragment = FALSE;
730   int len;
731   guint8 bitmap;
732   guint8 nbe = 0;
733   guint8 t = 0;
734   conversation_t        *conversation;
735   asp_request_key request_key, *new_request_key;
736   asp_request_val *request_val;
737
738   if (check_col(pinfo->cinfo, COL_PROTOCOL))
739     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATP");
740
741   ctrlinfo = tvb_get_guint8(tvb, offset);
742   bitmap   = tvb_get_guint8(tvb, offset +1);
743   tid      = tvb_get_ntohs(tvb, offset +2);
744
745   t = bitmap;
746   while(t) {
747         nbe++;
748         t >>= 1;
749   }
750
751   op = ctrlinfo >> 6;
752
753   aspinfo.reply   = (0x80 == (ctrlinfo & ATP_FUNCMASK))?1:0;
754   aspinfo.release = (0xC0 == (ctrlinfo & ATP_FUNCMASK))?1:0;
755   aspinfo.seq = tid;
756   aspinfo.code = 0;
757   query = (!aspinfo.reply && !aspinfo.release);
758
759   conversation = find_conversation(&pinfo->src, &pinfo->dst, pinfo->ptype,
760                 pinfo->srcport, pinfo->destport, 0);
761
762   if (conversation == NULL)
763   {
764         conversation = conversation_new(&pinfo->src, &pinfo->dst,
765                         pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
766   }
767
768   request_key.conversation = conversation->index;
769   memcpy(request_key.src, (!aspinfo.reply)?pinfo->src.data:pinfo->dst.data, 4);
770   request_key.seq = aspinfo.seq;
771
772   request_val = (asp_request_val *) g_hash_table_lookup(atp_request_hash, &request_key);
773
774   if (!request_val && query )  {
775          new_request_key = g_mem_chunk_alloc(atp_request_keys);
776          *new_request_key = request_key;
777
778          request_val = g_mem_chunk_alloc(atp_request_vals);
779          request_val->value = nbe;
780
781          g_hash_table_insert(atp_request_hash, new_request_key,request_val);
782   }
783
784   /*
785      ATP_EOM is not mandatory. Some implementations don't always set it
786      if the query is only one packet.
787
788      So it needs to keep the number of packets asked in request.
789     */
790
791   if (aspinfo.reply) {
792      more_fragment = !((ATP_EOM & ctrlinfo) || (request_val && 1 == request_val->value));
793      frag_number = bitmap;
794   }
795
796   if (check_col(pinfo->cinfo, COL_INFO)) {
797     col_clear(pinfo->cinfo, COL_INFO);
798     col_add_fstr(pinfo->cinfo, COL_INFO, "%s transaction %u",
799         val_to_str(op, atp_function_vals, "Unknown (0x%01x)"),tid);
800     if (more_fragment)
801         col_append_fstr(pinfo->cinfo, COL_INFO, " [fragment]");
802   }
803
804   if (tree) {
805     ti = proto_tree_add_item(tree, proto_atp, tvb, offset, -1, FALSE);
806     atp_tree = proto_item_add_subtree(ti, ett_atp);
807     proto_item_set_len(atp_tree, aspinfo.release?8:ATP_HDRSIZE -1);
808
809     info_item = proto_tree_add_item(atp_tree, hf_atp_ctrlinfo, tvb, offset, 1, FALSE);
810     atp_info_tree = proto_item_add_subtree(info_item, ett_atp_info);
811
812     proto_tree_add_item(atp_info_tree, hf_atp_function, tvb, offset, 1, FALSE);
813     proto_tree_add_item(atp_info_tree, hf_atp_xo, tvb, offset, 1, FALSE);
814     proto_tree_add_item(atp_info_tree, hf_atp_eom, tvb, offset, 1, FALSE);
815     proto_tree_add_item(atp_info_tree, hf_atp_sts, tvb, offset, 1, FALSE);
816     if ((ctrlinfo & (ATP_FUNCMASK|ATP_XO)) == (0x40|ATP_XO)) {
817       /* TReq with XO set */
818       proto_tree_add_item(atp_info_tree, hf_atp_treltimer, tvb, offset, 1, FALSE);
819     }
820     if (query) {
821       proto_tree_add_text(atp_tree, tvb, offset +1, 1,
822                           "Bitmap: 0x%02x  %u packet(s) max", bitmap, nbe);
823     }
824     else {
825       proto_tree_add_item(atp_tree, hf_atp_bitmap, tvb, offset +1, 1, FALSE);
826     }
827     proto_tree_add_item(atp_tree, hf_atp_tid, tvb, offset +2, 2, FALSE);
828
829     if (aspinfo.release)
830         proto_tree_add_item(atp_tree, hf_atp_user_bytes, tvb, offset +4, 4, FALSE);
831
832   }
833
834   if (aspinfo.release)
835         return;
836
837   save_fragmented = pinfo->fragmented;
838
839   /* FIXME
840      asp doesn't fit very well here
841      move asp back in atp?
842   */
843   if (atp_defragment && aspinfo.reply && (more_fragment || frag_number != 0)) {
844      fragment_data *fd_head;
845      int hdr;
846
847      hdr = ATP_HDRSIZE -1;
848      if (frag_number != 0)
849         hdr += 4;       /* asp header */
850      len = tvb_length_remaining(tvb, hdr);
851      fd_head = fragment_add_seq_check(tvb, hdr, pinfo, tid,
852                                      atp_fragment_table,
853                                      atp_reassembled_table,
854                                      frag_number,
855                                      len,
856                                      more_fragment);
857      if (fd_head != NULL) {
858         if (fd_head->next != NULL) {
859             new_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
860             tvb_set_child_real_data_tvbuff(tvb, new_tvb);
861             add_new_data_source(pinfo, new_tvb, "Reassembled ATP");
862             /* Show all fragments. */
863             if (tree) {
864                     show_fragment_seq_tree(fd_head, &atp_frag_items,
865                         atp_tree, pinfo, new_tvb);
866             }
867         }
868         else
869             new_tvb = tvb_new_subset(tvb, ATP_HDRSIZE -1, -1, -1);
870      }
871      else {
872         new_tvb = NULL;
873      }
874   }
875   else {
876       /* full packet */
877      new_tvb = tvb_new_subset(tvb, ATP_HDRSIZE -1, -1,- 1);
878   }
879
880   if (new_tvb) {
881      pinfo->private_data = &aspinfo;
882      /* if port == 6 it's not an ASP packet but a ZIP packet */
883      if (pinfo->srcport == 6 || pinfo->destport == 6 )
884         call_dissector(zip_atp_handle, new_tvb, pinfo, tree);
885      else
886         call_dissector(asp_handle, new_tvb, pinfo, tree);
887   }
888   else {
889     /* Just show this as a fragment. */
890     new_tvb = tvb_new_subset (tvb, ATP_HDRSIZE -1, -1, -1);
891     call_dissector(data_handle, new_tvb, pinfo, tree);
892   }
893   pinfo->fragmented = save_fragmented;
894   return;
895 }
896
897 /*
898         copy and paste from dsi
899 */
900 static gint
901 dissect_asp_reply_get_status(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
902 {
903         proto_tree      *sub_tree;
904         proto_item      *ti;
905
906         guint16 ofs;
907         guint16 flag;
908         guint16 machine_ofs;
909         guint16 sign_ofs = 0;
910         guint16 adr_ofs = 0;
911         guint16 dir_ofs = 0;
912         guint16 utf_ofs = 0;
913         guint8  nbe;
914         guint8  len;
915         guint8  i;
916
917         if (!tree)
918                 return offset;
919
920         ti = proto_tree_add_text(tree, tvb, offset, -1, "Get Status");
921         tree = proto_item_add_subtree(ti, ett_asp_status);
922
923         machine_ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_MACHOFF);
924         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_MACHOFF, 2, "Machine offset: %u", machine_ofs);
925         if (machine_ofs)
926                 machine_ofs += offset;
927
928         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_VERSOFF);
929         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_VERSOFF, 2, "Version offset: %u", ofs);
930
931         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_UAMSOFF);
932         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_UAMSOFF, 2, "UAMS offset: %u", ofs);
933
934         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_ICONOFF);
935         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_ICONOFF, 2, "Icon offset: %u", ofs);
936
937         ofs = offset +AFPSTATUS_FLAGOFF;
938         ti = proto_tree_add_item(tree, hf_asp_server_flag, tvb, ofs, 2, FALSE);
939         sub_tree = proto_item_add_subtree(ti, ett_asp_status_server_flag);
940         proto_tree_add_item(sub_tree, hf_asp_server_flag_copyfile      , tvb, ofs, 2, FALSE);
941         proto_tree_add_item(sub_tree, hf_asp_server_flag_passwd        , tvb, ofs, 2, FALSE);
942         proto_tree_add_item(sub_tree, hf_asp_server_flag_no_save_passwd, tvb, ofs, 2, FALSE);
943         proto_tree_add_item(sub_tree, hf_asp_server_flag_srv_msg       , tvb, ofs, 2, FALSE);
944         proto_tree_add_item(sub_tree, hf_asp_server_flag_srv_sig       , tvb, ofs, 2, FALSE);
945         proto_tree_add_item(sub_tree, hf_asp_server_flag_tcpip         , tvb, ofs, 2, FALSE);
946         proto_tree_add_item(sub_tree, hf_asp_server_flag_notify        , tvb, ofs, 2, FALSE);
947         proto_tree_add_item(sub_tree, hf_asp_server_flag_reconnect     , tvb, ofs, 2, FALSE);
948         proto_tree_add_item(sub_tree, hf_asp_server_flag_directory     , tvb, ofs, 2, FALSE);
949         proto_tree_add_item(sub_tree, hf_asp_server_flag_utf8_name     , tvb, ofs, 2, FALSE);
950         proto_tree_add_item(sub_tree, hf_asp_server_flag_fast_copy     , tvb, ofs, 2, FALSE);
951
952         proto_tree_add_item(tree, hf_asp_server_name, tvb, offset +AFPSTATUS_PRELEN, 1, FALSE);
953
954         flag = tvb_get_ntohs(tvb, ofs);
955         if ((flag & AFPSRVRINFO_SRVSIGNATURE)) {
956                 ofs = offset +AFPSTATUS_PRELEN +tvb_get_guint8(tvb, offset +AFPSTATUS_PRELEN) +1;
957                 if ((ofs & 1))
958                         ofs++;
959
960                 sign_ofs = tvb_get_ntohs(tvb, ofs);
961                 proto_tree_add_text(tree, tvb, ofs, 2, "Signature offset: %u", sign_ofs);
962                 sign_ofs += offset;
963                 ofs += 2;
964
965                 if ((flag & AFPSRVRINFO_TCPIP) && ofs < machine_ofs ) {
966                         adr_ofs =  tvb_get_ntohs(tvb, ofs);
967                         proto_tree_add_text(tree, tvb, ofs, 2, "Network address offset: %u", adr_ofs);
968                         adr_ofs += offset;
969                         ofs += 2;
970                 }
971
972                 if ((flag & AFPSRVRINFO_SRVDIRECTORY) && ofs < machine_ofs) {
973                         dir_ofs =  tvb_get_ntohs(tvb, ofs);
974                         proto_tree_add_text(tree, tvb, ofs, 2, "Directory services offset: %u", dir_ofs);
975                         dir_ofs += offset;
976                         ofs += 2;
977                 }
978
979                 if ((flag & AFPSRVRINFO_SRVUTF8) && ofs < machine_ofs) {
980                         utf_ofs =  tvb_get_ntohs(tvb, ofs);
981                         proto_tree_add_text(tree, tvb, ofs, 2, "UTF-8 Server name offset: %u", utf_ofs);
982                         utf_ofs += offset;
983                 }
984         }
985
986         if (machine_ofs)
987                 proto_tree_add_item(tree, hf_asp_server_type, tvb, machine_ofs, 1, FALSE);
988
989         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_VERSOFF);
990         if (ofs) {
991                 nbe = tvb_get_guint8(tvb, ofs);
992                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "Version list: %u", nbe);
993                 ofs++;
994                 sub_tree = proto_item_add_subtree(ti, ett_asp_vers);
995                 for (i = 0; i < nbe; i++) {
996                         len = tvb_get_guint8(tvb, ofs) +1;
997                         proto_tree_add_item(sub_tree, hf_asp_server_vers, tvb, ofs, 1, FALSE);
998                         ofs += len;
999                 }
1000         }
1001
1002         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_UAMSOFF);
1003         if (ofs) {
1004                 nbe = tvb_get_guint8(tvb, ofs);
1005                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "UAMS list: %u", nbe);
1006                 ofs++;
1007                 sub_tree = proto_item_add_subtree(ti, ett_asp_uams);
1008                 for (i = 0; i < nbe; i++) {
1009                         len = tvb_get_guint8(tvb, ofs) +1;
1010                         proto_tree_add_item(sub_tree, hf_asp_server_uams, tvb, ofs, 1, FALSE);
1011                         ofs += len;
1012                 }
1013         }
1014
1015         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_ICONOFF);
1016         if (ofs)
1017                 proto_tree_add_item(tree, hf_asp_server_icon, tvb, ofs, 256, FALSE);
1018
1019         if (sign_ofs) {
1020                 proto_tree_add_item(tree, hf_asp_server_signature, tvb, sign_ofs, 16, FALSE);
1021         }
1022
1023         if (adr_ofs) {
1024                 proto_tree *adr_tree;
1025                 char *tmp;
1026                 const guint8 *ip;
1027                 guint16 net;
1028                 guint8  node;
1029                 guint16 port;
1030
1031                 ofs = adr_ofs;
1032                 nbe = tvb_get_guint8(tvb, ofs);
1033                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "Address list: %u", nbe);
1034                 ofs++;
1035                 adr_tree = proto_item_add_subtree(ti, ett_asp_addr);
1036                 for (i = 0; i < nbe; i++) {
1037                         guint8 type;
1038
1039                         len = tvb_get_guint8(tvb, ofs);
1040                         type =  tvb_get_guint8(tvb, ofs +1);
1041                         switch (type) {
1042                         case 1: /* IP */
1043                                 ip = tvb_get_ptr(tvb, ofs+2, 4);
1044                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip %s", ip_to_str(ip));
1045                                 break;
1046                         case 2: /* IP + port */
1047                                 ip = tvb_get_ptr(tvb, ofs+2, 4);
1048                                 port = tvb_get_ntohs(tvb, ofs+6);
1049                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip %s:%u",ip_to_str(ip),port);
1050                                 break;
1051                         case 3: /* DDP, atalk_addr_to_str want host order not network */
1052                                 net  = tvb_get_ntohs(tvb, ofs+2);
1053                                 node = tvb_get_guint8(tvb, ofs +4);
1054                                 port = tvb_get_guint8(tvb, ofs +5);
1055                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ddp %u.%u:%u",
1056                                         net, node, port);
1057                                 break;
1058                         case 5: /* IP + port ssh tunnel */
1059                                 ip = tvb_get_ptr(tvb, ofs+2, 4);
1060                                 port = tvb_get_ntohs(tvb, ofs+6);
1061                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip (ssh tunnel) %s:%u",ip_to_str(ip),port);
1062                                 break;
1063                         case 4: /* DNS */
1064                                 if (len > 2) {
1065                                         tmp = g_malloc( len -1);
1066                                         tvb_memcpy(tvb, tmp, ofs +2, len -2);
1067                                         tmp[len -2] = 0;
1068                                         ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "dns %s", tmp);
1069                                         g_free(tmp);
1070                                         break;
1071                                 }
1072                                 /* else fall to default malformed record */
1073                         default:
1074                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len,"Unknow type : %u", type);
1075                                 break;
1076                         }
1077                         len -= 2;
1078                         sub_tree = proto_item_add_subtree(ti,ett_asp_addr_line);
1079                         proto_tree_add_item(sub_tree, hf_asp_server_addr_len, tvb, ofs, 1, FALSE);
1080                         ofs++;
1081                         proto_tree_add_item(sub_tree, hf_asp_server_addr_type, tvb, ofs, 1, FALSE);
1082                         ofs++;
1083                         proto_tree_add_item(sub_tree, hf_asp_server_addr_value,tvb, ofs, len, FALSE);
1084                         ofs += len;
1085                 }
1086         }
1087
1088         if (dir_ofs) {
1089                 ofs = dir_ofs;
1090                 nbe = tvb_get_guint8(tvb, ofs);
1091                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "Directory services list: %u", nbe);
1092                 ofs++;
1093                 sub_tree = proto_item_add_subtree(ti, ett_asp_directory);
1094                 for (i = 0; i < nbe; i++) {
1095                         len = tvb_get_guint8(tvb, ofs) +1;
1096                         proto_tree_add_item(sub_tree, hf_asp_server_directory, tvb, ofs, 1, FALSE);
1097                         ofs += len;
1098                 }
1099         }
1100         if (utf_ofs) {
1101                 ofs = utf_ofs;
1102                 len  = tvb_get_ntohs(tvb, ofs);
1103                 proto_tree_add_item(tree, hf_asp_server_utf8_name_len, tvb, ofs, 2, FALSE);
1104                 ofs += 2;               
1105                 proto_tree_add_item(tree, hf_asp_server_utf8_name, tvb, ofs, len, FALSE);
1106                 ofs += len;
1107         }
1108         /* FIXME: offset is not updated */
1109         return offset;
1110 }
1111
1112 /* -----------------------------
1113    ASP protocol cf. inside appletalk chap. 11
1114 */
1115 static struct aspinfo *
1116 get_transaction(tvbuff_t *tvb, packet_info *pinfo)
1117 {
1118   struct aspinfo *aspinfo = pinfo->private_data;
1119   conversation_t        *conversation;
1120   asp_request_key request_key, *new_request_key;
1121   asp_request_val *request_val;
1122   guint8 fn;
1123
1124   conversation = find_conversation(&pinfo->src, &pinfo->dst, pinfo->ptype,
1125                 pinfo->srcport, pinfo->destport, 0);
1126
1127   if (conversation == NULL)
1128   {
1129         conversation = conversation_new(&pinfo->src, &pinfo->dst,
1130                         pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
1131   }
1132
1133   request_key.conversation = conversation->index;
1134   memcpy(request_key.src, (!aspinfo->reply)?pinfo->src.data:pinfo->dst.data, 4);
1135   request_key.seq = aspinfo->seq;
1136
1137   request_val = (asp_request_val *) g_hash_table_lookup(
1138                                                                 asp_request_hash, &request_key);
1139   if (!request_val && !aspinfo->reply )  {
1140          fn = tvb_get_guint8(tvb, 0);
1141          new_request_key = g_mem_chunk_alloc(asp_request_keys);
1142          *new_request_key = request_key;
1143
1144          request_val = g_mem_chunk_alloc(asp_request_vals);
1145          request_val->value = fn;
1146
1147          g_hash_table_insert(asp_request_hash, new_request_key,
1148                                                                 request_val);
1149   }
1150
1151   if (!request_val)
1152         return NULL;
1153
1154   aspinfo->command = request_val->value;
1155   return aspinfo;
1156 }
1157
1158
1159 static void
1160 dissect_asp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1161 {
1162   struct aspinfo *aspinfo;
1163   int offset = 0;
1164   proto_tree *asp_tree = NULL;
1165   proto_item *ti;
1166   guint8 fn;
1167   int len;
1168
1169   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1170     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ASP");
1171   if (check_col(pinfo->cinfo, COL_INFO))
1172     col_clear(pinfo->cinfo, COL_INFO);
1173
1174   aspinfo = get_transaction(tvb, pinfo);
1175   if (!aspinfo)
1176      return;
1177
1178   fn = aspinfo->command;
1179
1180   if (check_col(pinfo->cinfo, COL_INFO)) {
1181         if (aspinfo->reply)
1182                 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply tid %u",aspinfo->seq);
1183         else
1184                 col_add_fstr(pinfo->cinfo, COL_INFO, "Function: %s  tid %u",
1185                                 val_to_str(fn, asp_func_vals, "Unknown (0x%01x)"), aspinfo->seq);
1186   }
1187
1188   if (tree) {
1189     ti = proto_tree_add_item(tree, proto_asp, tvb, offset, -1, FALSE);
1190     asp_tree = proto_item_add_subtree(ti, ett_asp);
1191   }
1192   if (!aspinfo->reply) {
1193         tvbuff_t   *new_tvb;
1194         /* let the called deal with asp_tree == NULL */
1195
1196         proto_tree_add_item(asp_tree, hf_asp_func, tvb, offset, 1, FALSE);
1197         offset++;
1198         switch(fn) {
1199         case ASPFUNC_OPEN:
1200                 proto_tree_add_item(asp_tree, hf_asp_socket, tvb, offset, 1, FALSE);
1201                 offset++;
1202                 proto_tree_add_item(asp_tree, hf_asp_version, tvb, offset, 2, FALSE);
1203                 offset += 2;
1204                 break;
1205         case ASPFUNC_TICKLE:
1206         case ASPFUNC_CLOSE:
1207                 proto_tree_add_item(asp_tree, hf_asp_session_id, tvb, offset, 1, FALSE);
1208                 offset++;
1209                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 2, FALSE);
1210                 offset +=2;
1211                 break;
1212         case ASPFUNC_STAT:
1213                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 1, FALSE);
1214                 offset++;
1215                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 2, FALSE);
1216                 offset += 2;
1217                 break;
1218         case ASPFUNC_ATTN:
1219                 proto_tree_add_item(asp_tree, hf_asp_session_id, tvb, offset, 1, FALSE);
1220                 offset++;
1221                 proto_tree_add_item(asp_tree, hf_asp_attn_code, tvb, offset, 2, FALSE);
1222                 offset +=2;
1223                 break;
1224         case ASPFUNC_CMD:
1225         case ASPFUNC_WRITE:
1226                 proto_item_set_len(asp_tree, 4);
1227                 proto_tree_add_item(asp_tree, hf_asp_session_id, tvb, offset, 1, FALSE);
1228                 offset++;
1229                 proto_tree_add_item(asp_tree, hf_asp_seq, tvb, offset, 2, FALSE);
1230                 offset += 2;
1231                 len = tvb_reported_length_remaining(tvb,offset);
1232                 new_tvb = tvb_new_subset(tvb, offset,-1,len);
1233                 call_dissector(afp_handle, new_tvb, pinfo, tree);
1234                 break;
1235         case ASPFUNC_WRTCONT:
1236                 proto_tree_add_item(asp_tree, hf_asp_session_id, tvb, offset, 1, FALSE);
1237                 offset++;
1238                 proto_tree_add_item(asp_tree, hf_asp_seq, tvb, offset, 2, FALSE);
1239                 offset += 2;
1240                 proto_tree_add_item(asp_tree, hf_asp_size, tvb, offset, 2, FALSE);
1241                 offset += 2;
1242                 break;
1243         default:
1244                 proto_item_set_len(asp_tree, 4);
1245                 offset += 3;
1246                 len = tvb_reported_length_remaining(tvb,offset);
1247                 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,len), pinfo, tree);
1248                 break;
1249         }
1250   }
1251   else {
1252         tvbuff_t   *new_tvb;
1253
1254         proto_tree_add_uint(asp_tree, hf_asp_func, tvb, 0, 0, fn);
1255         switch(fn) {
1256         case ASPFUNC_OPEN:
1257                 proto_tree_add_item(asp_tree, hf_asp_socket, tvb, offset, 1, FALSE);
1258                 offset++;
1259                 proto_tree_add_item(asp_tree, hf_asp_session_id, tvb, offset, 1, FALSE);
1260                 offset++;
1261                 proto_tree_add_item(asp_tree, hf_asp_init_error, tvb, offset, 2, FALSE);
1262                 offset += 2;
1263                 break;
1264         case ASPFUNC_CLOSE:
1265                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 1, FALSE);
1266                 offset++;
1267                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 1, FALSE);
1268                 offset++;
1269                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 2, FALSE);
1270                 offset += 2;
1271                 break;
1272         case ASPFUNC_STAT:
1273                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 4, FALSE);
1274                 offset += 4;
1275                 dissect_asp_reply_get_status(tvb, pinfo, asp_tree, offset);
1276                 break;
1277         case ASPFUNC_CMD:
1278         case ASPFUNC_WRITE:
1279                 proto_item_set_len(asp_tree, 4);
1280                 aspinfo->code = tvb_get_ntohl(tvb, offset);;
1281                 proto_tree_add_item(asp_tree, hf_asp_error, tvb, offset, 4, FALSE);
1282                 offset += 4;
1283                 len = tvb_reported_length_remaining(tvb,offset);
1284                 new_tvb = tvb_new_subset(tvb, offset,-1,len);
1285                 call_dissector(afp_handle, new_tvb, pinfo, tree);
1286                 break;
1287         case ASPFUNC_TICKLE:
1288         case ASPFUNC_WRTCONT:
1289                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 4, FALSE);
1290                 /* fall */
1291         case ASPFUNC_ATTN:      /* FIXME capture and spec disagree */
1292         default:
1293                 proto_item_set_len(asp_tree, 4);
1294                 offset += 4;
1295                 len = tvb_reported_length_remaining(tvb,offset);
1296                 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,len), pinfo, tree);
1297                 break;
1298         }
1299   }
1300 }
1301
1302 /* -----------------------------
1303    ZIP protocol cf. inside appletalk chap. 8
1304 */
1305 static void
1306 dissect_atp_zip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1307 {
1308   struct aspinfo *aspinfo;
1309   int offset = 0;
1310   proto_tree *zip_tree;
1311   proto_tree *sub_tree;
1312   proto_item *ti;
1313   guint8 fn;
1314   guint16 count;
1315   guint8 len;
1316
1317   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1318     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZIP");
1319   if (check_col(pinfo->cinfo, COL_INFO))
1320     col_clear(pinfo->cinfo, COL_INFO);
1321
1322   aspinfo = get_transaction(tvb, pinfo);
1323   if (!aspinfo)
1324      return;
1325
1326   fn = aspinfo->command;
1327
1328   if (check_col(pinfo->cinfo, COL_INFO)) {
1329         if (aspinfo->reply)
1330                 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply tid %u",aspinfo->seq);
1331         else
1332                 col_add_fstr(pinfo->cinfo, COL_INFO, "Function: %s  tid %u",
1333                                 val_to_str(fn, zip_atp_function_vals, "Unknown (0x%01x)"), aspinfo->seq);
1334   }
1335
1336   if (!tree)
1337      return;
1338
1339   ti = proto_tree_add_item(tree, proto_zip, tvb, offset, -1, FALSE);
1340   zip_tree = proto_item_add_subtree(ti, ett_zip);
1341
1342   if (!aspinfo->reply) {
1343      proto_tree_add_item(zip_tree, hf_zip_atp_function, tvb, offset, 1, FALSE);
1344      offset++;
1345      switch(fn) {
1346      case 7:    /* start_index = 0 */
1347      case 8:
1348      case 9:
1349          proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 1, FALSE);
1350          offset++;
1351          proto_tree_add_item(zip_tree, hf_zip_start_index, tvb, offset, 2, FALSE);
1352          break;
1353      }
1354   }
1355   else {
1356   guint8 i;
1357
1358      proto_tree_add_uint(zip_tree, hf_zip_atp_function, tvb, 0, 0, fn);
1359      switch(fn) {
1360      case 7:
1361      case 8:
1362      case 9:
1363          proto_tree_add_item(zip_tree, hf_zip_last_flag, tvb, offset, 1, FALSE);
1364          offset++;
1365
1366          proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 1, FALSE);
1367          offset++;
1368          count = tvb_get_ntohs(tvb, offset);
1369          ti = proto_tree_add_item(zip_tree, hf_zip_count, tvb, offset, 2, FALSE);
1370          offset += 2;
1371          sub_tree = proto_item_add_subtree(ti, ett_zip_zones_list);
1372          for (i= 1; i <= count; i++) {
1373              len = tvb_get_guint8(tvb, offset);
1374              proto_tree_add_item(sub_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1375              offset += len +1;
1376          }
1377          break;
1378      }
1379   }
1380 }
1381
1382 static void
1383 dissect_ddp_zip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1384 {
1385   proto_tree *zip_tree = NULL;
1386   proto_item *ti;
1387   guint8  fn;
1388   guint8  len;
1389   gint    offset = 0;
1390   proto_tree *flag_tree;
1391   proto_tree *sub_tree;
1392   proto_tree *net_tree;
1393   guint8 flag;
1394   guint16  net;
1395   guint8 i;
1396   guint8 count;
1397
1398   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1399     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZIP");
1400   if (check_col(pinfo->cinfo, COL_INFO))
1401     col_clear(pinfo->cinfo, COL_INFO);
1402
1403   fn = tvb_get_guint8(tvb, 0);
1404   if (check_col(pinfo->cinfo, COL_INFO)) {
1405     col_add_str(pinfo->cinfo, COL_INFO,
1406       val_to_str(fn, zip_function_vals, "Unknown ZIP function (%02x)"));
1407   }
1408
1409   if (!tree)
1410      return;
1411
1412   ti = proto_tree_add_item(tree, proto_zip, tvb, 0, -1, FALSE);
1413   zip_tree = proto_item_add_subtree(ti, ett_zip);
1414
1415   proto_tree_add_item(zip_tree, hf_zip_function, tvb, offset, 1,FALSE);
1416   offset++;
1417   /* fn 1,7,2,8 are not tested */
1418   switch (fn) {
1419   case 1: /* Query */
1420       count = tvb_get_guint8(tvb, offset);
1421       ti = proto_tree_add_item(zip_tree, hf_zip_network_count, tvb, offset, 1, FALSE);
1422       offset++;
1423       sub_tree = proto_item_add_subtree(ti, ett_zip_network_list);
1424       for (i= 1; i <= count; i++) {
1425           proto_tree_add_item(sub_tree, hf_zip_network, tvb, offset, 2, FALSE);
1426           offset += 2;
1427       }
1428       break;
1429   case 7: /* Notify */
1430       flag = tvb_get_guint8(tvb, offset);
1431       ti = proto_tree_add_text(zip_tree, tvb, offset , 1,"Flags : 0x%02x", flag);
1432       flag_tree = proto_item_add_subtree(ti, ett_zip_flags);
1433       proto_tree_add_item(flag_tree, hf_zip_flags_zone_invalid, tvb, offset, 1,FALSE);
1434       proto_tree_add_item(flag_tree, hf_zip_flags_use_broadcast,tvb, offset, 1,FALSE);
1435       proto_tree_add_item(flag_tree, hf_zip_flags_only_one_zone,tvb, offset, 1,FALSE);
1436       offset++;
1437
1438       proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 4, FALSE);
1439       offset += 4;
1440
1441       len = tvb_get_guint8(tvb, offset);
1442       proto_tree_add_item(zip_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1443       offset += len +1;
1444
1445       len = tvb_get_guint8(tvb, offset);
1446       proto_tree_add_item(zip_tree, hf_zip_multicast_length,tvb, offset, 1,FALSE);
1447       offset++;
1448       proto_tree_add_item(zip_tree, hf_zip_multicast_address,tvb, offset, len,FALSE);
1449       offset += len;
1450
1451       proto_tree_add_item(zip_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1452       break;
1453
1454   case 2: /* Reply */
1455   case 8: /* Extended Reply */
1456       count = tvb_get_guint8(tvb, offset);
1457       ti = proto_tree_add_item(zip_tree, hf_zip_network_count, tvb, offset, 1, FALSE);
1458       offset++;
1459       sub_tree = proto_item_add_subtree(ti, ett_zip_network_list);
1460       for (i= 1; i <= count; i++) {
1461           net = tvb_get_ntohs(tvb, offset);
1462           ti = proto_tree_add_text(zip_tree, tvb, offset , 2, "Zone for network : %u", net);
1463           net_tree = proto_item_add_subtree(ti, ett_zip_network_list);
1464           proto_tree_add_item(net_tree, hf_zip_network, tvb, offset, 2, FALSE);
1465           offset += 2;
1466           len = tvb_get_guint8(tvb, offset);
1467           proto_tree_add_item(net_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1468           offset += len +1;
1469       }
1470       break;
1471
1472   case 5 :  /* GetNetInfo request */
1473       proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 1, FALSE);
1474       offset++;
1475       proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 4, FALSE);
1476       offset += 4;
1477       proto_tree_add_item(zip_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1478       break;
1479
1480   case 6 :  /* GetNetInfo reply */
1481       flag = tvb_get_guint8(tvb, offset);
1482       ti = proto_tree_add_text(zip_tree, tvb, offset , 1,"Flags : 0x%02x", flag);
1483       flag_tree = proto_item_add_subtree(ti, ett_zip_flags);
1484       proto_tree_add_item(flag_tree, hf_zip_flags_zone_invalid, tvb, offset, 1,FALSE);
1485       proto_tree_add_item(flag_tree, hf_zip_flags_use_broadcast,tvb, offset, 1,FALSE);
1486       proto_tree_add_item(flag_tree, hf_zip_flags_only_one_zone,tvb, offset, 1,FALSE);
1487       offset++;
1488
1489       proto_tree_add_item(zip_tree, hf_zip_network_start, tvb, offset, 2, FALSE);
1490       offset += 2;
1491
1492       proto_tree_add_item(zip_tree, hf_zip_network_end, tvb, offset, 2, FALSE);
1493       offset += 2;
1494
1495       len = tvb_get_guint8(tvb, offset);
1496       proto_tree_add_item(zip_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1497       offset += len +1;
1498
1499       len = tvb_get_guint8(tvb, offset);
1500       proto_tree_add_item(zip_tree, hf_zip_multicast_length,tvb, offset, 1,FALSE);
1501       offset++;
1502       proto_tree_add_item(zip_tree, hf_zip_multicast_address,tvb, offset, len,FALSE);
1503       offset += len;
1504       if ((flag & 0x80) != 0)
1505          proto_tree_add_item(zip_tree, hf_zip_default_zone, tvb, offset, 1,FALSE);
1506       break;
1507
1508   default:
1509       break;
1510   }
1511 }
1512
1513 static void
1514 dissect_ddp_short(tvbuff_t *tvb, packet_info *pinfo, guint8 dnode,
1515                   guint8 snode, proto_tree *tree)
1516 {
1517   guint16 len;
1518   guint8  dport;
1519   guint8  sport;
1520   guint8  type;
1521   proto_tree *ddp_tree = NULL;
1522   proto_item *ti;
1523   static struct atalk_ddp_addr src, dst;
1524   tvbuff_t   *new_tvb;
1525
1526   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1527     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DDP");
1528   if (check_col(pinfo->cinfo, COL_INFO))
1529     col_clear(pinfo->cinfo, COL_INFO);
1530
1531   if (tree) {
1532     ti = proto_tree_add_item(tree, proto_ddp, tvb, 0, DDP_SHORT_HEADER_SIZE,
1533                              FALSE);
1534     ddp_tree = proto_item_add_subtree(ti, ett_ddp);
1535   }
1536   len = tvb_get_ntohs(tvb, 0);
1537   if (tree)
1538       proto_tree_add_uint(ddp_tree, hf_ddp_len, tvb, 0, 2, len);
1539   dport = tvb_get_guint8(tvb, 2);
1540   if (tree)
1541     proto_tree_add_uint(ddp_tree, hf_ddp_dst_socket, tvb, 2, 1, dport);
1542   sport = tvb_get_guint8(tvb, 3);
1543   if (tree)
1544     proto_tree_add_uint(ddp_tree, hf_ddp_src_socket, tvb, 3, 1, sport);
1545   type = tvb_get_guint8(tvb, 4);
1546
1547   src.net = 0;
1548   src.node = snode;
1549   dst.net = 0;
1550   dst.node = dnode;
1551   SET_ADDRESS(&pinfo->net_src, AT_ATALK, sizeof src, (guint8 *)&src);
1552   SET_ADDRESS(&pinfo->src, AT_ATALK, sizeof src, (guint8 *)&src);
1553   SET_ADDRESS(&pinfo->net_dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
1554   SET_ADDRESS(&pinfo->dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
1555
1556   pinfo->ptype = PT_DDP;
1557   pinfo->destport = dport;
1558   pinfo->srcport = sport;
1559
1560   if (check_col(pinfo->cinfo, COL_INFO)) {
1561     col_add_str(pinfo->cinfo, COL_INFO,
1562       val_to_str(type, op_vals, "Unknown DDP protocol (%02x)"));
1563   }
1564   if (tree) {
1565     proto_tree_add_string_hidden(ddp_tree, hf_ddp_src, tvb,
1566                                  4, 3, atalk_addr_to_str(&src));
1567     proto_tree_add_string_hidden(ddp_tree, hf_ddp_dst, tvb,
1568                                  6, 3, atalk_addr_to_str(&dst));
1569
1570     proto_tree_add_uint(ddp_tree, hf_ddp_type, tvb, 4, 1, type);
1571   }
1572   new_tvb = tvb_new_subset(tvb, DDP_SHORT_HEADER_SIZE, -1, -1);
1573
1574   if (!dissector_try_port(ddp_dissector_table, type, new_tvb, pinfo, tree))
1575     call_dissector(data_handle,new_tvb, pinfo, tree);
1576 }
1577
1578 static void
1579 dissect_ddp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1580 {
1581   e_ddp       ddp;
1582   proto_tree *ddp_tree;
1583   proto_item *ti;
1584   static struct atalk_ddp_addr src, dst;
1585   tvbuff_t   *new_tvb;
1586
1587   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1588     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DDP");
1589   if (check_col(pinfo->cinfo, COL_INFO))
1590     col_clear(pinfo->cinfo, COL_INFO);
1591
1592   tvb_memcpy(tvb, (guint8 *)&ddp, 0, sizeof(e_ddp));
1593   ddp.dnet=g_ntohs(ddp.dnet);
1594   ddp.snet=g_ntohs(ddp.snet);
1595   ddp.sum=g_ntohs(ddp.sum);
1596   ddp.hops_len=g_ntohs(ddp.hops_len);
1597
1598   src.net = ddp.snet;
1599   src.node = ddp.snode;
1600   dst.net = ddp.dnet;
1601   dst.node = ddp.dnode;
1602   SET_ADDRESS(&pinfo->net_src, AT_ATALK, sizeof src, (guint8 *)&src);
1603   SET_ADDRESS(&pinfo->src, AT_ATALK, sizeof src, (guint8 *)&src);
1604   SET_ADDRESS(&pinfo->net_dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
1605   SET_ADDRESS(&pinfo->dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
1606
1607   pinfo->ptype = PT_DDP;
1608   pinfo->destport = ddp.dport;
1609   pinfo->srcport = ddp.sport;
1610
1611   if (check_col(pinfo->cinfo, COL_INFO))
1612     col_add_str(pinfo->cinfo, COL_INFO,
1613       val_to_str(ddp.type, op_vals, "Unknown DDP protocol (%02x)"));
1614
1615   if (tree) {
1616     ti = proto_tree_add_item(tree, proto_ddp, tvb, 0, DDP_HEADER_SIZE,
1617                              FALSE);
1618     ddp_tree = proto_item_add_subtree(ti, ett_ddp);
1619
1620     proto_tree_add_string_hidden(ddp_tree, hf_ddp_src, tvb,
1621                                  4, 3, atalk_addr_to_str(&src));
1622     proto_tree_add_string_hidden(ddp_tree, hf_ddp_dst, tvb,
1623                                  6, 3, atalk_addr_to_str(&dst));
1624
1625     proto_tree_add_uint(ddp_tree, hf_ddp_hopcount,   tvb, 0, 1,
1626                         ddp_hops(ddp.hops_len));
1627     proto_tree_add_uint(ddp_tree, hf_ddp_len,        tvb, 0, 2,
1628                         ddp_len(ddp.hops_len));
1629     proto_tree_add_uint(ddp_tree, hf_ddp_checksum,   tvb, 2,  2,
1630                         ddp.sum);
1631     proto_tree_add_uint(ddp_tree, hf_ddp_dst_net,    tvb, 4,  2,
1632                         ddp.dnet);
1633     proto_tree_add_uint(ddp_tree, hf_ddp_src_net,    tvb, 6,  2,
1634                         ddp.snet);
1635     proto_tree_add_uint(ddp_tree, hf_ddp_dst_node,   tvb, 8,  1,
1636                         ddp.dnode);
1637     proto_tree_add_uint(ddp_tree, hf_ddp_src_node,   tvb, 9,  1,
1638                         ddp.snode);
1639     proto_tree_add_uint(ddp_tree, hf_ddp_dst_socket, tvb, 10, 1,
1640                         ddp.dport);
1641     proto_tree_add_uint(ddp_tree, hf_ddp_src_socket, tvb, 11, 1,
1642                         ddp.sport);
1643     proto_tree_add_uint(ddp_tree, hf_ddp_type,       tvb, 12, 1,
1644                         ddp.type);
1645   }
1646
1647   new_tvb = tvb_new_subset(tvb, DDP_HEADER_SIZE, -1, -1);
1648
1649   if (!dissector_try_port(ddp_dissector_table, ddp.type, new_tvb, pinfo, tree))
1650     call_dissector(data_handle,new_tvb, pinfo, tree);
1651 }
1652
1653 static const value_string llap_type_vals[] = {
1654   {0x01, "Short DDP"},
1655   {0x02, "DDP" },
1656   {0x81, "Enquiry"},
1657   {0x82, "Acknowledgement"},
1658   {0x84, "RTS"},
1659   {0x85, "CTS"},
1660   {0, NULL}
1661 };
1662
1663 void
1664 capture_llap(packet_counts *ld)
1665 {
1666   ld->other++;
1667 }
1668
1669 static void
1670 dissect_llap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1671 {
1672   guint8 dnode;
1673   guint8 snode;
1674   guint8 type;
1675   proto_tree *llap_tree = NULL;
1676   proto_item *ti;
1677   tvbuff_t   *new_tvb;
1678
1679   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1680     col_set_str(pinfo->cinfo, COL_PROTOCOL, "LLAP");
1681   if (check_col(pinfo->cinfo, COL_INFO))
1682     col_clear(pinfo->cinfo, COL_INFO);
1683
1684   if (tree) {
1685     ti = proto_tree_add_item(tree, proto_llap, tvb, 0, 3, FALSE);
1686     llap_tree = proto_item_add_subtree(ti, ett_llap);
1687   }
1688
1689   dnode = tvb_get_guint8(tvb, 0);
1690   if (tree)
1691     proto_tree_add_uint(llap_tree, hf_llap_dst, tvb, 0, 1, dnode);
1692   snode = tvb_get_guint8(tvb, 1);
1693   if (tree)
1694     proto_tree_add_uint(llap_tree, hf_llap_src, tvb, 1, 1, snode);
1695   type = tvb_get_guint8(tvb, 2);
1696   if (check_col(pinfo->cinfo, COL_INFO)) {
1697     col_add_str(pinfo->cinfo, COL_INFO,
1698       val_to_str(type, llap_type_vals, "Unknown LLAP type (%02x)"));
1699   }
1700   if (tree)
1701     proto_tree_add_uint(llap_tree, hf_llap_type, tvb, 2, 1, type);
1702
1703   new_tvb = tvb_new_subset(tvb, 3, -1, -1);
1704
1705   if (proto_is_protocol_enabled(proto_ddp)) {
1706     pinfo->current_proto = "DDP";
1707     switch (type) {
1708
1709     case 0x01:
1710       dissect_ddp_short(new_tvb, pinfo, dnode, snode, tree);
1711       return;
1712
1713     case 0x02:
1714       dissect_ddp(new_tvb, pinfo, tree);
1715       return;
1716     }
1717   }
1718   call_dissector(data_handle,new_tvb, pinfo, tree);
1719 }
1720
1721 static void
1722 atp_init(void)
1723 {
1724         /* fragment */
1725         fragment_table_init(&atp_fragment_table);
1726         reassembled_table_init(&atp_reassembled_table);
1727         /* bitmap */
1728         if (atp_request_hash)
1729                 g_hash_table_destroy(atp_request_hash);
1730         if (atp_request_keys)
1731                 g_mem_chunk_destroy(atp_request_keys);
1732         if (atp_request_vals)
1733                 g_mem_chunk_destroy(atp_request_vals);
1734
1735         atp_request_hash = g_hash_table_new(asp_hash, asp_equal);
1736
1737         atp_request_keys = g_mem_chunk_new("atp_request_keys",
1738                 sizeof(asp_request_key),
1739                 asp_packet_init_count * sizeof(asp_request_key),
1740                 G_ALLOC_AND_FREE);
1741         atp_request_vals = g_mem_chunk_new("atp_request_vals",
1742                 sizeof(asp_request_val),
1743                 asp_packet_init_count * sizeof(asp_request_val),
1744                 G_ALLOC_AND_FREE);
1745 }
1746
1747 static void
1748 asp_reinit( void)
1749 {
1750
1751         if (asp_request_hash)
1752                 g_hash_table_destroy(asp_request_hash);
1753         if (asp_request_keys)
1754                 g_mem_chunk_destroy(asp_request_keys);
1755         if (asp_request_vals)
1756                 g_mem_chunk_destroy(asp_request_vals);
1757
1758         asp_request_hash = g_hash_table_new(asp_hash, asp_equal);
1759
1760         asp_request_keys = g_mem_chunk_new("asp_request_keys",
1761                 sizeof(asp_request_key),
1762                 asp_packet_init_count * sizeof(asp_request_key),
1763                 G_ALLOC_AND_FREE);
1764         asp_request_vals = g_mem_chunk_new("asp_request_vals",
1765                 sizeof(asp_request_val),
1766                 asp_packet_init_count * sizeof(asp_request_val),
1767                 G_ALLOC_AND_FREE);
1768
1769 }
1770
1771 void
1772 proto_register_atalk(void)
1773 {
1774   static hf_register_info hf_llap[] = {
1775     { &hf_llap_dst,
1776       { "Destination Node",     "llap.dst",     FT_UINT8,  BASE_DEC, NULL, 0x0,
1777         "", HFILL }},
1778
1779     { &hf_llap_src,
1780       { "Source Node",          "llap.src",     FT_UINT8,  BASE_DEC, NULL, 0x0,
1781         "", HFILL }},
1782
1783     { &hf_llap_type,
1784       { "Type",                 "llap.type",    FT_UINT8,  BASE_HEX, VALS(llap_type_vals), 0x0,
1785         "", HFILL }},
1786   };
1787
1788   static hf_register_info hf_ddp[] = {
1789     { &hf_ddp_hopcount,
1790       { "Hop count",            "ddp.hopcount", FT_UINT8,  BASE_DEC, NULL, 0x0,
1791         "", HFILL }},
1792
1793     { &hf_ddp_len,
1794       { "Datagram length",      "ddp.len",      FT_UINT16, BASE_DEC, NULL, 0x0,
1795         "", HFILL }},
1796
1797     { &hf_ddp_checksum,
1798       { "Checksum",             "ddp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0,
1799         "", HFILL }},
1800
1801     { &hf_ddp_dst,
1802       { "Destination address",  "ddp.dst",      FT_STRING, BASE_NONE, NULL, 0x0,
1803         "", HFILL }},
1804
1805     { &hf_ddp_dst_net,
1806       { "Destination Net",      "ddp.dst.net",  FT_UINT16, BASE_DEC, NULL, 0x0,
1807         "", HFILL }},
1808
1809     { &hf_ddp_src,
1810       { "Source address",       "ddp.src",      FT_STRING, BASE_NONE, NULL, 0x0,
1811         "", HFILL }},
1812
1813     { &hf_ddp_src_net,
1814       { "Source Net",           "ddp.src.net",  FT_UINT16, BASE_DEC, NULL, 0x0,
1815         "", HFILL }},
1816
1817     { &hf_ddp_dst_node,
1818       { "Destination Node",     "ddp.dst.node", FT_UINT8,  BASE_DEC, NULL, 0x0,
1819         "", HFILL }},
1820
1821     { &hf_ddp_src_node,
1822       { "Source Node",          "ddp.src.node", FT_UINT8,  BASE_DEC, NULL, 0x0,
1823         "", HFILL }},
1824
1825     { &hf_ddp_dst_socket,
1826       { "Destination Socket",   "ddp.dst_socket", FT_UINT8,  BASE_DEC, NULL, 0x0,
1827         "", HFILL }},
1828
1829     { &hf_ddp_src_socket,
1830       { "Source Socket",        "ddp.src_socket", FT_UINT8,  BASE_DEC, NULL, 0x0,
1831         "", HFILL }},
1832
1833     { &hf_ddp_type,
1834       { "Protocol type",        "ddp.type",     FT_UINT8,  BASE_DEC, VALS(op_vals), 0x0,
1835         "", HFILL }},
1836   };
1837
1838   static hf_register_info hf_nbp[] = {
1839     { &hf_nbp_op,
1840       { "Operation",            "nbp.op",       FT_UINT8,  BASE_DEC,
1841                 VALS(nbp_op_vals), 0xF0, "Operation", HFILL }},
1842     { &hf_nbp_info,
1843       { "Info",         "nbp.info",     FT_UINT8,  BASE_HEX,
1844                 NULL, 0x0, "Info", HFILL }},
1845     { &hf_nbp_count,
1846       { "Count",                "nbp.count",    FT_UINT8,  BASE_DEC,
1847                 NULL, 0x0F, "Count", HFILL }},
1848     { &hf_nbp_node_net,
1849       { "Network",              "nbp.net",      FT_UINT16,  BASE_DEC,
1850                 NULL, 0x0, "Network", HFILL }},
1851     { &hf_nbp_node_node,
1852       { "Node",         "nbp.node",     FT_UINT8,  BASE_DEC,
1853                 NULL, 0x0, "Node", HFILL }},
1854     { &hf_nbp_node_port,
1855       { "Port",         "nbp.port",     FT_UINT8,  BASE_DEC,
1856                 NULL, 0x0, "Port", HFILL }},
1857     { &hf_nbp_node_enum,
1858       { "Enumerator",           "nbp.enum",     FT_UINT8,  BASE_DEC,
1859                 NULL, 0x0, "Enumerator", HFILL }},
1860     { &hf_nbp_node_object,
1861       { "Object",               "nbp.object",   FT_STRING,  BASE_DEC,
1862                 NULL, 0x0, "Object", HFILL }},
1863     { &hf_nbp_node_type,
1864       { "Type",         "nbp.type",     FT_STRING,  BASE_DEC,
1865                 NULL, 0x0, "Type", HFILL }},
1866     { &hf_nbp_node_zone,
1867       { "Zone",         "nbp.zone",     FT_STRING,  BASE_DEC,
1868                 NULL, 0x0, "Zone", HFILL }},
1869     { &hf_nbp_tid,
1870       { "Transaction ID",               "nbp.tid",      FT_UINT8,  BASE_DEC,
1871                 NULL, 0x0, "Transaction ID", HFILL }}
1872   };
1873
1874   static hf_register_info hf_rtmp[] = {
1875     { &hf_rtmp_net,
1876       { "Net",          "rtmp.net",     FT_UINT16,  BASE_DEC,
1877                 NULL, 0x0, "Net", HFILL }},
1878     { &hf_rtmp_node,
1879       { "Node",         "nbp.nodeid",   FT_UINT8,  BASE_DEC,
1880                 NULL, 0x0, "Node", HFILL }},
1881     { &hf_rtmp_node_len,
1882       { "Node Length",          "nbp.nodeid.length",    FT_UINT8,  BASE_DEC,
1883                 NULL, 0x0, "Node Length", HFILL }},
1884     { &hf_rtmp_tuple_net,
1885       { "Net",          "rtmp.tuple.net",       FT_UINT16,  BASE_DEC,
1886                 NULL, 0x0, "Net", HFILL }},
1887     { &hf_rtmp_tuple_range_start,
1888       { "Range Start",          "rtmp.tuple.range_start",       FT_UINT16,  BASE_DEC,
1889                 NULL, 0x0, "Range Start", HFILL }},
1890     { &hf_rtmp_tuple_range_end,
1891       { "Range End",            "rtmp.tuple.range_end", FT_UINT16,  BASE_DEC,
1892                 NULL, 0x0, "Range End", HFILL }},
1893     { &hf_rtmp_tuple_dist,
1894       { "Distance",             "rtmp.tuple.dist",      FT_UINT16,  BASE_DEC,
1895                 NULL, 0x0, "Distance", HFILL }},
1896     { &hf_rtmp_function,
1897       { "Function",             "rtmp.function",        FT_UINT8,  BASE_DEC,
1898                 VALS(rtmp_function_vals), 0x0, "Request Function", HFILL }}
1899   };
1900
1901   static hf_register_info hf_atp[] = {
1902     { &hf_atp_ctrlinfo,
1903       { "Control info",         "atp.ctrlinfo", FT_UINT8,  BASE_HEX,
1904                 NULL, 0, "control info", HFILL }},
1905
1906     { &hf_atp_function,
1907       { "Function",             "atp.function", FT_UINT8,  BASE_DEC,
1908                 VALS(atp_function_vals), ATP_FUNCMASK, "function code", HFILL }},
1909
1910
1911     { &hf_atp_xo,
1912       { "XO",           "atp.xo",       FT_BOOLEAN,  8,
1913                 NULL, ATP_XO, "Exactly-once flag", HFILL }},
1914
1915     { &hf_atp_eom,
1916       { "EOM",          "atp.eom",      FT_BOOLEAN,  8,
1917                 NULL, ATP_EOM, "End-of-message", HFILL }},
1918
1919     { &hf_atp_sts,
1920       { "STS",          "atp.sts",      FT_BOOLEAN,  8,
1921                 NULL, ATP_STS, "Send transaction status", HFILL }},
1922
1923     { &hf_atp_treltimer,
1924       { "TRel timer",           "atp.treltimer",        FT_UINT8,  BASE_DEC,
1925                 VALS(atp_trel_timer_vals), 0x07, "TRel timer", HFILL }},
1926
1927     { &hf_atp_bitmap,
1928       { "Bitmap",               "atp.bitmap",   FT_UINT8,  BASE_HEX,
1929                 NULL, 0x0, "Bitmap or sequence number", HFILL }},
1930
1931     { &hf_atp_tid,
1932       { "TID",                  "atp.tid",      FT_UINT16,  BASE_DEC,
1933                 NULL, 0x0, "Transaction id", HFILL }},
1934     { &hf_atp_user_bytes,
1935       { "User bytes",                   "atp.user_bytes",       FT_UINT32,  BASE_HEX,
1936                 NULL, 0x0, "User bytes", HFILL }},
1937
1938     { &hf_atp_segment_overlap,
1939       { "Segment overlap",      "atp.segment.overlap", FT_BOOLEAN, BASE_NONE,
1940                 NULL, 0x0, "Segment overlaps with other segments", HFILL }},
1941
1942     { &hf_atp_segment_overlap_conflict,
1943       { "Conflicting data in segment overlap", "atp.segment.overlap.conflict",
1944         FT_BOOLEAN, BASE_NONE,
1945                 NULL, 0x0, "Overlapping segments contained conflicting data", HFILL }},
1946
1947     { &hf_atp_segment_multiple_tails,
1948       { "Multiple tail segments found", "atp.segment.multipletails",
1949         FT_BOOLEAN, BASE_NONE,
1950                 NULL, 0x0, "Several tails were found when desegmenting the packet", HFILL }},
1951
1952     { &hf_atp_segment_too_long_segment,
1953       { "Segment too long",     "atp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE,
1954                 NULL, 0x0, "Segment contained data past end of packet", HFILL }},
1955
1956     { &hf_atp_segment_error,
1957       {"Desegmentation error",  "atp.segment.error", FT_NONE, BASE_NONE,
1958                 NULL, 0x0, "Desegmentation error due to illegal segments", HFILL }},
1959
1960     { &hf_atp_segment,
1961       { "ATP Fragment",         "atp.fragment", FT_NONE, BASE_NONE,
1962                 NULL, 0x0, "ATP Fragment", HFILL }},
1963
1964     { &hf_atp_segments,
1965       { "ATP Fragments",        "atp.fragments", FT_NONE, BASE_NONE,
1966                 NULL, 0x0, "ATP Fragments", HFILL }},
1967   };
1968
1969   static hf_register_info hf_asp[] = {
1970     { &hf_asp_func,
1971       { "asp function",         "asp.function", FT_UINT8,  BASE_DEC,
1972                 VALS(asp_func_vals), 0, "asp function", HFILL }},
1973
1974     { &hf_asp_error,
1975       { "asp error",            "asp.error",    FT_INT32,  BASE_DEC,
1976                 VALS(asp_error_vals), 0, "return error code", HFILL }},
1977
1978     { &hf_asp_version,
1979       { "Version",              "asp.version",  FT_UINT16,  BASE_HEX,
1980                 NULL, 0, "asp version", HFILL }},
1981
1982     { &hf_asp_attn_code,
1983       { "Attn code",            "asp.attn_code",        FT_UINT16,  BASE_HEX,
1984                 NULL, 0, "asp attention code", HFILL }},
1985
1986     { &hf_asp_init_error,
1987       { "Error",                "asp.init_error",       FT_UINT16,  BASE_DEC,
1988                 NULL, 0, "asp init error", HFILL }},
1989
1990     { &hf_asp_session_id,
1991       { "Session ID",           "asp.session_id", FT_UINT8,  BASE_DEC,
1992                 NULL, 0, "asp session id", HFILL }},
1993
1994     { &hf_asp_socket,
1995       { "Socket",               "asp.socket",   FT_UINT8,  BASE_DEC,
1996                 NULL, 0, "asp socket", HFILL }},
1997
1998     { &hf_asp_seq,
1999       { "Sequence",             "asp.seq",      FT_UINT16,  BASE_DEC,
2000                 NULL, 0, "asp sequence number", HFILL }},
2001
2002     { &hf_asp_size,
2003       { "size",         "asp.size",     FT_UINT16,  BASE_DEC,
2004                 NULL, 0, "asp available size for reply", HFILL }},
2005
2006     { &hf_asp_zero_value,
2007       { "Pad (0)",         "asp.zero_value",
2008         FT_BYTES, BASE_HEX, NULL, 0x0,
2009         "Pad", HFILL }},
2010
2011         /* asp ,dsi, afp */
2012     { &hf_asp_server_name,
2013       { "Server name",         "asp.server_name",
2014         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2015         "Server name", HFILL }},
2016
2017     { &hf_asp_server_type,
2018       { "Server type",         "asp.server_type",
2019         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2020         "Server type", HFILL }},
2021
2022     { &hf_asp_server_vers,
2023       { "AFP version",         "asp.server_vers",
2024         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2025         "AFP version", HFILL }},
2026
2027     { &hf_asp_server_uams,
2028       { "UAM",         "asp.server_uams",
2029         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2030         "UAM", HFILL }},
2031
2032     { &hf_asp_server_icon,
2033       { "Icon bitmap",         "asp.server_icon",
2034         FT_BYTES, BASE_HEX, NULL, 0x0,
2035         "Server icon bitmap", HFILL }},
2036
2037     { &hf_asp_server_directory,
2038       { "Directory service",         "asp.server_directory",
2039         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2040         "Server directory service", HFILL }},
2041
2042     { &hf_asp_server_signature,
2043       { "Server signature",         "asp.server_signature",
2044         FT_BYTES, BASE_HEX, NULL, 0x0,
2045         "Server signature", HFILL }},
2046
2047     { &hf_asp_server_flag,
2048       { "Flag",         "asp.server_flag",
2049         FT_UINT16, BASE_HEX, NULL, 0x0,
2050         "Server capabilities flag", HFILL }},
2051     { &hf_asp_server_flag_copyfile,
2052       { "Support copyfile",      "asp.server_flag.copyfile",
2053                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_COPY,
2054         "Server support copyfile", HFILL }},
2055     { &hf_asp_server_flag_passwd,
2056       { "Support change password",      "asp.server_flag.passwd",
2057                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_PASSWD,
2058         "Server support change password", HFILL }},
2059     { &hf_asp_server_flag_no_save_passwd,
2060       { "Don't allow save password",      "asp.server_flag.no_save_passwd",
2061                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_NOSAVEPASSWD,
2062         "Don't allow save password", HFILL }},
2063     { &hf_asp_server_flag_srv_msg,
2064       { "Support server message",      "asp.server_flag.srv_msg",
2065                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVMSGS,
2066         "Support server message", HFILL }},
2067     { &hf_asp_server_flag_srv_sig,
2068       { "Support server signature",      "asp.server_flag.srv_sig",
2069                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVSIGNATURE,
2070         "Support server signature", HFILL }},
2071     { &hf_asp_server_flag_tcpip,
2072       { "Support TCP/IP",      "asp.server_flag.tcpip",
2073                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_TCPIP,
2074         "Server support TCP/IP", HFILL }},
2075     { &hf_asp_server_flag_notify,
2076       { "Support server notifications",      "asp.server_flag.notify",
2077                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVNOTIFY,
2078         "Server support notifications", HFILL }},
2079     { &hf_asp_server_flag_reconnect,
2080       { "Support server reconnect",      "asp.server_flag.reconnect",
2081                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVRECONNECT,
2082         "Server support reconnect", HFILL }},
2083     { &hf_asp_server_flag_directory,
2084       { "Support directory services",      "asp.server_flag.directory",
2085                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVDIRECTORY,
2086         "Server support directory services", HFILL }},
2087     { &hf_asp_server_flag_utf8_name,
2088       { "Support UTF8 server name",      "asp.server_flag.utf8_name",
2089                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVUTF8,
2090         "Server support UTF8 server name", HFILL }},
2091     { &hf_asp_server_flag_fast_copy,
2092       { "Support fast copy",      "asp.server_flag.fast_copy",
2093                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_FASTBOZO,
2094         "Server support fast copy", HFILL }},
2095
2096     { &hf_asp_server_addr_len,
2097       { "Length",          "asp.server_addr.len",
2098         FT_UINT8, BASE_DEC, NULL, 0x0,
2099         "Address length.", HFILL }},
2100
2101     { &hf_asp_server_addr_type,
2102       { "Type",          "asp.server_addr.type",
2103         FT_UINT8, BASE_DEC, VALS(afp_server_addr_type_vals), 0x0,
2104         "Address type.", HFILL }},
2105
2106     { &hf_asp_server_addr_value,
2107       { "Value",          "asp.server_addr.value",
2108         FT_BYTES, BASE_HEX, NULL, 0x0,
2109         "Address value", HFILL }},
2110
2111     { &hf_asp_server_utf8_name_len,
2112       { "Server name length",         "asp.server_utf8_name_len",
2113         FT_UINT16, BASE_DEC, NULL, 0x0,
2114         "UTF8 server name length", HFILL }},
2115
2116     { &hf_asp_server_utf8_name,
2117       { "Server name (UTF8)",         "asp.server_utf8_name",
2118         FT_STRING, BASE_NONE, NULL, 0x0,
2119         "Server name (UTF8)", HFILL }},
2120   };
2121
2122   static hf_register_info hf_zip[] = {
2123     { &hf_zip_function,
2124       { "Function",     "zip.function", FT_UINT8,  BASE_DEC, VALS(zip_function_vals), 0x0,
2125         "ZIP function", HFILL }},
2126
2127     { &hf_zip_zero_value,
2128       { "Pad (0)",      "zip.zero_value",FT_BYTES, BASE_HEX, NULL, 0x0,
2129         "Pad", HFILL }},
2130
2131     { &hf_zip_atp_function,
2132       { "Function",     "zip.atp_function", FT_UINT8,  BASE_DEC, VALS(zip_atp_function_vals), 0x0,
2133         "", HFILL }},
2134
2135     { &hf_zip_start_index,
2136       { "Start index",  "zip.start_index", FT_UINT16, BASE_DEC, NULL, 0x0,
2137         "", HFILL }},
2138
2139     { &hf_zip_count,
2140       { "Count",        "zip.count", FT_UINT16, BASE_DEC, NULL, 0x0,
2141         "", HFILL }},
2142
2143     { &hf_zip_network_count,
2144       { "Count",        "zip.network_count", FT_UINT8, BASE_DEC, NULL, 0x0,
2145         "", HFILL }},
2146     { &hf_zip_network,
2147       { "Network","zip.network", FT_UINT16, BASE_DEC, NULL, 0x0,
2148         "", HFILL }},
2149     { &hf_zip_network_start,
2150       { "Network start","zip.network_start", FT_UINT16, BASE_DEC, NULL, 0x0,
2151         "", HFILL }},
2152     { &hf_zip_network_end,
2153       { "Network end",  "zip.network_end", FT_UINT16, BASE_DEC, NULL, 0x0,
2154         "", HFILL }},
2155
2156     { &hf_zip_flags,
2157       { "Flags",        "zip.flags", FT_BOOLEAN, 8, NULL, 0xC0,
2158         "", HFILL }},
2159
2160     { &hf_zip_last_flag,
2161       { "Last Flag",    "zip.last_flag", FT_BOOLEAN, 8, NULL, 0,
2162         "Non zero if contains last zone name in the zone list", HFILL }},
2163
2164     { &hf_zip_flags_zone_invalid,
2165       { "Zone invalid", "zip.flags.zone_invalid", FT_BOOLEAN, 8, NULL, 0x80,
2166         "", HFILL }},
2167
2168     { &hf_zip_flags_use_broadcast,
2169       { "Use broadcast","zip.flags.use_broadcast", FT_BOOLEAN, 8, NULL, 0x40,
2170         "", HFILL }},
2171
2172     { &hf_zip_flags_only_one_zone,
2173       { "Only one zone","zip.flags.only_one_zone", FT_BOOLEAN, 8, NULL, 0x20,
2174         "", HFILL }},
2175
2176     { &hf_zip_zone_name,
2177       { "Zone",         "zip.zone_name", FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2178         "", HFILL }},
2179
2180     { &hf_zip_default_zone,
2181       { "Default zone", "zip.default_zone",FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2182         "", HFILL }},
2183
2184     { &hf_zip_multicast_length,
2185       { "Multicast length",     "zip.multicast_length", FT_UINT8,  BASE_DEC, NULL, 0x0,
2186         "Multicast address length", HFILL }},
2187
2188     { &hf_zip_multicast_address,
2189       { "Multicast address", "zip.multicast_address",FT_BYTES, BASE_HEX, NULL, 0x0,
2190         "Multicast address", HFILL }},
2191
2192   };
2193
2194   static gint *ett[] = {
2195         &ett_llap,
2196         &ett_ddp,
2197         &ett_atp,
2198         &ett_atp_info,
2199         &ett_atp_segments,
2200         &ett_atp_segment,
2201         &ett_asp,
2202
2203         /* asp dsi afp */
2204         &ett_asp_status,
2205         &ett_asp_status_server_flag,
2206         &ett_asp_vers,
2207         &ett_asp_uams,
2208         &ett_asp_addr,
2209         &ett_asp_addr_line,
2210         &ett_asp_directory,
2211
2212         &ett_nbp,
2213         &ett_nbp_info,
2214         &ett_nbp_node,
2215         &ett_pstring,
2216         &ett_rtmp,
2217         &ett_rtmp_tuple,
2218
2219         &ett_zip,
2220         &ett_zip_flags,
2221         &ett_zip_zones_list,
2222         &ett_zip_network_list,
2223   };
2224   module_t *atp_module;
2225
2226   proto_llap = proto_register_protocol("LocalTalk Link Access Protocol", "LLAP", "llap");
2227   proto_register_field_array(proto_llap, hf_llap, array_length(hf_llap));
2228
2229   proto_ddp = proto_register_protocol("Datagram Delivery Protocol", "DDP", "ddp");
2230   proto_register_field_array(proto_ddp, hf_ddp, array_length(hf_ddp));
2231
2232   proto_nbp = proto_register_protocol("Name Binding Protocol", "NBP", "nbp");
2233   proto_register_field_array(proto_nbp, hf_nbp, array_length(hf_nbp));
2234
2235   proto_atp = proto_register_protocol("AppleTalk Transaction Protocol packet", "ATP", "atp");
2236   proto_register_field_array(proto_atp, hf_atp, array_length(hf_atp));
2237
2238   proto_asp = proto_register_protocol("AppleTalk Session Protocol", "ASP", "asp");
2239   proto_register_field_array(proto_asp, hf_asp, array_length(hf_asp));
2240
2241   proto_zip = proto_register_protocol("Zone Information Protocol", "ZIP", "zip");
2242   proto_register_field_array(proto_zip, hf_zip, array_length(hf_zip));
2243
2244   atp_module = prefs_register_protocol(proto_atp, NULL);
2245   prefs_register_bool_preference(atp_module, "desegment",
2246     "Desegment all ATP messages spanning multiple DDP packets",
2247     "Whether the ATP dissector should desegment all messages spanning multiple DDP packets",
2248     &atp_defragment);
2249
2250   proto_rtmp = proto_register_protocol("Routing Table Maintenance Protocol",
2251                                        "RTMP", "rtmp");
2252   proto_register_field_array(proto_rtmp, hf_rtmp, array_length(hf_rtmp));
2253
2254   proto_register_subtree_array(ett, array_length(ett));
2255
2256   /* subdissector code */
2257   ddp_dissector_table = register_dissector_table("ddp.type", "DDP packet type",
2258                                                  FT_UINT8, BASE_HEX);
2259 }
2260
2261 void
2262 proto_reg_handoff_atalk(void)
2263 {
2264   dissector_handle_t ddp_handle, nbp_handle, rtmp_request_handle;
2265   dissector_handle_t atp_handle;
2266   dissector_handle_t zip_ddp_handle;
2267   dissector_handle_t rtmp_data_handle, llap_handle;
2268
2269   ddp_handle = create_dissector_handle(dissect_ddp, proto_ddp);
2270   dissector_add("ethertype", ETHERTYPE_ATALK, ddp_handle);
2271   dissector_add("chdlctype", ETHERTYPE_ATALK, ddp_handle);
2272   dissector_add("ppp.protocol", PPP_AT, ddp_handle);
2273   dissector_add("null.type", BSD_AF_APPLETALK, ddp_handle);
2274
2275   nbp_handle = create_dissector_handle(dissect_nbp, proto_nbp);
2276   dissector_add("ddp.type", DDP_NBP, nbp_handle);
2277
2278   atp_handle = create_dissector_handle(dissect_atp, proto_atp);
2279   dissector_add("ddp.type", DDP_ATP, atp_handle);
2280
2281   asp_handle = create_dissector_handle(dissect_asp, proto_asp);
2282
2283   rtmp_request_handle = create_dissector_handle(dissect_rtmp_request, proto_rtmp);
2284   rtmp_data_handle = create_dissector_handle(dissect_rtmp_data, proto_rtmp);
2285   dissector_add("ddp.type", DDP_RTMPREQ, rtmp_request_handle);
2286   dissector_add("ddp.type", DDP_RTMPDATA, rtmp_data_handle);
2287
2288   zip_ddp_handle = create_dissector_handle(dissect_ddp_zip, proto_zip);
2289   dissector_add("ddp.type", DDP_ZIP, zip_ddp_handle);
2290
2291   zip_atp_handle = create_dissector_handle(dissect_atp_zip, proto_zip);
2292
2293   llap_handle = create_dissector_handle(dissect_llap, proto_llap);
2294   dissector_add("wtap_encap", WTAP_ENCAP_LOCALTALK, llap_handle);
2295
2296   register_init_routine( atp_init);
2297   register_init_routine( &asp_reinit);
2298
2299   afp_handle = find_dissector("afp");
2300   data_handle = find_dissector("data");
2301 }