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