As per a patch from Lars Roland, make RC_VERSION comma-separated.
[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.88 2003/04/20 11:36:11 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 "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      if (fd_head != NULL) {
861         if (fd_head->next != NULL) {
862             new_tvb = process_reassembled_data(tvb, pinfo, "Reassembled ATP",
863                 fd_head, &atp_frag_items, NULL, atp_tree);
864         }
865         else
866             new_tvb = tvb_new_subset(tvb, ATP_HDRSIZE -1, -1, -1);
867      }
868      else {
869         new_tvb = NULL;
870      }
871   }
872   else {
873       /* full packet */
874      new_tvb = tvb_new_subset(tvb, ATP_HDRSIZE -1, -1,- 1);
875   }
876
877   if (new_tvb) {
878      pinfo->private_data = &aspinfo;
879      /* if port == 6 it's not an ASP packet but a ZIP packet */
880      if (pinfo->srcport == 6 || pinfo->destport == 6 )
881         call_dissector(zip_atp_handle, new_tvb, pinfo, tree);
882      else
883         call_dissector(asp_handle, new_tvb, pinfo, tree);
884   }
885   else {
886     /* Just show this as a fragment. */
887     new_tvb = tvb_new_subset (tvb, ATP_HDRSIZE -1, -1, -1);
888     call_dissector(data_handle, new_tvb, pinfo, tree);
889   }
890   pinfo->fragmented = save_fragmented;
891   return;
892 }
893
894 /*
895         copy and paste from dsi
896 */
897 static gint
898 dissect_asp_reply_get_status(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
899 {
900         proto_tree      *sub_tree;
901         proto_item      *ti;
902
903         guint16 ofs;
904         guint16 flag;
905         guint16 machine_ofs;
906         guint16 sign_ofs = 0;
907         guint16 adr_ofs = 0;
908         guint16 dir_ofs = 0;
909         guint16 utf_ofs = 0;
910         guint8  nbe;
911         guint8  len;
912         guint8  i;
913
914         if (!tree)
915                 return offset;
916
917         ti = proto_tree_add_text(tree, tvb, offset, -1, "Get Status");
918         tree = proto_item_add_subtree(ti, ett_asp_status);
919
920         machine_ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_MACHOFF);
921         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_MACHOFF, 2, "Machine offset: %u", machine_ofs);
922         if (machine_ofs)
923                 machine_ofs += offset;
924
925         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_VERSOFF);
926         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_VERSOFF, 2, "Version offset: %u", ofs);
927
928         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_UAMSOFF);
929         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_UAMSOFF, 2, "UAMS offset: %u", ofs);
930
931         ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_ICONOFF);
932         proto_tree_add_text(tree, tvb, offset +AFPSTATUS_ICONOFF, 2, "Icon offset: %u", ofs);
933
934         ofs = offset +AFPSTATUS_FLAGOFF;
935         ti = proto_tree_add_item(tree, hf_asp_server_flag, tvb, ofs, 2, FALSE);
936         sub_tree = proto_item_add_subtree(ti, ett_asp_status_server_flag);
937         proto_tree_add_item(sub_tree, hf_asp_server_flag_copyfile      , tvb, ofs, 2, FALSE);
938         proto_tree_add_item(sub_tree, hf_asp_server_flag_passwd        , tvb, ofs, 2, FALSE);
939         proto_tree_add_item(sub_tree, hf_asp_server_flag_no_save_passwd, tvb, ofs, 2, FALSE);
940         proto_tree_add_item(sub_tree, hf_asp_server_flag_srv_msg       , tvb, ofs, 2, FALSE);
941         proto_tree_add_item(sub_tree, hf_asp_server_flag_srv_sig       , tvb, ofs, 2, FALSE);
942         proto_tree_add_item(sub_tree, hf_asp_server_flag_tcpip         , tvb, ofs, 2, FALSE);
943         proto_tree_add_item(sub_tree, hf_asp_server_flag_notify        , tvb, ofs, 2, FALSE);
944         proto_tree_add_item(sub_tree, hf_asp_server_flag_reconnect     , tvb, ofs, 2, FALSE);
945         proto_tree_add_item(sub_tree, hf_asp_server_flag_directory     , tvb, ofs, 2, FALSE);
946         proto_tree_add_item(sub_tree, hf_asp_server_flag_utf8_name     , tvb, ofs, 2, FALSE);
947         proto_tree_add_item(sub_tree, hf_asp_server_flag_fast_copy     , tvb, ofs, 2, FALSE);
948
949         proto_tree_add_item(tree, hf_asp_server_name, tvb, offset +AFPSTATUS_PRELEN, 1, FALSE);
950
951         flag = tvb_get_ntohs(tvb, ofs);
952         if ((flag & AFPSRVRINFO_SRVSIGNATURE)) {
953                 ofs = offset +AFPSTATUS_PRELEN +tvb_get_guint8(tvb, offset +AFPSTATUS_PRELEN) +1;
954                 if ((ofs & 1))
955                         ofs++;
956
957                 sign_ofs = tvb_get_ntohs(tvb, ofs);
958                 proto_tree_add_text(tree, tvb, ofs, 2, "Signature offset: %u", sign_ofs);
959                 sign_ofs += offset;
960                 ofs += 2;
961
962                 if ((flag & AFPSRVRINFO_TCPIP) && ofs < machine_ofs ) {
963                         adr_ofs =  tvb_get_ntohs(tvb, ofs);
964                         proto_tree_add_text(tree, tvb, ofs, 2, "Network address offset: %u", adr_ofs);
965                         adr_ofs += offset;
966                         ofs += 2;
967                 }
968
969                 if ((flag & AFPSRVRINFO_SRVDIRECTORY) && ofs < machine_ofs) {
970                         dir_ofs =  tvb_get_ntohs(tvb, ofs);
971                         proto_tree_add_text(tree, tvb, ofs, 2, "Directory services offset: %u", dir_ofs);
972                         dir_ofs += offset;
973                         ofs += 2;
974                 }
975
976                 if ((flag & AFPSRVRINFO_SRVUTF8) && ofs < machine_ofs) {
977                         utf_ofs =  tvb_get_ntohs(tvb, ofs);
978                         proto_tree_add_text(tree, tvb, ofs, 2, "UTF-8 Server name offset: %u", utf_ofs);
979                         utf_ofs += offset;
980                 }
981         }
982
983         if (machine_ofs)
984                 proto_tree_add_item(tree, hf_asp_server_type, tvb, machine_ofs, 1, FALSE);
985
986         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_VERSOFF);
987         if (ofs) {
988                 nbe = tvb_get_guint8(tvb, ofs);
989                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "Version list: %u", nbe);
990                 ofs++;
991                 sub_tree = proto_item_add_subtree(ti, ett_asp_vers);
992                 for (i = 0; i < nbe; i++) {
993                         len = tvb_get_guint8(tvb, ofs) +1;
994                         proto_tree_add_item(sub_tree, hf_asp_server_vers, tvb, ofs, 1, FALSE);
995                         ofs += len;
996                 }
997         }
998
999         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_UAMSOFF);
1000         if (ofs) {
1001                 nbe = tvb_get_guint8(tvb, ofs);
1002                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "UAMS list: %u", nbe);
1003                 ofs++;
1004                 sub_tree = proto_item_add_subtree(ti, ett_asp_uams);
1005                 for (i = 0; i < nbe; i++) {
1006                         len = tvb_get_guint8(tvb, ofs) +1;
1007                         proto_tree_add_item(sub_tree, hf_asp_server_uams, tvb, ofs, 1, FALSE);
1008                         ofs += len;
1009                 }
1010         }
1011
1012         ofs = offset +tvb_get_ntohs(tvb, offset +AFPSTATUS_ICONOFF);
1013         if (ofs)
1014                 proto_tree_add_item(tree, hf_asp_server_icon, tvb, ofs, 256, FALSE);
1015
1016         if (sign_ofs) {
1017                 proto_tree_add_item(tree, hf_asp_server_signature, tvb, sign_ofs, 16, FALSE);
1018         }
1019
1020         if (adr_ofs) {
1021                 proto_tree *adr_tree;
1022                 char *tmp;
1023                 const guint8 *ip;
1024                 guint16 net;
1025                 guint8  node;
1026                 guint16 port;
1027
1028                 ofs = adr_ofs;
1029                 nbe = tvb_get_guint8(tvb, ofs);
1030                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "Address list: %u", nbe);
1031                 ofs++;
1032                 adr_tree = proto_item_add_subtree(ti, ett_asp_addr);
1033                 for (i = 0; i < nbe; i++) {
1034                         guint8 type;
1035
1036                         len = tvb_get_guint8(tvb, ofs);
1037                         type =  tvb_get_guint8(tvb, ofs +1);
1038                         switch (type) {
1039                         case 1: /* IP */
1040                                 ip = tvb_get_ptr(tvb, ofs+2, 4);
1041                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip %s", ip_to_str(ip));
1042                                 break;
1043                         case 2: /* IP + port */
1044                                 ip = tvb_get_ptr(tvb, ofs+2, 4);
1045                                 port = tvb_get_ntohs(tvb, ofs+6);
1046                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip %s:%u",ip_to_str(ip),port);
1047                                 break;
1048                         case 3: /* DDP, atalk_addr_to_str want host order not network */
1049                                 net  = tvb_get_ntohs(tvb, ofs+2);
1050                                 node = tvb_get_guint8(tvb, ofs +4);
1051                                 port = tvb_get_guint8(tvb, ofs +5);
1052                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ddp %u.%u:%u",
1053                                         net, node, port);
1054                                 break;
1055                         case 5: /* IP + port ssh tunnel */
1056                                 ip = tvb_get_ptr(tvb, ofs+2, 4);
1057                                 port = tvb_get_ntohs(tvb, ofs+6);
1058                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip (ssh tunnel) %s:%u",ip_to_str(ip),port);
1059                                 break;
1060                         case 4: /* DNS */
1061                                 if (len > 2) {
1062                                         tmp = g_malloc( len -1);
1063                                         tvb_memcpy(tvb, tmp, ofs +2, len -2);
1064                                         tmp[len -2] = 0;
1065                                         ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "dns %s", tmp);
1066                                         g_free(tmp);
1067                                         break;
1068                                 }
1069                                 /* else fall to default malformed record */
1070                         default:
1071                                 ti = proto_tree_add_text(adr_tree, tvb, ofs, len,"Unknow type : %u", type);
1072                                 break;
1073                         }
1074                         len -= 2;
1075                         sub_tree = proto_item_add_subtree(ti,ett_asp_addr_line);
1076                         proto_tree_add_item(sub_tree, hf_asp_server_addr_len, tvb, ofs, 1, FALSE);
1077                         ofs++;
1078                         proto_tree_add_item(sub_tree, hf_asp_server_addr_type, tvb, ofs, 1, FALSE);
1079                         ofs++;
1080                         proto_tree_add_item(sub_tree, hf_asp_server_addr_value,tvb, ofs, len, FALSE);
1081                         ofs += len;
1082                 }
1083         }
1084
1085         if (dir_ofs) {
1086                 ofs = dir_ofs;
1087                 nbe = tvb_get_guint8(tvb, ofs);
1088                 ti = proto_tree_add_text(tree, tvb, ofs, 1, "Directory services list: %u", nbe);
1089                 ofs++;
1090                 sub_tree = proto_item_add_subtree(ti, ett_asp_directory);
1091                 for (i = 0; i < nbe; i++) {
1092                         len = tvb_get_guint8(tvb, ofs) +1;
1093                         proto_tree_add_item(sub_tree, hf_asp_server_directory, tvb, ofs, 1, FALSE);
1094                         ofs += len;
1095                 }
1096         }
1097         if (utf_ofs) {
1098                 ofs = utf_ofs;
1099                 len  = tvb_get_ntohs(tvb, ofs);
1100                 proto_tree_add_item(tree, hf_asp_server_utf8_name_len, tvb, ofs, 2, FALSE);
1101                 ofs += 2;               
1102                 proto_tree_add_item(tree, hf_asp_server_utf8_name, tvb, ofs, len, FALSE);
1103                 ofs += len;
1104         }
1105         /* FIXME: offset is not updated */
1106         return offset;
1107 }
1108
1109 /* -----------------------------
1110    ASP protocol cf. inside appletalk chap. 11
1111 */
1112 static struct aspinfo *
1113 get_transaction(tvbuff_t *tvb, packet_info *pinfo)
1114 {
1115   struct aspinfo *aspinfo = pinfo->private_data;
1116   conversation_t        *conversation;
1117   asp_request_key request_key, *new_request_key;
1118   asp_request_val *request_val;
1119   guint8 fn;
1120
1121   conversation = find_conversation(&pinfo->src, &pinfo->dst, pinfo->ptype,
1122                 pinfo->srcport, pinfo->destport, 0);
1123
1124   if (conversation == NULL)
1125   {
1126         conversation = conversation_new(&pinfo->src, &pinfo->dst,
1127                         pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
1128   }
1129
1130   request_key.conversation = conversation->index;
1131   memcpy(request_key.src, (!aspinfo->reply)?pinfo->src.data:pinfo->dst.data, 4);
1132   request_key.seq = aspinfo->seq;
1133
1134   request_val = (asp_request_val *) g_hash_table_lookup(
1135                                                                 asp_request_hash, &request_key);
1136   if (!request_val && !aspinfo->reply )  {
1137          fn = tvb_get_guint8(tvb, 0);
1138          new_request_key = g_mem_chunk_alloc(asp_request_keys);
1139          *new_request_key = request_key;
1140
1141          request_val = g_mem_chunk_alloc(asp_request_vals);
1142          request_val->value = fn;
1143
1144          g_hash_table_insert(asp_request_hash, new_request_key,
1145                                                                 request_val);
1146   }
1147
1148   if (!request_val)
1149         return NULL;
1150
1151   aspinfo->command = request_val->value;
1152   return aspinfo;
1153 }
1154
1155
1156 static void
1157 dissect_asp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1158 {
1159   struct aspinfo *aspinfo;
1160   int offset = 0;
1161   proto_tree *asp_tree = NULL;
1162   proto_item *ti;
1163   guint8 fn;
1164   int len;
1165
1166   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1167     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ASP");
1168   if (check_col(pinfo->cinfo, COL_INFO))
1169     col_clear(pinfo->cinfo, COL_INFO);
1170
1171   aspinfo = get_transaction(tvb, pinfo);
1172   if (!aspinfo)
1173      return;
1174
1175   fn = aspinfo->command;
1176
1177   if (check_col(pinfo->cinfo, COL_INFO)) {
1178         if (aspinfo->reply)
1179                 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply tid %u",aspinfo->seq);
1180         else
1181                 col_add_fstr(pinfo->cinfo, COL_INFO, "Function: %s  tid %u",
1182                                 val_to_str(fn, asp_func_vals, "Unknown (0x%01x)"), aspinfo->seq);
1183   }
1184
1185   if (tree) {
1186     ti = proto_tree_add_item(tree, proto_asp, tvb, offset, -1, FALSE);
1187     asp_tree = proto_item_add_subtree(ti, ett_asp);
1188   }
1189   if (!aspinfo->reply) {
1190         tvbuff_t   *new_tvb;
1191         /* let the called deal with asp_tree == NULL */
1192
1193         proto_tree_add_item(asp_tree, hf_asp_func, tvb, offset, 1, FALSE);
1194         offset++;
1195         switch(fn) {
1196         case ASPFUNC_OPEN:
1197                 proto_tree_add_item(asp_tree, hf_asp_socket, tvb, offset, 1, FALSE);
1198                 offset++;
1199                 proto_tree_add_item(asp_tree, hf_asp_version, tvb, offset, 2, FALSE);
1200                 offset += 2;
1201                 break;
1202         case ASPFUNC_TICKLE:
1203         case ASPFUNC_CLOSE:
1204                 proto_tree_add_item(asp_tree, hf_asp_session_id, tvb, offset, 1, FALSE);
1205                 offset++;
1206                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 2, FALSE);
1207                 offset +=2;
1208                 break;
1209         case ASPFUNC_STAT:
1210                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 1, FALSE);
1211                 offset++;
1212                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 2, FALSE);
1213                 offset += 2;
1214                 break;
1215         case ASPFUNC_ATTN:
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_attn_code, tvb, offset, 2, FALSE);
1219                 offset +=2;
1220                 break;
1221         case ASPFUNC_CMD:
1222         case ASPFUNC_WRITE:
1223                 proto_item_set_len(asp_tree, 4);
1224                 proto_tree_add_item(asp_tree, hf_asp_session_id, tvb, offset, 1, FALSE);
1225                 offset++;
1226                 proto_tree_add_item(asp_tree, hf_asp_seq, tvb, offset, 2, FALSE);
1227                 offset += 2;
1228                 len = tvb_reported_length_remaining(tvb,offset);
1229                 new_tvb = tvb_new_subset(tvb, offset,-1,len);
1230                 call_dissector(afp_handle, new_tvb, pinfo, tree);
1231                 break;
1232         case ASPFUNC_WRTCONT:
1233                 proto_tree_add_item(asp_tree, hf_asp_session_id, tvb, offset, 1, FALSE);
1234                 offset++;
1235                 proto_tree_add_item(asp_tree, hf_asp_seq, tvb, offset, 2, FALSE);
1236                 offset += 2;
1237                 proto_tree_add_item(asp_tree, hf_asp_size, tvb, offset, 2, FALSE);
1238                 offset += 2;
1239                 break;
1240         default:
1241                 proto_item_set_len(asp_tree, 4);
1242                 offset += 3;
1243                 len = tvb_reported_length_remaining(tvb,offset);
1244                 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,len), pinfo, tree);
1245                 break;
1246         }
1247   }
1248   else {
1249         tvbuff_t   *new_tvb;
1250
1251         proto_tree_add_uint(asp_tree, hf_asp_func, tvb, 0, 0, fn);
1252         switch(fn) {
1253         case ASPFUNC_OPEN:
1254                 proto_tree_add_item(asp_tree, hf_asp_socket, tvb, offset, 1, FALSE);
1255                 offset++;
1256                 proto_tree_add_item(asp_tree, hf_asp_session_id, tvb, offset, 1, FALSE);
1257                 offset++;
1258                 proto_tree_add_item(asp_tree, hf_asp_init_error, tvb, offset, 2, FALSE);
1259                 offset += 2;
1260                 break;
1261         case ASPFUNC_CLOSE:
1262                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 1, FALSE);
1263                 offset++;
1264                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 1, FALSE);
1265                 offset++;
1266                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 2, FALSE);
1267                 offset += 2;
1268                 break;
1269         case ASPFUNC_STAT:
1270                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 4, FALSE);
1271                 offset += 4;
1272                 dissect_asp_reply_get_status(tvb, pinfo, asp_tree, offset);
1273                 break;
1274         case ASPFUNC_CMD:
1275         case ASPFUNC_WRITE:
1276                 proto_item_set_len(asp_tree, 4);
1277                 aspinfo->code = tvb_get_ntohl(tvb, offset);;
1278                 proto_tree_add_item(asp_tree, hf_asp_error, tvb, offset, 4, FALSE);
1279                 offset += 4;
1280                 len = tvb_reported_length_remaining(tvb,offset);
1281                 new_tvb = tvb_new_subset(tvb, offset,-1,len);
1282                 call_dissector(afp_handle, new_tvb, pinfo, tree);
1283                 break;
1284         case ASPFUNC_TICKLE:
1285         case ASPFUNC_WRTCONT:
1286                 proto_tree_add_item(asp_tree, hf_asp_zero_value, tvb, offset, 4, FALSE);
1287                 /* fall */
1288         case ASPFUNC_ATTN:      /* FIXME capture and spec disagree */
1289         default:
1290                 proto_item_set_len(asp_tree, 4);
1291                 offset += 4;
1292                 len = tvb_reported_length_remaining(tvb,offset);
1293                 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,len), pinfo, tree);
1294                 break;
1295         }
1296   }
1297 }
1298
1299 /* -----------------------------
1300    ZIP protocol cf. inside appletalk chap. 8
1301 */
1302 static void
1303 dissect_atp_zip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1304 {
1305   struct aspinfo *aspinfo;
1306   int offset = 0;
1307   proto_tree *zip_tree;
1308   proto_tree *sub_tree;
1309   proto_item *ti;
1310   guint8 fn;
1311   guint16 count;
1312   guint8 len;
1313
1314   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1315     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZIP");
1316   if (check_col(pinfo->cinfo, COL_INFO))
1317     col_clear(pinfo->cinfo, COL_INFO);
1318
1319   aspinfo = get_transaction(tvb, pinfo);
1320   if (!aspinfo)
1321      return;
1322
1323   fn = aspinfo->command;
1324
1325   if (check_col(pinfo->cinfo, COL_INFO)) {
1326         if (aspinfo->reply)
1327                 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply tid %u",aspinfo->seq);
1328         else
1329                 col_add_fstr(pinfo->cinfo, COL_INFO, "Function: %s  tid %u",
1330                                 val_to_str(fn, zip_atp_function_vals, "Unknown (0x%01x)"), aspinfo->seq);
1331   }
1332
1333   if (!tree)
1334      return;
1335
1336   ti = proto_tree_add_item(tree, proto_zip, tvb, offset, -1, FALSE);
1337   zip_tree = proto_item_add_subtree(ti, ett_zip);
1338
1339   if (!aspinfo->reply) {
1340      proto_tree_add_item(zip_tree, hf_zip_atp_function, tvb, offset, 1, FALSE);
1341      offset++;
1342      switch(fn) {
1343      case 7:    /* start_index = 0 */
1344      case 8:
1345      case 9:
1346          proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 1, FALSE);
1347          offset++;
1348          proto_tree_add_item(zip_tree, hf_zip_start_index, tvb, offset, 2, FALSE);
1349          break;
1350      }
1351   }
1352   else {
1353   guint8 i;
1354
1355      proto_tree_add_uint(zip_tree, hf_zip_atp_function, tvb, 0, 0, fn);
1356      switch(fn) {
1357      case 7:
1358      case 8:
1359      case 9:
1360          proto_tree_add_item(zip_tree, hf_zip_last_flag, tvb, offset, 1, FALSE);
1361          offset++;
1362
1363          proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 1, FALSE);
1364          offset++;
1365          count = tvb_get_ntohs(tvb, offset);
1366          ti = proto_tree_add_item(zip_tree, hf_zip_count, tvb, offset, 2, FALSE);
1367          offset += 2;
1368          sub_tree = proto_item_add_subtree(ti, ett_zip_zones_list);
1369          for (i= 1; i <= count; i++) {
1370              len = tvb_get_guint8(tvb, offset);
1371              proto_tree_add_item(sub_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1372              offset += len +1;
1373          }
1374          break;
1375      }
1376   }
1377 }
1378
1379 static void
1380 dissect_ddp_zip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1381 {
1382   proto_tree *zip_tree = NULL;
1383   proto_item *ti;
1384   guint8  fn;
1385   guint8  len;
1386   gint    offset = 0;
1387   proto_tree *flag_tree;
1388   proto_tree *sub_tree;
1389   proto_tree *net_tree;
1390   guint8 flag;
1391   guint16  net;
1392   guint8 i;
1393   guint8 count;
1394
1395   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1396     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZIP");
1397   if (check_col(pinfo->cinfo, COL_INFO))
1398     col_clear(pinfo->cinfo, COL_INFO);
1399
1400   fn = tvb_get_guint8(tvb, 0);
1401   if (check_col(pinfo->cinfo, COL_INFO)) {
1402     col_add_str(pinfo->cinfo, COL_INFO,
1403       val_to_str(fn, zip_function_vals, "Unknown ZIP function (%02x)"));
1404   }
1405
1406   if (!tree)
1407      return;
1408
1409   ti = proto_tree_add_item(tree, proto_zip, tvb, 0, -1, FALSE);
1410   zip_tree = proto_item_add_subtree(ti, ett_zip);
1411
1412   proto_tree_add_item(zip_tree, hf_zip_function, tvb, offset, 1,FALSE);
1413   offset++;
1414   /* fn 1,7,2,8 are not tested */
1415   switch (fn) {
1416   case 1: /* Query */
1417       count = tvb_get_guint8(tvb, offset);
1418       ti = proto_tree_add_item(zip_tree, hf_zip_network_count, tvb, offset, 1, FALSE);
1419       offset++;
1420       sub_tree = proto_item_add_subtree(ti, ett_zip_network_list);
1421       for (i= 1; i <= count; i++) {
1422           proto_tree_add_item(sub_tree, hf_zip_network, tvb, offset, 2, FALSE);
1423           offset += 2;
1424       }
1425       break;
1426   case 7: /* Notify */
1427       flag = tvb_get_guint8(tvb, offset);
1428       ti = proto_tree_add_text(zip_tree, tvb, offset , 1,"Flags : 0x%02x", flag);
1429       flag_tree = proto_item_add_subtree(ti, ett_zip_flags);
1430       proto_tree_add_item(flag_tree, hf_zip_flags_zone_invalid, tvb, offset, 1,FALSE);
1431       proto_tree_add_item(flag_tree, hf_zip_flags_use_broadcast,tvb, offset, 1,FALSE);
1432       proto_tree_add_item(flag_tree, hf_zip_flags_only_one_zone,tvb, offset, 1,FALSE);
1433       offset++;
1434
1435       proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 4, FALSE);
1436       offset += 4;
1437
1438       len = tvb_get_guint8(tvb, offset);
1439       proto_tree_add_item(zip_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1440       offset += len +1;
1441
1442       len = tvb_get_guint8(tvb, offset);
1443       proto_tree_add_item(zip_tree, hf_zip_multicast_length,tvb, offset, 1,FALSE);
1444       offset++;
1445       proto_tree_add_item(zip_tree, hf_zip_multicast_address,tvb, offset, len,FALSE);
1446       offset += len;
1447
1448       proto_tree_add_item(zip_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1449       break;
1450
1451   case 2: /* Reply */
1452   case 8: /* Extended Reply */
1453       count = tvb_get_guint8(tvb, offset);
1454       ti = proto_tree_add_item(zip_tree, hf_zip_network_count, tvb, offset, 1, FALSE);
1455       offset++;
1456       sub_tree = proto_item_add_subtree(ti, ett_zip_network_list);
1457       for (i= 1; i <= count; i++) {
1458           net = tvb_get_ntohs(tvb, offset);
1459           ti = proto_tree_add_text(zip_tree, tvb, offset , 2, "Zone for network : %u", net);
1460           net_tree = proto_item_add_subtree(ti, ett_zip_network_list);
1461           proto_tree_add_item(net_tree, hf_zip_network, tvb, offset, 2, FALSE);
1462           offset += 2;
1463           len = tvb_get_guint8(tvb, offset);
1464           proto_tree_add_item(net_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1465           offset += len +1;
1466       }
1467       break;
1468
1469   case 5 :  /* GetNetInfo request */
1470       proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 1, FALSE);
1471       offset++;
1472       proto_tree_add_item(zip_tree, hf_zip_zero_value, tvb, offset, 4, FALSE);
1473       offset += 4;
1474       proto_tree_add_item(zip_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1475       break;
1476
1477   case 6 :  /* GetNetInfo reply */
1478       flag = tvb_get_guint8(tvb, offset);
1479       ti = proto_tree_add_text(zip_tree, tvb, offset , 1,"Flags : 0x%02x", flag);
1480       flag_tree = proto_item_add_subtree(ti, ett_zip_flags);
1481       proto_tree_add_item(flag_tree, hf_zip_flags_zone_invalid, tvb, offset, 1,FALSE);
1482       proto_tree_add_item(flag_tree, hf_zip_flags_use_broadcast,tvb, offset, 1,FALSE);
1483       proto_tree_add_item(flag_tree, hf_zip_flags_only_one_zone,tvb, offset, 1,FALSE);
1484       offset++;
1485
1486       proto_tree_add_item(zip_tree, hf_zip_network_start, tvb, offset, 2, FALSE);
1487       offset += 2;
1488
1489       proto_tree_add_item(zip_tree, hf_zip_network_end, tvb, offset, 2, FALSE);
1490       offset += 2;
1491
1492       len = tvb_get_guint8(tvb, offset);
1493       proto_tree_add_item(zip_tree, hf_zip_zone_name, tvb, offset, 1,FALSE);
1494       offset += len +1;
1495
1496       len = tvb_get_guint8(tvb, offset);
1497       proto_tree_add_item(zip_tree, hf_zip_multicast_length,tvb, offset, 1,FALSE);
1498       offset++;
1499       proto_tree_add_item(zip_tree, hf_zip_multicast_address,tvb, offset, len,FALSE);
1500       offset += len;
1501       if ((flag & 0x80) != 0)
1502          proto_tree_add_item(zip_tree, hf_zip_default_zone, tvb, offset, 1,FALSE);
1503       break;
1504
1505   default:
1506       break;
1507   }
1508 }
1509
1510 static void
1511 dissect_ddp_short(tvbuff_t *tvb, packet_info *pinfo, guint8 dnode,
1512                   guint8 snode, proto_tree *tree)
1513 {
1514   guint16 len;
1515   guint8  dport;
1516   guint8  sport;
1517   guint8  type;
1518   proto_tree *ddp_tree = NULL;
1519   proto_item *ti;
1520   static struct atalk_ddp_addr src, dst;
1521   tvbuff_t   *new_tvb;
1522
1523   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1524     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DDP");
1525   if (check_col(pinfo->cinfo, COL_INFO))
1526     col_clear(pinfo->cinfo, COL_INFO);
1527
1528   if (tree) {
1529     ti = proto_tree_add_item(tree, proto_ddp, tvb, 0, DDP_SHORT_HEADER_SIZE,
1530                              FALSE);
1531     ddp_tree = proto_item_add_subtree(ti, ett_ddp);
1532   }
1533   len = tvb_get_ntohs(tvb, 0);
1534   if (tree)
1535       proto_tree_add_uint(ddp_tree, hf_ddp_len, tvb, 0, 2, len);
1536   dport = tvb_get_guint8(tvb, 2);
1537   if (tree)
1538     proto_tree_add_uint(ddp_tree, hf_ddp_dst_socket, tvb, 2, 1, dport);
1539   sport = tvb_get_guint8(tvb, 3);
1540   if (tree)
1541     proto_tree_add_uint(ddp_tree, hf_ddp_src_socket, tvb, 3, 1, sport);
1542   type = tvb_get_guint8(tvb, 4);
1543
1544   src.net = 0;
1545   src.node = snode;
1546   dst.net = 0;
1547   dst.node = dnode;
1548   SET_ADDRESS(&pinfo->net_src, AT_ATALK, sizeof src, (guint8 *)&src);
1549   SET_ADDRESS(&pinfo->src, AT_ATALK, sizeof src, (guint8 *)&src);
1550   SET_ADDRESS(&pinfo->net_dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
1551   SET_ADDRESS(&pinfo->dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
1552
1553   pinfo->ptype = PT_DDP;
1554   pinfo->destport = dport;
1555   pinfo->srcport = sport;
1556
1557   if (check_col(pinfo->cinfo, COL_INFO)) {
1558     col_add_str(pinfo->cinfo, COL_INFO,
1559       val_to_str(type, op_vals, "Unknown DDP protocol (%02x)"));
1560   }
1561   if (tree) {
1562     proto_tree_add_string_hidden(ddp_tree, hf_ddp_src, tvb,
1563                                  4, 3, atalk_addr_to_str(&src));
1564     proto_tree_add_string_hidden(ddp_tree, hf_ddp_dst, tvb,
1565                                  6, 3, atalk_addr_to_str(&dst));
1566
1567     proto_tree_add_uint(ddp_tree, hf_ddp_type, tvb, 4, 1, type);
1568   }
1569   new_tvb = tvb_new_subset(tvb, DDP_SHORT_HEADER_SIZE, -1, -1);
1570
1571   if (!dissector_try_port(ddp_dissector_table, type, new_tvb, pinfo, tree))
1572     call_dissector(data_handle,new_tvb, pinfo, tree);
1573 }
1574
1575 static void
1576 dissect_ddp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1577 {
1578   e_ddp       ddp;
1579   proto_tree *ddp_tree;
1580   proto_item *ti;
1581   static struct atalk_ddp_addr src, dst;
1582   tvbuff_t   *new_tvb;
1583
1584   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1585     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DDP");
1586   if (check_col(pinfo->cinfo, COL_INFO))
1587     col_clear(pinfo->cinfo, COL_INFO);
1588
1589   tvb_memcpy(tvb, (guint8 *)&ddp, 0, sizeof(e_ddp));
1590   ddp.dnet=g_ntohs(ddp.dnet);
1591   ddp.snet=g_ntohs(ddp.snet);
1592   ddp.sum=g_ntohs(ddp.sum);
1593   ddp.hops_len=g_ntohs(ddp.hops_len);
1594
1595   src.net = ddp.snet;
1596   src.node = ddp.snode;
1597   dst.net = ddp.dnet;
1598   dst.node = ddp.dnode;
1599   SET_ADDRESS(&pinfo->net_src, AT_ATALK, sizeof src, (guint8 *)&src);
1600   SET_ADDRESS(&pinfo->src, AT_ATALK, sizeof src, (guint8 *)&src);
1601   SET_ADDRESS(&pinfo->net_dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
1602   SET_ADDRESS(&pinfo->dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
1603
1604   pinfo->ptype = PT_DDP;
1605   pinfo->destport = ddp.dport;
1606   pinfo->srcport = ddp.sport;
1607
1608   if (check_col(pinfo->cinfo, COL_INFO))
1609     col_add_str(pinfo->cinfo, COL_INFO,
1610       val_to_str(ddp.type, op_vals, "Unknown DDP protocol (%02x)"));
1611
1612   if (tree) {
1613     ti = proto_tree_add_item(tree, proto_ddp, tvb, 0, DDP_HEADER_SIZE,
1614                              FALSE);
1615     ddp_tree = proto_item_add_subtree(ti, ett_ddp);
1616
1617     proto_tree_add_string_hidden(ddp_tree, hf_ddp_src, tvb,
1618                                  4, 3, atalk_addr_to_str(&src));
1619     proto_tree_add_string_hidden(ddp_tree, hf_ddp_dst, tvb,
1620                                  6, 3, atalk_addr_to_str(&dst));
1621
1622     proto_tree_add_uint(ddp_tree, hf_ddp_hopcount,   tvb, 0, 1,
1623                         ddp_hops(ddp.hops_len));
1624     proto_tree_add_uint(ddp_tree, hf_ddp_len,        tvb, 0, 2,
1625                         ddp_len(ddp.hops_len));
1626     proto_tree_add_uint(ddp_tree, hf_ddp_checksum,   tvb, 2,  2,
1627                         ddp.sum);
1628     proto_tree_add_uint(ddp_tree, hf_ddp_dst_net,    tvb, 4,  2,
1629                         ddp.dnet);
1630     proto_tree_add_uint(ddp_tree, hf_ddp_src_net,    tvb, 6,  2,
1631                         ddp.snet);
1632     proto_tree_add_uint(ddp_tree, hf_ddp_dst_node,   tvb, 8,  1,
1633                         ddp.dnode);
1634     proto_tree_add_uint(ddp_tree, hf_ddp_src_node,   tvb, 9,  1,
1635                         ddp.snode);
1636     proto_tree_add_uint(ddp_tree, hf_ddp_dst_socket, tvb, 10, 1,
1637                         ddp.dport);
1638     proto_tree_add_uint(ddp_tree, hf_ddp_src_socket, tvb, 11, 1,
1639                         ddp.sport);
1640     proto_tree_add_uint(ddp_tree, hf_ddp_type,       tvb, 12, 1,
1641                         ddp.type);
1642   }
1643
1644   new_tvb = tvb_new_subset(tvb, DDP_HEADER_SIZE, -1, -1);
1645
1646   if (!dissector_try_port(ddp_dissector_table, ddp.type, new_tvb, pinfo, tree))
1647     call_dissector(data_handle,new_tvb, pinfo, tree);
1648 }
1649
1650 static const value_string llap_type_vals[] = {
1651   {0x01, "Short DDP"},
1652   {0x02, "DDP" },
1653   {0x81, "Enquiry"},
1654   {0x82, "Acknowledgement"},
1655   {0x84, "RTS"},
1656   {0x85, "CTS"},
1657   {0, NULL}
1658 };
1659
1660 void
1661 capture_llap(packet_counts *ld)
1662 {
1663   ld->other++;
1664 }
1665
1666 static void
1667 dissect_llap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1668 {
1669   guint8 dnode;
1670   guint8 snode;
1671   guint8 type;
1672   proto_tree *llap_tree = NULL;
1673   proto_item *ti;
1674   tvbuff_t   *new_tvb;
1675
1676   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1677     col_set_str(pinfo->cinfo, COL_PROTOCOL, "LLAP");
1678   if (check_col(pinfo->cinfo, COL_INFO))
1679     col_clear(pinfo->cinfo, COL_INFO);
1680
1681   if (tree) {
1682     ti = proto_tree_add_item(tree, proto_llap, tvb, 0, 3, FALSE);
1683     llap_tree = proto_item_add_subtree(ti, ett_llap);
1684   }
1685
1686   dnode = tvb_get_guint8(tvb, 0);
1687   if (tree)
1688     proto_tree_add_uint(llap_tree, hf_llap_dst, tvb, 0, 1, dnode);
1689   snode = tvb_get_guint8(tvb, 1);
1690   if (tree)
1691     proto_tree_add_uint(llap_tree, hf_llap_src, tvb, 1, 1, snode);
1692   type = tvb_get_guint8(tvb, 2);
1693   if (check_col(pinfo->cinfo, COL_INFO)) {
1694     col_add_str(pinfo->cinfo, COL_INFO,
1695       val_to_str(type, llap_type_vals, "Unknown LLAP type (%02x)"));
1696   }
1697   if (tree)
1698     proto_tree_add_uint(llap_tree, hf_llap_type, tvb, 2, 1, type);
1699
1700   new_tvb = tvb_new_subset(tvb, 3, -1, -1);
1701
1702   if (proto_is_protocol_enabled(proto_ddp)) {
1703     pinfo->current_proto = "DDP";
1704     switch (type) {
1705
1706     case 0x01:
1707       dissect_ddp_short(new_tvb, pinfo, dnode, snode, tree);
1708       return;
1709
1710     case 0x02:
1711       dissect_ddp(new_tvb, pinfo, tree);
1712       return;
1713     }
1714   }
1715   call_dissector(data_handle,new_tvb, pinfo, tree);
1716 }
1717
1718 static void
1719 atp_init(void)
1720 {
1721         /* fragment */
1722         fragment_table_init(&atp_fragment_table);
1723         reassembled_table_init(&atp_reassembled_table);
1724         /* bitmap */
1725         if (atp_request_hash)
1726                 g_hash_table_destroy(atp_request_hash);
1727         if (atp_request_keys)
1728                 g_mem_chunk_destroy(atp_request_keys);
1729         if (atp_request_vals)
1730                 g_mem_chunk_destroy(atp_request_vals);
1731
1732         atp_request_hash = g_hash_table_new(asp_hash, asp_equal);
1733
1734         atp_request_keys = g_mem_chunk_new("atp_request_keys",
1735                 sizeof(asp_request_key),
1736                 asp_packet_init_count * sizeof(asp_request_key),
1737                 G_ALLOC_AND_FREE);
1738         atp_request_vals = g_mem_chunk_new("atp_request_vals",
1739                 sizeof(asp_request_val),
1740                 asp_packet_init_count * sizeof(asp_request_val),
1741                 G_ALLOC_AND_FREE);
1742 }
1743
1744 static void
1745 asp_reinit( void)
1746 {
1747
1748         if (asp_request_hash)
1749                 g_hash_table_destroy(asp_request_hash);
1750         if (asp_request_keys)
1751                 g_mem_chunk_destroy(asp_request_keys);
1752         if (asp_request_vals)
1753                 g_mem_chunk_destroy(asp_request_vals);
1754
1755         asp_request_hash = g_hash_table_new(asp_hash, asp_equal);
1756
1757         asp_request_keys = g_mem_chunk_new("asp_request_keys",
1758                 sizeof(asp_request_key),
1759                 asp_packet_init_count * sizeof(asp_request_key),
1760                 G_ALLOC_AND_FREE);
1761         asp_request_vals = g_mem_chunk_new("asp_request_vals",
1762                 sizeof(asp_request_val),
1763                 asp_packet_init_count * sizeof(asp_request_val),
1764                 G_ALLOC_AND_FREE);
1765
1766 }
1767
1768 void
1769 proto_register_atalk(void)
1770 {
1771   static hf_register_info hf_llap[] = {
1772     { &hf_llap_dst,
1773       { "Destination Node",     "llap.dst",     FT_UINT8,  BASE_DEC, NULL, 0x0,
1774         "", HFILL }},
1775
1776     { &hf_llap_src,
1777       { "Source Node",          "llap.src",     FT_UINT8,  BASE_DEC, NULL, 0x0,
1778         "", HFILL }},
1779
1780     { &hf_llap_type,
1781       { "Type",                 "llap.type",    FT_UINT8,  BASE_HEX, VALS(llap_type_vals), 0x0,
1782         "", HFILL }},
1783   };
1784
1785   static hf_register_info hf_ddp[] = {
1786     { &hf_ddp_hopcount,
1787       { "Hop count",            "ddp.hopcount", FT_UINT8,  BASE_DEC, NULL, 0x0,
1788         "", HFILL }},
1789
1790     { &hf_ddp_len,
1791       { "Datagram length",      "ddp.len",      FT_UINT16, BASE_DEC, NULL, 0x0,
1792         "", HFILL }},
1793
1794     { &hf_ddp_checksum,
1795       { "Checksum",             "ddp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0,
1796         "", HFILL }},
1797
1798     { &hf_ddp_dst,
1799       { "Destination address",  "ddp.dst",      FT_STRING, BASE_NONE, NULL, 0x0,
1800         "", HFILL }},
1801
1802     { &hf_ddp_dst_net,
1803       { "Destination Net",      "ddp.dst.net",  FT_UINT16, BASE_DEC, NULL, 0x0,
1804         "", HFILL }},
1805
1806     { &hf_ddp_src,
1807       { "Source address",       "ddp.src",      FT_STRING, BASE_NONE, NULL, 0x0,
1808         "", HFILL }},
1809
1810     { &hf_ddp_src_net,
1811       { "Source Net",           "ddp.src.net",  FT_UINT16, BASE_DEC, NULL, 0x0,
1812         "", HFILL }},
1813
1814     { &hf_ddp_dst_node,
1815       { "Destination Node",     "ddp.dst.node", FT_UINT8,  BASE_DEC, NULL, 0x0,
1816         "", HFILL }},
1817
1818     { &hf_ddp_src_node,
1819       { "Source Node",          "ddp.src.node", FT_UINT8,  BASE_DEC, NULL, 0x0,
1820         "", HFILL }},
1821
1822     { &hf_ddp_dst_socket,
1823       { "Destination Socket",   "ddp.dst_socket", FT_UINT8,  BASE_DEC, NULL, 0x0,
1824         "", HFILL }},
1825
1826     { &hf_ddp_src_socket,
1827       { "Source Socket",        "ddp.src_socket", FT_UINT8,  BASE_DEC, NULL, 0x0,
1828         "", HFILL }},
1829
1830     { &hf_ddp_type,
1831       { "Protocol type",        "ddp.type",     FT_UINT8,  BASE_DEC, VALS(op_vals), 0x0,
1832         "", HFILL }},
1833   };
1834
1835   static hf_register_info hf_nbp[] = {
1836     { &hf_nbp_op,
1837       { "Operation",            "nbp.op",       FT_UINT8,  BASE_DEC,
1838                 VALS(nbp_op_vals), 0xF0, "Operation", HFILL }},
1839     { &hf_nbp_info,
1840       { "Info",         "nbp.info",     FT_UINT8,  BASE_HEX,
1841                 NULL, 0x0, "Info", HFILL }},
1842     { &hf_nbp_count,
1843       { "Count",                "nbp.count",    FT_UINT8,  BASE_DEC,
1844                 NULL, 0x0F, "Count", HFILL }},
1845     { &hf_nbp_node_net,
1846       { "Network",              "nbp.net",      FT_UINT16,  BASE_DEC,
1847                 NULL, 0x0, "Network", HFILL }},
1848     { &hf_nbp_node_node,
1849       { "Node",         "nbp.node",     FT_UINT8,  BASE_DEC,
1850                 NULL, 0x0, "Node", HFILL }},
1851     { &hf_nbp_node_port,
1852       { "Port",         "nbp.port",     FT_UINT8,  BASE_DEC,
1853                 NULL, 0x0, "Port", HFILL }},
1854     { &hf_nbp_node_enum,
1855       { "Enumerator",           "nbp.enum",     FT_UINT8,  BASE_DEC,
1856                 NULL, 0x0, "Enumerator", HFILL }},
1857     { &hf_nbp_node_object,
1858       { "Object",               "nbp.object",   FT_STRING,  BASE_DEC,
1859                 NULL, 0x0, "Object", HFILL }},
1860     { &hf_nbp_node_type,
1861       { "Type",         "nbp.type",     FT_STRING,  BASE_DEC,
1862                 NULL, 0x0, "Type", HFILL }},
1863     { &hf_nbp_node_zone,
1864       { "Zone",         "nbp.zone",     FT_STRING,  BASE_DEC,
1865                 NULL, 0x0, "Zone", HFILL }},
1866     { &hf_nbp_tid,
1867       { "Transaction ID",               "nbp.tid",      FT_UINT8,  BASE_DEC,
1868                 NULL, 0x0, "Transaction ID", HFILL }}
1869   };
1870
1871   static hf_register_info hf_rtmp[] = {
1872     { &hf_rtmp_net,
1873       { "Net",          "rtmp.net",     FT_UINT16,  BASE_DEC,
1874                 NULL, 0x0, "Net", HFILL }},
1875     { &hf_rtmp_node,
1876       { "Node",         "nbp.nodeid",   FT_UINT8,  BASE_DEC,
1877                 NULL, 0x0, "Node", HFILL }},
1878     { &hf_rtmp_node_len,
1879       { "Node Length",          "nbp.nodeid.length",    FT_UINT8,  BASE_DEC,
1880                 NULL, 0x0, "Node Length", HFILL }},
1881     { &hf_rtmp_tuple_net,
1882       { "Net",          "rtmp.tuple.net",       FT_UINT16,  BASE_DEC,
1883                 NULL, 0x0, "Net", HFILL }},
1884     { &hf_rtmp_tuple_range_start,
1885       { "Range Start",          "rtmp.tuple.range_start",       FT_UINT16,  BASE_DEC,
1886                 NULL, 0x0, "Range Start", HFILL }},
1887     { &hf_rtmp_tuple_range_end,
1888       { "Range End",            "rtmp.tuple.range_end", FT_UINT16,  BASE_DEC,
1889                 NULL, 0x0, "Range End", HFILL }},
1890     { &hf_rtmp_tuple_dist,
1891       { "Distance",             "rtmp.tuple.dist",      FT_UINT16,  BASE_DEC,
1892                 NULL, 0x0, "Distance", HFILL }},
1893     { &hf_rtmp_function,
1894       { "Function",             "rtmp.function",        FT_UINT8,  BASE_DEC,
1895                 VALS(rtmp_function_vals), 0x0, "Request Function", HFILL }}
1896   };
1897
1898   static hf_register_info hf_atp[] = {
1899     { &hf_atp_ctrlinfo,
1900       { "Control info",         "atp.ctrlinfo", FT_UINT8,  BASE_HEX,
1901                 NULL, 0, "control info", HFILL }},
1902
1903     { &hf_atp_function,
1904       { "Function",             "atp.function", FT_UINT8,  BASE_DEC,
1905                 VALS(atp_function_vals), ATP_FUNCMASK, "function code", HFILL }},
1906
1907
1908     { &hf_atp_xo,
1909       { "XO",           "atp.xo",       FT_BOOLEAN,  8,
1910                 NULL, ATP_XO, "Exactly-once flag", HFILL }},
1911
1912     { &hf_atp_eom,
1913       { "EOM",          "atp.eom",      FT_BOOLEAN,  8,
1914                 NULL, ATP_EOM, "End-of-message", HFILL }},
1915
1916     { &hf_atp_sts,
1917       { "STS",          "atp.sts",      FT_BOOLEAN,  8,
1918                 NULL, ATP_STS, "Send transaction status", HFILL }},
1919
1920     { &hf_atp_treltimer,
1921       { "TRel timer",           "atp.treltimer",        FT_UINT8,  BASE_DEC,
1922                 VALS(atp_trel_timer_vals), 0x07, "TRel timer", HFILL }},
1923
1924     { &hf_atp_bitmap,
1925       { "Bitmap",               "atp.bitmap",   FT_UINT8,  BASE_HEX,
1926                 NULL, 0x0, "Bitmap or sequence number", HFILL }},
1927
1928     { &hf_atp_tid,
1929       { "TID",                  "atp.tid",      FT_UINT16,  BASE_DEC,
1930                 NULL, 0x0, "Transaction id", HFILL }},
1931     { &hf_atp_user_bytes,
1932       { "User bytes",                   "atp.user_bytes",       FT_UINT32,  BASE_HEX,
1933                 NULL, 0x0, "User bytes", HFILL }},
1934
1935     { &hf_atp_segment_overlap,
1936       { "Segment overlap",      "atp.segment.overlap", FT_BOOLEAN, BASE_NONE,
1937                 NULL, 0x0, "Segment overlaps with other segments", HFILL }},
1938
1939     { &hf_atp_segment_overlap_conflict,
1940       { "Conflicting data in segment overlap", "atp.segment.overlap.conflict",
1941         FT_BOOLEAN, BASE_NONE,
1942                 NULL, 0x0, "Overlapping segments contained conflicting data", HFILL }},
1943
1944     { &hf_atp_segment_multiple_tails,
1945       { "Multiple tail segments found", "atp.segment.multipletails",
1946         FT_BOOLEAN, BASE_NONE,
1947                 NULL, 0x0, "Several tails were found when desegmenting the packet", HFILL }},
1948
1949     { &hf_atp_segment_too_long_segment,
1950       { "Segment too long",     "atp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE,
1951                 NULL, 0x0, "Segment contained data past end of packet", HFILL }},
1952
1953     { &hf_atp_segment_error,
1954       {"Desegmentation error",  "atp.segment.error", FT_FRAMENUM, BASE_NONE,
1955                 NULL, 0x0, "Desegmentation error due to illegal segments", HFILL }},
1956
1957     { &hf_atp_segment,
1958       { "ATP Fragment",         "atp.fragment", FT_FRAMENUM, BASE_NONE,
1959                 NULL, 0x0, "ATP Fragment", HFILL }},
1960
1961     { &hf_atp_segments,
1962       { "ATP Fragments",        "atp.fragments", FT_NONE, BASE_NONE,
1963                 NULL, 0x0, "ATP Fragments", HFILL }},
1964
1965     { &hf_atp_reassembled_in,
1966       { "Reassembled ATP in frame", "atp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1967        "This ATP packet is reassembled in this frame", HFILL }}
1968   };
1969
1970   static hf_register_info hf_asp[] = {
1971     { &hf_asp_func,
1972       { "asp function",         "asp.function", FT_UINT8,  BASE_DEC,
1973                 VALS(asp_func_vals), 0, "asp function", HFILL }},
1974
1975     { &hf_asp_error,
1976       { "asp error",            "asp.error",    FT_INT32,  BASE_DEC,
1977                 VALS(asp_error_vals), 0, "return error code", HFILL }},
1978
1979     { &hf_asp_version,
1980       { "Version",              "asp.version",  FT_UINT16,  BASE_HEX,
1981                 NULL, 0, "asp version", HFILL }},
1982
1983     { &hf_asp_attn_code,
1984       { "Attn code",            "asp.attn_code",        FT_UINT16,  BASE_HEX,
1985                 NULL, 0, "asp attention code", HFILL }},
1986
1987     { &hf_asp_init_error,
1988       { "Error",                "asp.init_error",       FT_UINT16,  BASE_DEC,
1989                 NULL, 0, "asp init error", HFILL }},
1990
1991     { &hf_asp_session_id,
1992       { "Session ID",           "asp.session_id", FT_UINT8,  BASE_DEC,
1993                 NULL, 0, "asp session id", HFILL }},
1994
1995     { &hf_asp_socket,
1996       { "Socket",               "asp.socket",   FT_UINT8,  BASE_DEC,
1997                 NULL, 0, "asp socket", HFILL }},
1998
1999     { &hf_asp_seq,
2000       { "Sequence",             "asp.seq",      FT_UINT16,  BASE_DEC,
2001                 NULL, 0, "asp sequence number", HFILL }},
2002
2003     { &hf_asp_size,
2004       { "size",         "asp.size",     FT_UINT16,  BASE_DEC,
2005                 NULL, 0, "asp available size for reply", HFILL }},
2006
2007     { &hf_asp_zero_value,
2008       { "Pad (0)",         "asp.zero_value",
2009         FT_BYTES, BASE_HEX, NULL, 0x0,
2010         "Pad", HFILL }},
2011
2012         /* asp ,dsi, afp */
2013     { &hf_asp_server_name,
2014       { "Server name",         "asp.server_name",
2015         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2016         "Server name", HFILL }},
2017
2018     { &hf_asp_server_type,
2019       { "Server type",         "asp.server_type",
2020         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2021         "Server type", HFILL }},
2022
2023     { &hf_asp_server_vers,
2024       { "AFP version",         "asp.server_vers",
2025         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2026         "AFP version", HFILL }},
2027
2028     { &hf_asp_server_uams,
2029       { "UAM",         "asp.server_uams",
2030         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2031         "UAM", HFILL }},
2032
2033     { &hf_asp_server_icon,
2034       { "Icon bitmap",         "asp.server_icon",
2035         FT_BYTES, BASE_HEX, NULL, 0x0,
2036         "Server icon bitmap", HFILL }},
2037
2038     { &hf_asp_server_directory,
2039       { "Directory service",         "asp.server_directory",
2040         FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2041         "Server directory service", HFILL }},
2042
2043     { &hf_asp_server_signature,
2044       { "Server signature",         "asp.server_signature",
2045         FT_BYTES, BASE_HEX, NULL, 0x0,
2046         "Server signature", HFILL }},
2047
2048     { &hf_asp_server_flag,
2049       { "Flag",         "asp.server_flag",
2050         FT_UINT16, BASE_HEX, NULL, 0x0,
2051         "Server capabilities flag", HFILL }},
2052     { &hf_asp_server_flag_copyfile,
2053       { "Support copyfile",      "asp.server_flag.copyfile",
2054                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_COPY,
2055         "Server support copyfile", HFILL }},
2056     { &hf_asp_server_flag_passwd,
2057       { "Support change password",      "asp.server_flag.passwd",
2058                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_PASSWD,
2059         "Server support change password", HFILL }},
2060     { &hf_asp_server_flag_no_save_passwd,
2061       { "Don't allow save password",      "asp.server_flag.no_save_passwd",
2062                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_NOSAVEPASSWD,
2063         "Don't allow save password", HFILL }},
2064     { &hf_asp_server_flag_srv_msg,
2065       { "Support server message",      "asp.server_flag.srv_msg",
2066                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVMSGS,
2067         "Support server message", HFILL }},
2068     { &hf_asp_server_flag_srv_sig,
2069       { "Support server signature",      "asp.server_flag.srv_sig",
2070                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVSIGNATURE,
2071         "Support server signature", HFILL }},
2072     { &hf_asp_server_flag_tcpip,
2073       { "Support TCP/IP",      "asp.server_flag.tcpip",
2074                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_TCPIP,
2075         "Server support TCP/IP", HFILL }},
2076     { &hf_asp_server_flag_notify,
2077       { "Support server notifications",      "asp.server_flag.notify",
2078                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVNOTIFY,
2079         "Server support notifications", HFILL }},
2080     { &hf_asp_server_flag_reconnect,
2081       { "Support server reconnect",      "asp.server_flag.reconnect",
2082                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVRECONNECT,
2083         "Server support reconnect", HFILL }},
2084     { &hf_asp_server_flag_directory,
2085       { "Support directory services",      "asp.server_flag.directory",
2086                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVDIRECTORY,
2087         "Server support directory services", HFILL }},
2088     { &hf_asp_server_flag_utf8_name,
2089       { "Support UTF8 server name",      "asp.server_flag.utf8_name",
2090                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_SRVUTF8,
2091         "Server support UTF8 server name", HFILL }},
2092     { &hf_asp_server_flag_fast_copy,
2093       { "Support fast copy",      "asp.server_flag.fast_copy",
2094                 FT_BOOLEAN, 16, NULL, AFPSRVRINFO_FASTBOZO,
2095         "Server support fast copy", HFILL }},
2096
2097     { &hf_asp_server_addr_len,
2098       { "Length",          "asp.server_addr.len",
2099         FT_UINT8, BASE_DEC, NULL, 0x0,
2100         "Address length.", HFILL }},
2101
2102     { &hf_asp_server_addr_type,
2103       { "Type",          "asp.server_addr.type",
2104         FT_UINT8, BASE_DEC, VALS(afp_server_addr_type_vals), 0x0,
2105         "Address type.", HFILL }},
2106
2107     { &hf_asp_server_addr_value,
2108       { "Value",          "asp.server_addr.value",
2109         FT_BYTES, BASE_HEX, NULL, 0x0,
2110         "Address value", HFILL }},
2111
2112     { &hf_asp_server_utf8_name_len,
2113       { "Server name length",         "asp.server_utf8_name_len",
2114         FT_UINT16, BASE_DEC, NULL, 0x0,
2115         "UTF8 server name length", HFILL }},
2116
2117     { &hf_asp_server_utf8_name,
2118       { "Server name (UTF8)",         "asp.server_utf8_name",
2119         FT_STRING, BASE_NONE, NULL, 0x0,
2120         "Server name (UTF8)", HFILL }},
2121   };
2122
2123   static hf_register_info hf_zip[] = {
2124     { &hf_zip_function,
2125       { "Function",     "zip.function", FT_UINT8,  BASE_DEC, VALS(zip_function_vals), 0x0,
2126         "ZIP function", HFILL }},
2127
2128     { &hf_zip_zero_value,
2129       { "Pad (0)",      "zip.zero_value",FT_BYTES, BASE_HEX, NULL, 0x0,
2130         "Pad", HFILL }},
2131
2132     { &hf_zip_atp_function,
2133       { "Function",     "zip.atp_function", FT_UINT8,  BASE_DEC, VALS(zip_atp_function_vals), 0x0,
2134         "", HFILL }},
2135
2136     { &hf_zip_start_index,
2137       { "Start index",  "zip.start_index", FT_UINT16, BASE_DEC, NULL, 0x0,
2138         "", HFILL }},
2139
2140     { &hf_zip_count,
2141       { "Count",        "zip.count", FT_UINT16, BASE_DEC, NULL, 0x0,
2142         "", HFILL }},
2143
2144     { &hf_zip_network_count,
2145       { "Count",        "zip.network_count", FT_UINT8, BASE_DEC, NULL, 0x0,
2146         "", HFILL }},
2147     { &hf_zip_network,
2148       { "Network","zip.network", FT_UINT16, BASE_DEC, NULL, 0x0,
2149         "", HFILL }},
2150     { &hf_zip_network_start,
2151       { "Network start","zip.network_start", FT_UINT16, BASE_DEC, NULL, 0x0,
2152         "", HFILL }},
2153     { &hf_zip_network_end,
2154       { "Network end",  "zip.network_end", FT_UINT16, BASE_DEC, NULL, 0x0,
2155         "", HFILL }},
2156
2157     { &hf_zip_flags,
2158       { "Flags",        "zip.flags", FT_BOOLEAN, 8, NULL, 0xC0,
2159         "", HFILL }},
2160
2161     { &hf_zip_last_flag,
2162       { "Last Flag",    "zip.last_flag", FT_BOOLEAN, 8, NULL, 0,
2163         "Non zero if contains last zone name in the zone list", HFILL }},
2164
2165     { &hf_zip_flags_zone_invalid,
2166       { "Zone invalid", "zip.flags.zone_invalid", FT_BOOLEAN, 8, NULL, 0x80,
2167         "", HFILL }},
2168
2169     { &hf_zip_flags_use_broadcast,
2170       { "Use broadcast","zip.flags.use_broadcast", FT_BOOLEAN, 8, NULL, 0x40,
2171         "", HFILL }},
2172
2173     { &hf_zip_flags_only_one_zone,
2174       { "Only one zone","zip.flags.only_one_zone", FT_BOOLEAN, 8, NULL, 0x20,
2175         "", HFILL }},
2176
2177     { &hf_zip_zone_name,
2178       { "Zone",         "zip.zone_name", FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2179         "", HFILL }},
2180
2181     { &hf_zip_default_zone,
2182       { "Default zone", "zip.default_zone",FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2183         "", HFILL }},
2184
2185     { &hf_zip_multicast_length,
2186       { "Multicast length",     "zip.multicast_length", FT_UINT8,  BASE_DEC, NULL, 0x0,
2187         "Multicast address length", HFILL }},
2188
2189     { &hf_zip_multicast_address,
2190       { "Multicast address", "zip.multicast_address",FT_BYTES, BASE_HEX, NULL, 0x0,
2191         "Multicast address", HFILL }},
2192
2193   };
2194
2195   static gint *ett[] = {
2196         &ett_llap,
2197         &ett_ddp,
2198         &ett_atp,
2199         &ett_atp_info,
2200         &ett_atp_segments,
2201         &ett_atp_segment,
2202         &ett_asp,
2203
2204         /* asp dsi afp */
2205         &ett_asp_status,
2206         &ett_asp_status_server_flag,
2207         &ett_asp_vers,
2208         &ett_asp_uams,
2209         &ett_asp_addr,
2210         &ett_asp_addr_line,
2211         &ett_asp_directory,
2212
2213         &ett_nbp,
2214         &ett_nbp_info,
2215         &ett_nbp_node,
2216         &ett_pstring,
2217         &ett_rtmp,
2218         &ett_rtmp_tuple,
2219
2220         &ett_zip,
2221         &ett_zip_flags,
2222         &ett_zip_zones_list,
2223         &ett_zip_network_list,
2224   };
2225   module_t *atp_module;
2226
2227   proto_llap = proto_register_protocol("LocalTalk Link Access Protocol", "LLAP", "llap");
2228   proto_register_field_array(proto_llap, hf_llap, array_length(hf_llap));
2229
2230   proto_ddp = proto_register_protocol("Datagram Delivery Protocol", "DDP", "ddp");
2231   proto_register_field_array(proto_ddp, hf_ddp, array_length(hf_ddp));
2232
2233   proto_nbp = proto_register_protocol("Name Binding Protocol", "NBP", "nbp");
2234   proto_register_field_array(proto_nbp, hf_nbp, array_length(hf_nbp));
2235
2236   proto_atp = proto_register_protocol("AppleTalk Transaction Protocol packet", "ATP", "atp");
2237   proto_register_field_array(proto_atp, hf_atp, array_length(hf_atp));
2238
2239   proto_asp = proto_register_protocol("AppleTalk Session Protocol", "ASP", "asp");
2240   proto_register_field_array(proto_asp, hf_asp, array_length(hf_asp));
2241
2242   proto_zip = proto_register_protocol("Zone Information Protocol", "ZIP", "zip");
2243   proto_register_field_array(proto_zip, hf_zip, array_length(hf_zip));
2244
2245   atp_module = prefs_register_protocol(proto_atp, NULL);
2246   prefs_register_bool_preference(atp_module, "desegment",
2247     "Desegment all ATP messages spanning multiple DDP packets",
2248     "Whether the ATP dissector should desegment all messages spanning multiple DDP packets",
2249     &atp_defragment);
2250
2251   proto_rtmp = proto_register_protocol("Routing Table Maintenance Protocol",
2252                                        "RTMP", "rtmp");
2253   proto_register_field_array(proto_rtmp, hf_rtmp, array_length(hf_rtmp));
2254
2255   proto_register_subtree_array(ett, array_length(ett));
2256
2257   /* subdissector code */
2258   ddp_dissector_table = register_dissector_table("ddp.type", "DDP packet type",
2259                                                  FT_UINT8, BASE_HEX);
2260 }
2261
2262 void
2263 proto_reg_handoff_atalk(void)
2264 {
2265   dissector_handle_t ddp_handle, nbp_handle, rtmp_request_handle;
2266   dissector_handle_t atp_handle;
2267   dissector_handle_t zip_ddp_handle;
2268   dissector_handle_t rtmp_data_handle, llap_handle;
2269
2270   ddp_handle = create_dissector_handle(dissect_ddp, proto_ddp);
2271   dissector_add("ethertype", ETHERTYPE_ATALK, ddp_handle);
2272   dissector_add("chdlctype", ETHERTYPE_ATALK, ddp_handle);
2273   dissector_add("ppp.protocol", PPP_AT, ddp_handle);
2274   dissector_add("null.type", BSD_AF_APPLETALK, ddp_handle);
2275   dissector_add("arcnet.protocol_id", ARCNET_PROTO_APPLETALK, ddp_handle);
2276
2277   nbp_handle = create_dissector_handle(dissect_nbp, proto_nbp);
2278   dissector_add("ddp.type", DDP_NBP, nbp_handle);
2279
2280   atp_handle = create_dissector_handle(dissect_atp, proto_atp);
2281   dissector_add("ddp.type", DDP_ATP, atp_handle);
2282
2283   asp_handle = create_dissector_handle(dissect_asp, proto_asp);
2284
2285   rtmp_request_handle = create_dissector_handle(dissect_rtmp_request, proto_rtmp);
2286   rtmp_data_handle = create_dissector_handle(dissect_rtmp_data, proto_rtmp);
2287   dissector_add("ddp.type", DDP_RTMPREQ, rtmp_request_handle);
2288   dissector_add("ddp.type", DDP_RTMPDATA, rtmp_data_handle);
2289
2290   zip_ddp_handle = create_dissector_handle(dissect_ddp_zip, proto_zip);
2291   dissector_add("ddp.type", DDP_ZIP, zip_ddp_handle);
2292
2293   zip_atp_handle = create_dissector_handle(dissect_atp_zip, proto_zip);
2294
2295   llap_handle = create_dissector_handle(dissect_llap, proto_llap);
2296   dissector_add("wtap_encap", WTAP_ENCAP_LOCALTALK, llap_handle);
2297
2298   register_init_routine( atp_init);
2299   register_init_routine( &asp_reinit);
2300
2301   afp_handle = find_dissector("afp");
2302   data_handle = find_dissector("data");
2303 }