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