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