It's the AppleTalk Session Protocol, not the AppleTalk Stream Protocol.
[obnox/wireshark/wip.git] / packet-atalk.c
1 /* packet-atalk.c
2  * Routines for Appletalk packet disassembly (DDP, currently).
3  *
4  * $Id: packet-atalk.c,v 1.65 2002/04/26 07:41:31 guy Exp $
5  *
6  * Simon Wilkinson <sxw@dcs.ed.ac.uk>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #ifdef HAVE_NETINET_IN_H
36 # include <netinet/in.h>
37 #endif
38
39 #include <glib.h>
40 #include <epan/packet.h>
41 #include "etypes.h"
42 #include "ppptypes.h"
43 #include "aftypes.h"
44 #include <epan/atalk-utils.h>
45 #include <epan/conversation.h>
46
47 #include "packet-afp.h"
48
49 static dissector_handle_t afp_handle;
50
51 static int proto_llap = -1;
52 static int hf_llap_dst = -1;
53 static int hf_llap_src = -1;
54 static int hf_llap_type = -1;
55
56 static int proto_ddp = -1;
57 static int hf_ddp_hopcount = -1;
58 static int hf_ddp_len = -1;
59 static int hf_ddp_checksum = -1;
60 static int hf_ddp_dst_net = -1;
61 static int hf_ddp_src_net = -1;
62 static int hf_ddp_dst_node = -1;
63 static int hf_ddp_src_node = -1;
64 static int hf_ddp_dst_socket = -1;
65 static int hf_ddp_src_socket = -1;
66 static int hf_ddp_type = -1;
67
68
69 /* --------------------------------------
70  * ATP protocol parameters
71  * from netatalk/include/atalk/atp.h
72  */
73 #define ATP_MAXDATA     (578+4)         /* maximum ATP data size */
74 #define ATP_BUFSIZ      587             /* maximum packet size */
75 #define ATP_HDRSIZE     5               /* includes DDP type field */
76  
77 #define ATP_TRELMASK    0x07            /* mask all but TREL */
78 #define ATP_RELTIME     30              /* base release timer (in secs) */
79   
80 #define ATP_TREL30      0x0             /* release time codes */
81 #define ATP_TREL1M      0x1             /* these are passed in flags of */
82 #define ATP_TREL2M      0x2             /* atp_sreq call, and set in the */
83 #define ATP_TREL4M      0x3             /* packet control info. */
84 #define ATP_TREL8M      0x4
85
86 /* flags for ATP options (and control byte)
87 */
88 #define ATP_XO          0x20 /* (1<<5)          eXactly Once mode */
89 #define ATP_EOM         0x10 /* (1<<4)          End Of Message */
90 #define ATP_STS         0x08 /* (1<<3)          Transaction Status */
91  
92 /* function codes
93 */
94 #define ATP_FUNCMASK    (3<<6)          /* mask all but function */
95   
96 #define ATP_TREQ        1 /* (1<<6)        Trans. REQuest */
97 #define ATP_TRESP       2 /* (2<<6)        Trans. RESPonse */
98 #define ATP_TREL        3 /* (3<<6)        Trans. RELease */
99
100 /* ------------------------- */    
101 static dissector_handle_t asp_handle;
102
103 static int proto_atp = -1;
104 static int hf_atp_ctrlinfo  = -1; /* u_int8_t    control information */
105 static int hf_atp_function  = -1; /* bits 7,6    function */
106 static int hf_atp_xo        = -1; /* bit 5       exactly-once */
107 static int hf_atp_eom       = -1; /* bit 4       end-of-message */
108 static int hf_atp_sts       = -1; /* bit 3       send transaction status */
109 static int hf_atp_treltimer = -1; /* bits 2,1,0  TRel timeout indicator */
110
111 static int hf_atp_bitmap = -1;   /* u_int8_t  bitmap or sequence number */
112 static int hf_atp_tid = -1;      /* u_int16_t transaction id. */
113
114 /* --------------------------------
115  * from netatalk/include/atalk/ats.h
116  */
117  
118 #define ASPFUNC_CLOSE   1
119 #define ASPFUNC_CMD     2
120 #define ASPFUNC_STAT    3
121 #define ASPFUNC_OPEN    4
122 #define ASPFUNC_TICKLE  5
123 #define ASPFUNC_WRITE   6
124 #define ASPFUNC_WRTCONT 7
125 #define ASPFUNC_ATTN    8
126
127 #define ASP_HDRSIZ      4 
128 #define ASPERR_OK       0x0000
129 #define ASPERR_BADVERS  0xfbd6
130 #define ASPERR_BUFSMALL 0xfbd5
131 #define ASPERR_NOSESS   0xfbd4
132 #define ASPERR_NOSERV   0xfbd3
133 #define ASPERR_PARM     0xfbd2
134 #define ASPERR_SERVBUSY 0xfbd1
135 #define ASPERR_SESSCLOS 0xfbd0
136 #define ASPERR_SIZERR   0xfbcf
137 #define ASPERR_TOOMANY  0xfbce
138 #define ASPERR_NOACK    0xfbcd
139
140 static int proto_asp = -1;
141 static int hf_asp_func = -1;
142 static int hf_asp_error = -1;
143
144 static guint asp_packet_init_count = 200;
145
146 typedef struct {
147         guint32 conversation;
148         guint16 seq;
149 } asp_request_key;
150  
151 typedef struct {
152         guint8  command;
153 } asp_request_val;
154  
155 static GHashTable *asp_request_hash = NULL;
156 static GMemChunk *asp_request_keys = NULL;
157 static GMemChunk *asp_request_vals = NULL;
158
159 /* Hash Functions */
160 static gint  asp_equal (gconstpointer v, gconstpointer v2)
161 {
162         asp_request_key *val1 = (asp_request_key*)v;
163         asp_request_key *val2 = (asp_request_key*)v2;
164
165         if (val1->conversation == val2->conversation &&
166                         val1->seq == val2->seq) {
167                 return 1;
168         }
169         return 0;
170 }
171
172 static guint asp_hash  (gconstpointer v)
173 {
174         asp_request_key *asp_key = (asp_request_key*)v;
175         return asp_key->seq;
176 }
177
178 /* ------------------------------------ */
179 static int proto_nbp = -1;
180 static int hf_nbp_op = -1;
181 static int hf_nbp_info = -1;
182 static int hf_nbp_count = -1;
183 static int hf_nbp_tid = -1;
184
185 static int hf_nbp_node_net = -1;
186 static int hf_nbp_node_port = -1;
187 static int hf_nbp_node_node = -1;
188 static int hf_nbp_node_enum = -1;
189 static int hf_nbp_node_object = -1;
190 static int hf_nbp_node_type = -1;
191 static int hf_nbp_node_zone = -1;
192
193 static int proto_rtmp = -1;
194 static int hf_rtmp_net = -1;
195 static int hf_rtmp_node_len = -1;
196 static int hf_rtmp_node = -1;
197 static int hf_rtmp_tuple_net = -1;
198 static int hf_rtmp_tuple_range_start = -1;
199 static int hf_rtmp_tuple_range_end = -1;
200 static int hf_rtmp_tuple_dist = -1;
201 static int hf_rtmp_function = -1;
202
203 static gint ett_atp = -1;
204
205 static gint ett_atp_info = -1;
206 static gint ett_asp = -1;
207
208 static gint ett_nbp = -1;
209 static gint ett_nbp_info = -1;
210 static gint ett_nbp_node = -1;
211 static gint ett_rtmp = -1;
212 static gint ett_rtmp_tuple = -1;
213 static gint ett_ddp = -1;
214 static gint ett_llap = -1;
215 static gint ett_pstring = -1;
216
217 static dissector_table_t ddp_dissector_table;
218
219 static dissector_handle_t data_handle;
220
221 #define DDP_SHORT_HEADER_SIZE 5
222
223 /*
224  * P = Padding, H = Hops, L = Len
225  *
226  * PPHHHHLL LLLLLLLL
227  *
228  * Assumes the argument is in host byte order.
229  */
230 #define ddp_hops(x)     ( ( x >> 10) & 0x3C )
231 #define ddp_len(x)              ( x & 0x03ff )
232 typedef struct _e_ddp {
233   guint16       hops_len; /* combines pad, hops, and len */
234   guint16       sum,dnet,snet;
235   guint8        dnode,snode;
236   guint8        dport,sport;
237   guint8        type;
238 } e_ddp;
239
240 #define DDP_HEADER_SIZE 13
241
242
243 static const value_string op_vals[] = {
244   {DDP_RTMPDATA, "AppleTalk Routing Table response or data" },
245   {DDP_NBP, "AppleTalk Name Binding Protocol packet"},
246   {DDP_ATP, "AppleTalk Transaction Protocol packet"},
247   {DDP_AEP, "AppleTalk Echo Protocol packet"},
248   {DDP_RTMPREQ, "AppleTalk Routing Table request"},
249   {DDP_ZIP, "AppleTalk Zone Information Protocol packet"},
250   {DDP_ADSP, "AppleTalk Data Stream Protocol"},
251   {DDP_EIGRP, "Cisco EIGRP for AppleTalk"},
252   {0, NULL}
253 };
254
255 static const value_string rtmp_function_vals[] = {
256   {1, "Request"},
257   {2, "Route Data Request (split horizon processed)"},
258   {3, "Route Data Request (no split horizon processing)"},
259   {0, NULL}
260 };
261
262 #define NBP_LOOKUP 2
263 #define NBP_FORWARD 4
264 #define NBP_REPLY 3
265
266 static const value_string nbp_op_vals[] = {
267   {NBP_LOOKUP, "lookup"},
268   {NBP_FORWARD, "forward request"},
269   {NBP_REPLY, "reply"},
270   {0, NULL}
271 };
272
273 static const value_string atp_function_vals[] = {
274   {ATP_TREQ        ,"REQuest"},
275   {ATP_TRESP       ,"RESPonse"},
276   {ATP_TREL        ,"RELease"},
277   {0, NULL}
278 };
279
280 static const value_string atp_trel_timer_vals[] = {
281   {0, "30 seconds"},
282   {1, "1 minute"},
283   {2, "2 minutes"},
284   {3, "4 minutes"},
285   {4, "8 minutes"},
286   {0, NULL}
287 };
288
289 /*
290 */
291 static const value_string asp_func_vals[] = {
292   {ASPFUNC_CLOSE,       "CloseSession" },
293   {ASPFUNC_CMD,         "Command" },
294   {ASPFUNC_STAT,        "GetStatus" },
295   {ASPFUNC_OPEN,        "OpenSession" },
296   {ASPFUNC_TICKLE,      "Tickle" },
297   {ASPFUNC_WRITE,       "Write" },
298   {ASPFUNC_WRTCONT,     "Write Cont" },
299   {ASPFUNC_ATTN,        "Attention" },
300   {0,                   NULL } };
301
302 static const value_string asp_error_vals[] = {
303   {AFP_OK                       , "success"},
304   {AFPERR_ACCESS        , "permission denied" },
305   {AFPERR_AUTHCONT      , "logincont" },
306   {AFPERR_BADUAM        , "uam doesn't exist" },
307   {AFPERR_BADVERS       , "bad afp version number" },
308   {AFPERR_BITMAP        , "invalid bitmap" },
309   {AFPERR_CANTMOVE      , "can't move file" },
310   {AFPERR_DENYCONF      , "file synchronization locks conflict" },
311   {AFPERR_DIRNEMPT      , "directory not empty" },
312   {AFPERR_DFULL         , "disk full" },
313   {AFPERR_EOF           , "end of file" },
314   {AFPERR_BUSY          , "FileBusy" },
315   {AFPERR_FLATVOL       , "volume doesn't support directories" },
316   {AFPERR_NOITEM        , "ItemNotFound" },
317   {AFPERR_LOCK          , "LockErr" },
318   {AFPERR_MISC          , "misc. err" },
319   {AFPERR_NLOCK         , "no more locks" },
320   {AFPERR_NOSRVR        , "no response by server at that address" },
321   {AFPERR_EXIST         , "object already exists" },
322   {AFPERR_NOOBJ         , "object not found" },
323   {AFPERR_PARAM         , "parameter error" },
324   {AFPERR_NORANGE       , "no range lock" },
325   {AFPERR_RANGEOVR      , "range overlap" },
326   {AFPERR_SESSCLOS      , "session closed" },
327   {AFPERR_NOTAUTH       , "user not authenticated" },
328   {AFPERR_NOOP          , "command not supported" },
329   {AFPERR_BADTYPE       , "object is the wrong type" },
330   {AFPERR_NFILE         , "too many files open" },
331   {AFPERR_SHUTDOWN      , "server is going down" },
332   {AFPERR_NORENAME      , "can't rename" },
333   {AFPERR_NODIR         , "couldn't find directory" },
334   {AFPERR_ITYPE         , "wrong icon type" },
335   {AFPERR_VLOCK         , "volume locked" },
336   {AFPERR_OLOCK         , "object locked" },
337   {AFPERR_CTNSHRD       , "share point contains a share point" },
338   {AFPERR_NOID          , "file thread not found" },
339   {AFPERR_EXISTID       , "file already has an id" },
340   {AFPERR_DIFFVOL       , "different volume" },
341   {AFPERR_CATCHNG       , "catalog has changed" },
342   {AFPERR_SAMEOBJ       , "source file == destination file" },
343   {AFPERR_BADID         , "non-existent file id" },
344   {AFPERR_PWDSAME       , "same password/can't change password" },
345   {AFPERR_PWDSHORT      , "password too short" },
346   {AFPERR_PWDEXPR       , "password expired" },
347   {AFPERR_INSHRD        , "folder being shared is inside a shared folder." },
348   {AFPERR_INTRASH   , "shared folder in trash." },
349   {AFPERR_PWDCHNG   , "password needs to be changed" },
350   {AFPERR_PWDPOLCY  , "password fails policy check" },
351   {AFPERR_USRLOGIN  , "user already logged on" },
352   {0,                   NULL } };
353
354 /*
355  * XXX - do this with an FT_UINT_STRING?
356  * Unfortunately, you can't extract from an FT_UINT_STRING the string,
357  * which we'd want to do in order to put it into the "Data:" portion.
358  *
359  * Are these always in the Mac extended character set?
360  */
361 int dissect_pascal_string(tvbuff_t *tvb, int offset, proto_tree *tree,
362         int hf_index)
363 {
364         int len;
365         
366         len = tvb_get_guint8(tvb, offset);
367         offset++;
368
369         if ( tree )
370         {
371                 char *tmp;
372                 proto_tree *item;
373                 proto_tree *subtree;
374                 
375                 /*
376                  * XXX - if we could do this inside the protocol tree
377                  * code, we could perhaps avoid allocating and freeing
378                  * this string buffer.
379                  */
380                 tmp = g_malloc( len+1 );
381                 tvb_memcpy(tvb, tmp, offset, len);
382                 tmp[len] = 0;
383                 item = proto_tree_add_string(tree, hf_index, tvb, offset-1, len+1, tmp);
384
385                 subtree = proto_item_add_subtree(item, ett_pstring);
386                 proto_tree_add_text(subtree, tvb, offset-1, 1, "Length: %d", len);
387                 proto_tree_add_text(subtree, tvb, offset, len, "Data: %s", tmp);
388                 
389                 g_free(tmp);
390         }
391         offset += len;
392         
393         return offset;  
394 }
395
396 static void
397 dissect_rtmp_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
398   proto_tree *rtmp_tree;
399   proto_item *ti;
400   guint8 function;
401
402   if (check_col(pinfo->cinfo, COL_PROTOCOL))
403     col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMP");
404   if (check_col(pinfo->cinfo, COL_INFO))
405     col_clear(pinfo->cinfo, COL_INFO);
406
407   function = tvb_get_guint8(tvb, 0);
408
409   if (check_col(pinfo->cinfo, COL_INFO))
410     col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
411         val_to_str(function, rtmp_function_vals, "Unknown function (%02)"));
412   
413   if (tree) {
414     ti = proto_tree_add_item(tree, proto_rtmp, tvb, 0, 1, FALSE);
415     rtmp_tree = proto_item_add_subtree(ti, ett_rtmp);
416
417     proto_tree_add_uint(rtmp_tree, hf_rtmp_function, tvb, 0, 1, function);
418   }
419 }
420
421 static void
422 dissect_rtmp_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
423   proto_tree *rtmp_tree;
424   proto_item *ti;
425   int offset = 0;
426   guint16 net;
427   guint8 nodelen,nodelen_bits;
428   guint16 node; /* might be more than 8 bits */
429   int i;
430
431   if (check_col(pinfo->cinfo, COL_PROTOCOL))
432     col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMP");
433   if (check_col(pinfo->cinfo, COL_INFO))
434     col_clear(pinfo->cinfo, COL_INFO);
435
436   net = tvb_get_ntohs(tvb, offset);
437   nodelen_bits = tvb_get_guint8(tvb, offset+2);
438   if ( nodelen_bits <= 8 ) {
439     node = tvb_get_guint8(tvb, offset)+1;
440     nodelen = 1;
441   } else {
442     node = tvb_get_ntohs(tvb, offset);
443     nodelen = 2;
444   }
445   
446   if (check_col(pinfo->cinfo, COL_INFO))
447     col_add_fstr(pinfo->cinfo, COL_INFO, "Net: %u  Node Len: %u  Node: %u",
448                 net, nodelen_bits, node);
449   
450   if (tree) {
451     ti = proto_tree_add_item(tree, proto_rtmp, tvb, offset, -1, FALSE);
452     rtmp_tree = proto_item_add_subtree(ti, ett_rtmp);
453
454     proto_tree_add_uint(rtmp_tree, hf_rtmp_net, tvb, offset, 2, net);
455     proto_tree_add_uint(rtmp_tree, hf_rtmp_node_len, tvb, offset+2, 1,
456                         nodelen_bits);
457     proto_tree_add_uint(rtmp_tree, hf_rtmp_node, tvb, offset+3, nodelen,
458                         node);
459     offset += 3 + nodelen;
460
461     i = 1;
462     while (tvb_offset_exists(tvb, offset)) {
463       proto_tree *tuple_item, *tuple_tree;
464       guint16 tuple_net;
465       guint8 tuple_dist;
466       guint16 tuple_range_end;
467
468       tuple_net = tvb_get_ntohs(tvb, offset);
469       tuple_dist = tvb_get_guint8(tvb, offset+2);
470
471       if (tuple_dist & 0x80) {
472         tuple_range_end = tvb_get_ntohs(tvb, offset+3);
473         tuple_item = proto_tree_add_text(rtmp_tree, tvb, offset, 6,
474                         "Tuple %d:  Range Start: %u  Dist: %u  Range End: %u",
475                         i, tuple_net, tuple_dist&0x7F, tuple_range_end);
476       } else {
477         tuple_item = proto_tree_add_text(rtmp_tree, tvb, offset, 3,
478                         "Tuple %d:  Net: %u  Dist: %u",
479                         i, tuple_net, tuple_dist);
480       }
481       tuple_tree = proto_item_add_subtree(tuple_item, ett_rtmp_tuple);
482
483       if (tuple_dist & 0x80) {
484         proto_tree_add_uint(tuple_tree, hf_rtmp_tuple_range_start, tvb, offset, 2, 
485                         tuple_net);
486       } else {
487         proto_tree_add_uint(tuple_tree, hf_rtmp_tuple_net, tvb, offset, 2, 
488                         tuple_net);
489       }
490       proto_tree_add_uint(tuple_tree, hf_rtmp_tuple_dist, tvb, offset+2, 1,
491                         tuple_dist & 0x7F);
492
493       if (tuple_dist & 0x80) {
494         /*
495          * Extended network tuple.
496          */
497         proto_tree_add_item(tuple_tree, hf_rtmp_tuple_range_end, tvb, offset+3, 2, 
498                                 FALSE);
499         offset += 6;
500       } else
501         offset += 3;
502
503       i++;
504     }
505   }
506 }
507
508 static void
509 dissect_nbp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
510   proto_tree *nbp_tree;
511   proto_tree *nbp_info_tree;
512   proto_item *ti, *info_item;
513   int offset = 0;
514   guint8 info;
515   guint op, count;
516   unsigned int i;
517
518   if (check_col(pinfo->cinfo, COL_PROTOCOL))
519     col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBP");
520   if (check_col(pinfo->cinfo, COL_INFO))
521     col_clear(pinfo->cinfo, COL_INFO);
522
523   info = tvb_get_guint8(tvb, offset);
524   op = info >> 4;
525   count = info & 0x0F;
526
527   if (check_col(pinfo->cinfo, COL_INFO))
528     col_add_fstr(pinfo->cinfo, COL_INFO, "Op: %s  Count: %u",
529       val_to_str(op, nbp_op_vals, "Unknown (0x%01x)"), count);
530   
531   if (tree) {
532     ti = proto_tree_add_item(tree, proto_nbp, tvb, offset, -1, FALSE);
533     nbp_tree = proto_item_add_subtree(ti, ett_nbp);
534
535     info_item = proto_tree_add_uint_format(nbp_tree, hf_nbp_info, tvb, offset, 1,
536                 info,
537                 "Info: 0x%01X  Operation: %s  Count: %u", info,
538                 val_to_str(op, nbp_op_vals, "Unknown (0x%01X)"),
539                 count);
540     nbp_info_tree = proto_item_add_subtree(info_item, ett_nbp_info);
541     proto_tree_add_uint(nbp_info_tree, hf_nbp_op, tvb, offset, 1, info);
542     proto_tree_add_uint(nbp_info_tree, hf_nbp_count, tvb, offset, 1, info);
543     proto_tree_add_item(nbp_tree, hf_nbp_tid, tvb, offset+1, 1, FALSE);
544     offset += 2;
545
546     for (i=0; i<count; i++) {
547       proto_tree *node_item,*node_tree;
548       int soffset = offset;
549
550       node_item = proto_tree_add_text(nbp_tree, tvb, offset, -1, 
551                         "Node %d", i+1);
552       node_tree = proto_item_add_subtree(node_item, ett_nbp_node);
553
554       proto_tree_add_item(node_tree, hf_nbp_node_net, tvb, offset, 2, FALSE);
555       offset += 2;
556       proto_tree_add_item(node_tree, hf_nbp_node_node, tvb, offset, 1, FALSE);
557       offset++;
558       proto_tree_add_item(node_tree, hf_nbp_node_port, tvb, offset, 1, FALSE);
559       offset++;
560       proto_tree_add_item(node_tree, hf_nbp_node_enum, tvb, offset, 1, FALSE);
561       offset++;
562
563       offset = dissect_pascal_string(tvb, offset, node_tree, hf_nbp_node_object);
564       offset = dissect_pascal_string(tvb, offset, node_tree, hf_nbp_node_type);
565       offset = dissect_pascal_string(tvb, offset, node_tree, hf_nbp_node_zone);
566
567       proto_item_set_len(node_item, offset-soffset);
568     }
569   }
570
571   return;
572 }
573
574 /* ----------------------------- 
575    FIXME : need desegmentation 
576    atp.function == 0x80 (response)
577    atp.bitmap 0 .. 7
578    until atp.option == 0x10 (end of message)
579 */
580 static void
581 dissect_atp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
582   proto_tree *atp_tree;
583   proto_item *ti;
584   proto_tree *atp_info_tree;
585   proto_item *info_item;
586   int offset = 0;
587   guint8 ctrlinfo;
588   guint op;
589   guint16 tid;
590   struct aspinfo aspinfo;
591   tvbuff_t   *new_tvb;
592   int len;
593   
594   if (check_col(pinfo->cinfo, COL_PROTOCOL))
595     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATP");
596   if (check_col(pinfo->cinfo, COL_INFO))
597     col_clear(pinfo->cinfo, COL_INFO);
598
599   ctrlinfo = tvb_get_guint8(tvb, offset);
600   op = ctrlinfo >> 6;
601   tid = tvb_get_ntohs(tvb, offset +2);
602
603   if (check_col(pinfo->cinfo, COL_INFO)) {
604     col_add_fstr(pinfo->cinfo, COL_INFO, "%s transaction %d", 
605         val_to_str(op, atp_function_vals, "Unknown (0x%01x)"), 
606         tid);
607   }  
608   aspinfo.reply   = (0x80 == (ctrlinfo & ATP_FUNCMASK))?1:0;
609   aspinfo.release = (0xC0 == (ctrlinfo & ATP_FUNCMASK))?1:0;
610
611   aspinfo.seq = tid;
612   aspinfo.code = 0;
613
614   if (tree) {
615     ti = proto_tree_add_item(tree, proto_atp, tvb, offset, -1, FALSE);
616     atp_tree = proto_item_add_subtree(ti, ett_atp);
617     proto_item_set_len(atp_tree, ATP_HDRSIZE -1);
618
619     info_item = proto_tree_add_item(atp_tree, hf_atp_ctrlinfo, tvb, offset, 1, FALSE);
620     atp_info_tree = proto_item_add_subtree(info_item, ett_atp_info);
621
622     proto_tree_add_item(atp_info_tree, hf_atp_function, tvb, offset, 1, FALSE);
623     proto_tree_add_item(atp_info_tree, hf_atp_xo, tvb, offset, 1, FALSE);
624     proto_tree_add_item(atp_info_tree, hf_atp_eom, tvb, offset, 1, FALSE);
625     proto_tree_add_item(atp_info_tree, hf_atp_sts, tvb, offset, 1, FALSE);
626     if ((ctrlinfo & (ATP_FUNCMASK|ATP_XO)) == (0x40|ATP_XO)) {
627       /* TReq with XO set */
628       proto_tree_add_item(atp_info_tree, hf_atp_treltimer, tvb, offset, 1, FALSE);
629     }
630
631     if (!aspinfo.reply) {
632       guint8 bitmap = tvb_get_guint8(tvb, offset +1);
633       guint8 nbe = 0;
634       guint8 t = bitmap;
635                 
636       while(t) {
637         nbe++;
638         t >>= 1;
639       }
640       proto_tree_add_text(atp_tree, tvb, offset +1, 1,
641                           "Bitmap: 0x%02x  %d packet(s) max", bitmap, nbe);
642     }
643     else {
644       proto_tree_add_item(atp_tree, hf_atp_bitmap, tvb, offset +1, 1, FALSE);
645     }
646     proto_tree_add_item(atp_tree, hf_atp_tid, tvb, offset +2, 2, FALSE);
647   }
648
649   pinfo->private_data = &aspinfo;
650   len = tvb_reported_length_remaining(tvb,ATP_HDRSIZE -1);
651   new_tvb = tvb_new_subset(tvb, ATP_HDRSIZE -1,-1,len);
652   call_dissector(asp_handle, new_tvb, pinfo, tree);
653
654   return;
655 }
656
657 /* ----------------------------- */
658 static void
659 dissect_asp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 
660 {
661   struct aspinfo *aspinfo = pinfo->private_data;
662   int offset = 0;
663   proto_tree *asp_tree = NULL;
664   proto_item *ti;
665   guint8 fn;
666   gint32 error;
667   int len;
668   conversation_t        *conversation;
669   asp_request_key request_key, *new_request_key;
670   asp_request_val *request_val;
671     
672   if (check_col(pinfo->cinfo, COL_PROTOCOL))
673     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ASP");
674   if (check_col(pinfo->cinfo, COL_INFO))
675     col_clear(pinfo->cinfo, COL_INFO);
676
677   conversation = find_conversation(&pinfo->src, &pinfo->dst, pinfo->ptype,
678                 pinfo->srcport, pinfo->destport, 0);
679
680   if (conversation == NULL)
681   {
682         conversation = conversation_new(&pinfo->src, &pinfo->dst,
683                         pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
684   }
685
686   request_key.conversation = conversation->index;       
687   request_key.seq = aspinfo->seq;
688
689   request_val = (asp_request_val *) g_hash_table_lookup(
690                                                                 asp_request_hash, &request_key);
691
692   if (!request_val && !aspinfo->reply && !aspinfo->release)  {
693          fn = tvb_get_guint8(tvb, offset);
694          new_request_key = g_mem_chunk_alloc(asp_request_keys);
695          *new_request_key = request_key;
696
697          request_val = g_mem_chunk_alloc(asp_request_vals);
698          request_val->command = fn;
699
700          g_hash_table_insert(asp_request_hash, new_request_key,
701                                                                 request_val);
702   }
703
704   if (!request_val) { 
705         return;
706   }
707
708   fn = request_val->command;
709
710   if (check_col(pinfo->cinfo, COL_INFO)) {
711         if (aspinfo->reply)
712                 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply tid %d",aspinfo->seq);
713         else if (aspinfo->release)
714                 col_add_fstr(pinfo->cinfo, COL_INFO, "Release tid %d",aspinfo->seq);
715         else
716                 col_add_fstr(pinfo->cinfo, COL_INFO, "Function: %s  tid %d",
717                                 val_to_str(fn, asp_func_vals, "Unknown (0x%01x)"), aspinfo->seq);
718   }
719
720   if (tree) {
721     ti = proto_tree_add_item(tree, proto_asp, tvb, offset, -1, FALSE);
722     asp_tree = proto_item_add_subtree(ti, ett_asp);
723     if (!aspinfo->reply && !aspinfo->release) {
724       proto_tree_add_item(asp_tree, hf_asp_func, tvb, offset, 1, FALSE);
725     }
726     else { /* error code */
727       error = tvb_get_ntohl(tvb, offset);
728       if (error <= 0) 
729         proto_tree_add_item(asp_tree, hf_asp_error, tvb, offset, 4, FALSE);
730     }
731   }
732   aspinfo->command = fn;
733   offset += 4;
734   len = tvb_reported_length_remaining(tvb,offset);
735   if (!aspinfo->release &&
736                    (fn == ASPFUNC_CMD || fn  == ASPFUNC_WRITE)) {
737         tvbuff_t   *new_tvb;
738
739         if (len) {
740
741                 if (asp_tree)
742                         proto_item_set_len(asp_tree, 4); 
743                 new_tvb = tvb_new_subset(tvb, offset,-1,len);
744                 call_dissector(afp_handle, new_tvb, pinfo, tree);       
745         }
746   }
747   else {        
748         call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,len), pinfo, tree); 
749   }
750 }
751
752
753 static void
754 dissect_ddp_short(tvbuff_t *tvb, packet_info *pinfo, guint8 dnode,
755                   guint8 snode, proto_tree *tree)
756 {
757   guint16 len;
758   guint8  dport;
759   guint8  sport;
760   guint8  type;
761   proto_tree *ddp_tree = NULL;
762   proto_item *ti;
763   static struct atalk_ddp_addr src, dst;
764   tvbuff_t   *new_tvb;
765
766   if (check_col(pinfo->cinfo, COL_PROTOCOL))
767     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DDP");
768   if (check_col(pinfo->cinfo, COL_INFO))
769     col_clear(pinfo->cinfo, COL_INFO);
770
771   if (tree) {
772     ti = proto_tree_add_item(tree, proto_ddp, tvb, 0, DDP_SHORT_HEADER_SIZE,
773                              FALSE);
774     ddp_tree = proto_item_add_subtree(ti, ett_ddp);
775   }
776   len = tvb_get_ntohs(tvb, 0);
777   if (tree)
778       proto_tree_add_uint(ddp_tree, hf_ddp_len, tvb, 0, 2, len);
779   dport = tvb_get_guint8(tvb, 2);
780   if (tree)
781     proto_tree_add_uint(ddp_tree, hf_ddp_dst_socket, tvb, 2, 1, dport);
782   sport = tvb_get_guint8(tvb, 3);
783   if (tree)
784     proto_tree_add_uint(ddp_tree, hf_ddp_src_socket, tvb, 3, 1, sport);
785   type = tvb_get_guint8(tvb, 4);
786   
787   src.net = 0;
788   src.node = snode;
789   src.port = sport;
790   dst.net = 0;
791   dst.node = dnode;
792   dst.port = dport;
793   SET_ADDRESS(&pinfo->net_src, AT_ATALK, sizeof src, (guint8 *)&src);
794   SET_ADDRESS(&pinfo->src, AT_ATALK, sizeof src, (guint8 *)&src);
795   SET_ADDRESS(&pinfo->net_dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
796   SET_ADDRESS(&pinfo->dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
797
798   if (check_col(pinfo->cinfo, COL_INFO)) {
799     col_add_str(pinfo->cinfo, COL_INFO,
800       val_to_str(type, op_vals, "Unknown DDP protocol (%02x)"));
801   }
802   if (tree)
803     proto_tree_add_uint(ddp_tree, hf_ddp_type, tvb, 4, 1, type);
804   
805   new_tvb = tvb_new_subset(tvb, DDP_SHORT_HEADER_SIZE, -1, -1);
806
807   if (!dissector_try_port(ddp_dissector_table, type, new_tvb, pinfo, tree))
808     call_dissector(data_handle,new_tvb, pinfo, tree);
809 }
810
811 static void
812 dissect_ddp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
813 {
814   e_ddp       ddp;
815   proto_tree *ddp_tree;
816   proto_item *ti;
817   static struct atalk_ddp_addr src, dst;
818   tvbuff_t   *new_tvb;
819
820   if (check_col(pinfo->cinfo, COL_PROTOCOL))
821     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DDP");
822   if (check_col(pinfo->cinfo, COL_INFO))
823     col_clear(pinfo->cinfo, COL_INFO);
824
825   tvb_memcpy(tvb, (guint8 *)&ddp, 0, sizeof(e_ddp));
826   ddp.dnet=ntohs(ddp.dnet);
827   ddp.snet=ntohs(ddp.snet);
828   ddp.sum=ntohs(ddp.sum);
829   ddp.hops_len=ntohs(ddp.hops_len);
830   
831   src.net = ddp.snet;
832   src.node = ddp.snode;
833   src.port = ddp.sport;
834   dst.net = ddp.dnet;
835   dst.node = ddp.dnode;
836   dst.port = ddp.dport;
837   SET_ADDRESS(&pinfo->net_src, AT_ATALK, sizeof src, (guint8 *)&src);
838   SET_ADDRESS(&pinfo->src, AT_ATALK, sizeof src, (guint8 *)&src);
839   SET_ADDRESS(&pinfo->net_dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
840   SET_ADDRESS(&pinfo->dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
841
842   if (check_col(pinfo->cinfo, COL_INFO))
843     col_add_str(pinfo->cinfo, COL_INFO,
844       val_to_str(ddp.type, op_vals, "Unknown DDP protocol (%02x)"));
845   
846   if (tree) {
847     ti = proto_tree_add_item(tree, proto_ddp, tvb, 0, DDP_HEADER_SIZE,
848                              FALSE);
849     ddp_tree = proto_item_add_subtree(ti, ett_ddp);
850     proto_tree_add_uint(ddp_tree, hf_ddp_hopcount,   tvb, 0, 1,
851                         ddp_hops(ddp.hops_len));
852     proto_tree_add_uint(ddp_tree, hf_ddp_len,        tvb, 0, 2, 
853                         ddp_len(ddp.hops_len));
854     proto_tree_add_uint(ddp_tree, hf_ddp_checksum,   tvb, 2,  2,
855                         ddp.sum);
856     proto_tree_add_uint(ddp_tree, hf_ddp_dst_net,    tvb, 4,  2,
857                         ddp.dnet);
858     proto_tree_add_uint(ddp_tree, hf_ddp_src_net,    tvb, 6,  2,
859                         ddp.snet);
860     proto_tree_add_uint(ddp_tree, hf_ddp_dst_node,   tvb, 8,  1,
861                         ddp.dnode);
862     proto_tree_add_uint(ddp_tree, hf_ddp_src_node,   tvb, 9,  1,
863                         ddp.snode);
864     proto_tree_add_uint(ddp_tree, hf_ddp_dst_socket, tvb, 10, 1,
865                         ddp.dport);
866     proto_tree_add_uint(ddp_tree, hf_ddp_src_socket, tvb, 11, 1,
867                         ddp.sport);
868     proto_tree_add_uint(ddp_tree, hf_ddp_type,       tvb, 12, 1,
869                         ddp.type);  
870   }
871
872   new_tvb = tvb_new_subset(tvb, DDP_HEADER_SIZE, -1, -1);
873
874   if (!dissector_try_port(ddp_dissector_table, ddp.type, new_tvb, pinfo, tree))
875     call_dissector(data_handle,new_tvb, pinfo, tree);
876 }
877
878 static const value_string llap_type_vals[] = {
879   {0x01, "Short DDP"},
880   {0x02, "DDP" },
881   {0x81, "Enquiry"},
882   {0x82, "Acknowledgement"},
883   {0x84, "RTS"},
884   {0x85, "CTS"},
885   {0, NULL}
886 };
887
888 void
889 capture_llap(packet_counts *ld)
890 {
891   ld->other++;
892 }
893
894 static void
895 dissect_llap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
896 {
897   guint8 dnode;
898   guint8 snode;
899   guint8 type;
900   proto_tree *llap_tree = NULL;
901   proto_item *ti;
902   tvbuff_t   *new_tvb;
903
904   if (check_col(pinfo->cinfo, COL_PROTOCOL))
905     col_set_str(pinfo->cinfo, COL_PROTOCOL, "LLAP");
906   if (check_col(pinfo->cinfo, COL_INFO))
907     col_clear(pinfo->cinfo, COL_INFO);
908
909   if (tree) {
910     ti = proto_tree_add_item(tree, proto_llap, tvb, 0, 3, FALSE);
911     llap_tree = proto_item_add_subtree(ti, ett_llap);
912   }
913
914   dnode = tvb_get_guint8(tvb, 0);
915   if (tree)  
916     proto_tree_add_uint(llap_tree, hf_llap_dst, tvb, 0, 1, dnode);
917   snode = tvb_get_guint8(tvb, 1);
918   if (tree)
919     proto_tree_add_uint(llap_tree, hf_llap_src, tvb, 1, 1, snode);
920   type = tvb_get_guint8(tvb, 2);
921   if (check_col(pinfo->cinfo, COL_INFO)) {
922     col_add_str(pinfo->cinfo, COL_INFO,
923       val_to_str(type, llap_type_vals, "Unknown LLAP type (%02x)"));
924   }
925   if (tree)
926     proto_tree_add_uint(llap_tree, hf_llap_type, tvb, 2, 1, type);
927   
928   new_tvb = tvb_new_subset(tvb, 3, -1, -1);
929
930   if (proto_is_protocol_enabled(proto_ddp)) {
931     pinfo->current_proto = "DDP";
932     switch (type) {
933
934     case 0x01:
935       dissect_ddp_short(new_tvb, pinfo, dnode, snode, tree);
936       return;
937
938     case 0x02:
939       dissect_ddp(new_tvb, pinfo, tree);
940       return;
941     }
942   }
943   call_dissector(data_handle,new_tvb, pinfo, tree);
944 }
945
946 static void asp_reinit( void)
947 {
948
949         if (asp_request_hash)
950                 g_hash_table_destroy(asp_request_hash);
951         if (asp_request_keys)
952                 g_mem_chunk_destroy(asp_request_keys);
953         if (asp_request_vals)
954                 g_mem_chunk_destroy(asp_request_vals);
955
956         asp_request_hash = g_hash_table_new(asp_hash, asp_equal);
957
958         asp_request_keys = g_mem_chunk_new("asp_request_keys",
959                 sizeof(asp_request_key),
960                 asp_packet_init_count * sizeof(asp_request_key),
961                 G_ALLOC_AND_FREE);
962         asp_request_vals = g_mem_chunk_new("asp_request_vals",
963                 sizeof(asp_request_val),
964                 asp_packet_init_count * sizeof(asp_request_val),
965                 G_ALLOC_AND_FREE);
966
967 }
968
969 void
970 proto_register_atalk(void)
971 {
972   static hf_register_info hf_llap[] = {
973     { &hf_llap_dst,
974       { "Destination Node",     "llap.dst",     FT_UINT8,  BASE_DEC, NULL, 0x0,
975         "", HFILL }},
976
977     { &hf_llap_src,
978       { "Source Node",          "llap.src",     FT_UINT8,  BASE_DEC, NULL, 0x0,
979         "", HFILL }},
980
981     { &hf_llap_type,
982       { "Type",                 "llap.type",    FT_UINT8,  BASE_HEX, VALS(llap_type_vals), 0x0,
983         "", HFILL }},
984   };
985
986   static hf_register_info hf_ddp[] = {
987     { &hf_ddp_hopcount,
988       { "Hop count",            "ddp.hopcount", FT_UINT8,  BASE_DEC, NULL, 0x0,
989         "", HFILL }},
990
991     { &hf_ddp_len,
992       { "Datagram length",      "ddp.len",      FT_UINT16, BASE_DEC, NULL, 0x0,
993         "", HFILL }},
994
995     { &hf_ddp_checksum,
996       { "Checksum",             "ddp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0,
997         "", HFILL }},
998
999     { &hf_ddp_dst_net,
1000       { "Destination Net",      "ddp.dst.net",  FT_UINT16, BASE_DEC, NULL, 0x0,
1001         "", HFILL }},
1002
1003     { &hf_ddp_src_net,
1004       { "Source Net",           "ddp.src.net",  FT_UINT16, BASE_DEC, NULL, 0x0,
1005         "", HFILL }},
1006
1007     { &hf_ddp_dst_node,
1008       { "Destination Node",     "ddp.dst.node", FT_UINT8,  BASE_DEC, NULL, 0x0,
1009         "", HFILL }},
1010
1011     { &hf_ddp_src_node,
1012       { "Source Node",          "ddp.src.node", FT_UINT8,  BASE_DEC, NULL, 0x0,
1013         "", HFILL }},
1014
1015     { &hf_ddp_dst_socket,
1016       { "Destination Socket",   "ddp.dst.socket", FT_UINT8,  BASE_DEC, NULL, 0x0,
1017         "", HFILL }},
1018
1019     { &hf_ddp_src_socket,
1020       { "Source Socket",        "ddp.src.socket", FT_UINT8,  BASE_DEC, NULL, 0x0,
1021         "", HFILL }},
1022
1023     { &hf_ddp_type,
1024       { "Protocol type",        "ddp.type",     FT_UINT8,  BASE_DEC, VALS(op_vals), 0x0,
1025         "", HFILL }},
1026   };
1027
1028   static hf_register_info hf_nbp[] = {
1029     { &hf_nbp_op,
1030       { "Operation",            "nbp.op",       FT_UINT8,  BASE_DEC, 
1031                 VALS(nbp_op_vals), 0xF0, "Operation", HFILL }},
1032     { &hf_nbp_info,
1033       { "Info",         "nbp.info",     FT_UINT8,  BASE_HEX, 
1034                 NULL, 0x0, "Info", HFILL }},
1035     { &hf_nbp_count,
1036       { "Count",                "nbp.count",    FT_UINT8,  BASE_DEC, 
1037                 NULL, 0x0F, "Count", HFILL }},
1038     { &hf_nbp_node_net,
1039       { "Network",              "nbp.net",      FT_UINT16,  BASE_DEC, 
1040                 NULL, 0x0, "Network", HFILL }},
1041     { &hf_nbp_node_node,
1042       { "Node",         "nbp.node",     FT_UINT8,  BASE_DEC, 
1043                 NULL, 0x0, "Node", HFILL }},
1044     { &hf_nbp_node_port,
1045       { "Port",         "nbp.port",     FT_UINT8,  BASE_DEC, 
1046                 NULL, 0x0, "Port", HFILL }},
1047     { &hf_nbp_node_enum,
1048       { "Enumerator",           "nbp.enum",     FT_UINT8,  BASE_DEC, 
1049                 NULL, 0x0, "Enumerator", HFILL }},
1050     { &hf_nbp_node_object,
1051       { "Object",               "nbp.object",   FT_STRING,  BASE_DEC, 
1052                 NULL, 0x0, "Object", HFILL }},
1053     { &hf_nbp_node_type,
1054       { "Type",         "nbp.type",     FT_STRING,  BASE_DEC, 
1055                 NULL, 0x0, "Type", HFILL }},
1056     { &hf_nbp_node_zone,
1057       { "Zone",         "nbp.zone",     FT_STRING,  BASE_DEC, 
1058                 NULL, 0x0, "Zone", HFILL }},
1059     { &hf_nbp_tid,
1060       { "Transaction ID",               "nbp.tid",      FT_UINT8,  BASE_DEC, 
1061                 NULL, 0x0, "Transaction ID", HFILL }}
1062   };
1063
1064   static hf_register_info hf_rtmp[] = {
1065     { &hf_rtmp_net,
1066       { "Net",          "rtmp.net",     FT_UINT16,  BASE_DEC, 
1067                 NULL, 0x0, "Net", HFILL }},
1068     { &hf_rtmp_node,
1069       { "Node",         "nbp.nodeid",   FT_UINT8,  BASE_DEC, 
1070                 NULL, 0x0, "Node", HFILL }},
1071     { &hf_rtmp_node_len,
1072       { "Node Length",          "nbp.nodeid.length",    FT_UINT8,  BASE_DEC, 
1073                 NULL, 0x0, "Node Length", HFILL }},
1074     { &hf_rtmp_tuple_net,
1075       { "Net",          "rtmp.tuple.net",       FT_UINT16,  BASE_DEC, 
1076                 NULL, 0x0, "Net", HFILL }},
1077     { &hf_rtmp_tuple_range_start,
1078       { "Range Start",          "rtmp.tuple.range_start",       FT_UINT16,  BASE_DEC, 
1079                 NULL, 0x0, "Range Start", HFILL }},
1080     { &hf_rtmp_tuple_range_end,
1081       { "Range End",            "rtmp.tuple.range_end", FT_UINT16,  BASE_DEC, 
1082                 NULL, 0x0, "Range End", HFILL }},
1083     { &hf_rtmp_tuple_dist,
1084       { "Distance",             "rtmp.tuple.dist",      FT_UINT16,  BASE_DEC, 
1085                 NULL, 0x0, "Distance", HFILL }},
1086     { &hf_rtmp_function,
1087       { "Function",             "rtmp.function",        FT_UINT8,  BASE_DEC, 
1088                 VALS(rtmp_function_vals), 0x0, "Request Function", HFILL }}
1089   };
1090
1091   static hf_register_info hf_atp[] = {
1092     { &hf_atp_ctrlinfo,
1093       { "Control info",         "atp.ctrlinfo", FT_UINT8,  BASE_HEX, 
1094                 NULL, 0, "control info", HFILL }},
1095
1096     { &hf_atp_function,
1097       { "Function",             "atp.function", FT_UINT8,  BASE_DEC, 
1098                 VALS(atp_function_vals), ATP_FUNCMASK, "function code", HFILL }},
1099
1100
1101     { &hf_atp_xo,
1102       { "XO",           "atp.xo",       FT_BOOLEAN,  8,
1103                 NULL, ATP_XO, "Exactly-once flag", HFILL }},
1104
1105     { &hf_atp_eom,
1106       { "EOM",          "atp.eom",      FT_BOOLEAN,  8,
1107                 NULL, ATP_EOM, "End-of-message", HFILL }},
1108
1109     { &hf_atp_sts,
1110       { "STS",          "atp.sts",      FT_BOOLEAN,  8,
1111                 NULL, ATP_STS, "Send transaction status", HFILL }},
1112
1113     { &hf_atp_treltimer,
1114       { "TRel timer",           "atp.treltimer",        FT_UINT8,  BASE_DEC,
1115                 VALS(atp_trel_timer_vals), 0x07, "TRel timer", HFILL }},
1116
1117     { &hf_atp_bitmap,
1118       { "Bitmap",               "atp.bitmap",   FT_UINT8,  BASE_HEX, 
1119                 NULL, 0x0, "bitmap or sequence number", HFILL }},
1120     { &hf_atp_tid,
1121       { "tid",          "atp.tid",      FT_UINT16,  BASE_DEC, 
1122                 NULL, 0,   "transaction id", HFILL }},
1123   };
1124
1125   static hf_register_info hf_asp[] = {
1126     { &hf_asp_func,
1127       { "asp function",         "asp.function", FT_UINT8,  BASE_DEC, 
1128                 VALS(asp_func_vals), 0, "asp function", HFILL }},
1129
1130     { &hf_asp_error,
1131       { "asp error",            "asp.error",    FT_INT32,  BASE_DEC, 
1132                 VALS(asp_error_vals), 0, "return error code", HFILL }},
1133   };
1134   
1135   static gint *ett[] = {
1136         &ett_llap,
1137         &ett_ddp,
1138         &ett_atp,
1139         &ett_atp_info,
1140         &ett_asp,
1141         &ett_nbp,
1142         &ett_nbp_info,
1143         &ett_nbp_node,
1144         &ett_pstring,
1145         &ett_rtmp,
1146         &ett_rtmp_tuple,
1147   };
1148
1149   proto_llap = proto_register_protocol("LocalTalk Link Access Protocol", "LLAP", "llap");
1150   proto_register_field_array(proto_llap, hf_llap, array_length(hf_llap));
1151
1152   proto_ddp = proto_register_protocol("Datagram Delivery Protocol", "DDP", "ddp");
1153   proto_register_field_array(proto_ddp, hf_ddp, array_length(hf_ddp));
1154
1155   proto_nbp = proto_register_protocol("Name Binding Protocol", "NBP", "nbp");
1156   proto_register_field_array(proto_nbp, hf_nbp, array_length(hf_nbp));
1157
1158   proto_atp = proto_register_protocol("AppleTalk Transaction Protocol packet", "ATP", "atp");
1159   proto_register_field_array(proto_atp, hf_atp, array_length(hf_atp));
1160
1161   proto_asp = proto_register_protocol("AppleTalk Session Protocol", "ASP", "asp");
1162   proto_register_field_array(proto_asp, hf_asp, array_length(hf_asp));
1163
1164   proto_rtmp = proto_register_protocol("Routing Table Maintenance Protocol",
1165                                        "RTMP", "rtmp");
1166   proto_register_field_array(proto_rtmp, hf_rtmp, array_length(hf_rtmp));
1167
1168   proto_register_subtree_array(ett, array_length(ett));
1169
1170   /* subdissector code */
1171   ddp_dissector_table = register_dissector_table("ddp.type", "DDP packet type",
1172                                                  FT_UINT8, BASE_HEX);
1173 }
1174
1175 void
1176 proto_reg_handoff_atalk(void)
1177 {
1178   dissector_handle_t ddp_handle, nbp_handle, rtmp_request_handle;
1179   dissector_handle_t atp_handle;
1180   dissector_handle_t rtmp_data_handle, llap_handle;
1181
1182   ddp_handle = create_dissector_handle(dissect_ddp, proto_ddp);
1183   dissector_add("ethertype", ETHERTYPE_ATALK, ddp_handle);
1184   dissector_add("chdlctype", ETHERTYPE_ATALK, ddp_handle);
1185   dissector_add("ppp.protocol", PPP_AT, ddp_handle);
1186   dissector_add("null.type", BSD_AF_APPLETALK, ddp_handle);
1187
1188   nbp_handle = create_dissector_handle(dissect_nbp, proto_nbp);
1189   dissector_add("ddp.type", DDP_NBP, nbp_handle);
1190
1191   atp_handle = create_dissector_handle(dissect_atp, proto_atp);
1192   dissector_add("ddp.type", DDP_ATP, atp_handle);
1193
1194   asp_handle = create_dissector_handle(dissect_asp, proto_asp);
1195
1196   rtmp_request_handle = create_dissector_handle(dissect_rtmp_request, proto_rtmp);
1197   rtmp_data_handle = create_dissector_handle(dissect_rtmp_data, proto_rtmp);
1198   dissector_add("ddp.type", DDP_RTMPREQ, rtmp_request_handle);
1199   dissector_add("ddp.type", DDP_RTMPDATA, rtmp_data_handle);
1200
1201   llap_handle = create_dissector_handle(dissect_llap, proto_llap);
1202   dissector_add("wtap_encap", WTAP_ENCAP_LOCALTALK, llap_handle);
1203
1204   register_init_routine( &asp_reinit);
1205
1206   afp_handle = find_dissector("afp");
1207   data_handle = find_dissector("data");
1208 }