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