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