vendor/TCPDUMP: Import libpcap 4.99.1
[dragonfly.git] / contrib / tcpdump / print-rx.c
1 /*
2  * Copyright: (c) 2000 United States Government as represented by the
3  *      Secretary of the Navy. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *   2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in
13  *      the documentation and/or other materials provided with the
14  *      distribution.
15  *   3. The names of the authors may not be used to endorse or promote
16  *      products derived from this software without specific prior
17  *      written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23
24 /* \summary: AFS RX printer */
25
26 /*
27  * This code unmangles RX packets.  RX is the mutant form of RPC that AFS
28  * uses to communicate between clients and servers.
29  *
30  * In this code, I mainly concern myself with decoding the AFS calls, not
31  * with the guts of RX, per se.
32  *
33  * Bah.  If I never look at rx_packet.h again, it will be too soon.
34  *
35  * Ken Hornstein <kenh@cmf.nrl.navy.mil>
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <stdio.h>
43 #include <string.h>
44 #include "netdissect-stdinc.h"
45
46 #include "netdissect.h"
47 #include "addrtoname.h"
48 #include "extract.h"
49
50 #include "ip.h"
51
52 #define FS_RX_PORT      7000
53 #define CB_RX_PORT      7001
54 #define PROT_RX_PORT    7002
55 #define VLDB_RX_PORT    7003
56 #define KAUTH_RX_PORT   7004
57 #define VOL_RX_PORT     7005
58 #define ERROR_RX_PORT   7006            /* Doesn't seem to be used */
59 #define BOS_RX_PORT     7007
60
61 #define AFSOPAQUEMAX 1024
62 #define AFSNAMEMAX 256                  /* Must be >= PRNAMEMAX + 1, VLNAMEMAX + 1, and 32 + 1 */
63 #define PRNAMEMAX 64
64 #define VLNAMEMAX 65
65 #define KANAMEMAX 64
66 #define BOSNAMEMAX 256
67 #define USERNAMEMAX 1024                /* AFSOPAQUEMAX was used for this; does it need to be this big? */
68
69 #define PRSFS_READ              1 /* Read files */
70 #define PRSFS_WRITE             2 /* Write files */
71 #define PRSFS_INSERT            4 /* Insert files into a directory */
72 #define PRSFS_LOOKUP            8 /* Lookup files into a directory */
73 #define PRSFS_DELETE            16 /* Delete files */
74 #define PRSFS_LOCK              32 /* Lock files */
75 #define PRSFS_ADMINISTER        64 /* Change ACL's */
76
77 struct rx_header {
78         nd_uint32_t epoch;
79         nd_uint32_t cid;
80         nd_uint32_t callNumber;
81         nd_uint32_t seq;
82         nd_uint32_t serial;
83         nd_uint8_t type;
84 #define RX_PACKET_TYPE_DATA             1
85 #define RX_PACKET_TYPE_ACK              2
86 #define RX_PACKET_TYPE_BUSY             3
87 #define RX_PACKET_TYPE_ABORT            4
88 #define RX_PACKET_TYPE_ACKALL           5
89 #define RX_PACKET_TYPE_CHALLENGE        6
90 #define RX_PACKET_TYPE_RESPONSE         7
91 #define RX_PACKET_TYPE_DEBUG            8
92 #define RX_PACKET_TYPE_PARAMS           9
93 #define RX_PACKET_TYPE_VERSION          13
94         nd_uint8_t flags;
95 #define RX_CLIENT_INITIATED     1
96 #define RX_REQUEST_ACK          2
97 #define RX_LAST_PACKET          4
98 #define RX_MORE_PACKETS         8
99 #define RX_FREE_PACKET          16
100 #define RX_SLOW_START_OK        32
101 #define RX_JUMBO_PACKET         32
102         nd_uint8_t userStatus;
103         nd_uint8_t securityIndex;
104         nd_uint16_t spare;              /* How clever: even though the AFS */
105         nd_uint16_t serviceId;          /* header files indicate that the */
106 };                                      /* serviceId is first, it's really */
107                                         /* encoded _after_ the spare field */
108                                         /* I wasted a day figuring that out! */
109
110 #define NUM_RX_FLAGS 7
111
112 #define RX_MAXACKS 255
113
114 struct rx_ackPacket {
115         nd_uint16_t bufferSpace;        /* Number of packet buffers available */
116         nd_uint16_t maxSkew;            /* Max diff between ack'd packet and */
117                                         /* highest packet received */
118         nd_uint32_t firstPacket;        /* The first packet in ack list */
119         nd_uint32_t previousPacket;     /* Previous packet recv'd (obsolete) */
120         nd_uint32_t serial;             /* # of packet that prompted the ack */
121         nd_uint8_t reason;              /* Reason for acknowledgement */
122         nd_uint8_t nAcks;               /* Number of acknowledgements */
123         /* Followed by nAcks acknowledgments */
124 #if 0
125         uint8_t acks[RX_MAXACKS];       /* Up to RX_MAXACKS acknowledgements */
126 #endif
127 };
128
129 /*
130  * Values for the acks array
131  */
132
133 #define RX_ACK_TYPE_NACK        0       /* Don't have this packet */
134 #define RX_ACK_TYPE_ACK         1       /* I have this packet */
135
136 static const struct tok rx_types[] = {
137         { RX_PACKET_TYPE_DATA,          "data" },
138         { RX_PACKET_TYPE_ACK,           "ack" },
139         { RX_PACKET_TYPE_BUSY,          "busy" },
140         { RX_PACKET_TYPE_ABORT,         "abort" },
141         { RX_PACKET_TYPE_ACKALL,        "ackall" },
142         { RX_PACKET_TYPE_CHALLENGE,     "challenge" },
143         { RX_PACKET_TYPE_RESPONSE,      "response" },
144         { RX_PACKET_TYPE_DEBUG,         "debug" },
145         { RX_PACKET_TYPE_PARAMS,        "params" },
146         { RX_PACKET_TYPE_VERSION,       "version" },
147         { 0,                            NULL },
148 };
149
150 static const struct double_tok {
151         uint32_t flag;          /* Rx flag */
152         uint32_t packetType;    /* Packet type */
153         const char *s;          /* Flag string */
154 } rx_flags[] = {
155         { RX_CLIENT_INITIATED,  0,                      "client-init" },
156         { RX_REQUEST_ACK,       0,                      "req-ack" },
157         { RX_LAST_PACKET,       0,                      "last-pckt" },
158         { RX_MORE_PACKETS,      0,                      "more-pckts" },
159         { RX_FREE_PACKET,       0,                      "free-pckt" },
160         { RX_SLOW_START_OK,     RX_PACKET_TYPE_ACK,     "slow-start" },
161         { RX_JUMBO_PACKET,      RX_PACKET_TYPE_DATA,    "jumbogram" }
162 };
163
164 static const struct tok fs_req[] = {
165         { 130,          "fetch-data" },
166         { 131,          "fetch-acl" },
167         { 132,          "fetch-status" },
168         { 133,          "store-data" },
169         { 134,          "store-acl" },
170         { 135,          "store-status" },
171         { 136,          "remove-file" },
172         { 137,          "create-file" },
173         { 138,          "rename" },
174         { 139,          "symlink" },
175         { 140,          "link" },
176         { 141,          "makedir" },
177         { 142,          "rmdir" },
178         { 143,          "oldsetlock" },
179         { 144,          "oldextlock" },
180         { 145,          "oldrellock" },
181         { 146,          "get-stats" },
182         { 147,          "give-cbs" },
183         { 148,          "get-vlinfo" },
184         { 149,          "get-vlstats" },
185         { 150,          "set-vlstats" },
186         { 151,          "get-rootvl" },
187         { 152,          "check-token" },
188         { 153,          "get-time" },
189         { 154,          "nget-vlinfo" },
190         { 155,          "bulk-stat" },
191         { 156,          "setlock" },
192         { 157,          "extlock" },
193         { 158,          "rellock" },
194         { 159,          "xstat-ver" },
195         { 160,          "get-xstat" },
196         { 161,          "dfs-lookup" },
197         { 162,          "dfs-flushcps" },
198         { 163,          "dfs-symlink" },
199         { 220,          "residency" },
200         { 65536,        "inline-bulk-status" },
201         { 65537,        "fetch-data-64" },
202         { 65538,        "store-data-64" },
203         { 65539,        "give-up-all-cbs" },
204         { 65540,        "get-caps" },
205         { 65541,        "cb-rx-conn-addr" },
206         { 0,            NULL },
207 };
208
209 static const struct tok cb_req[] = {
210         { 204,          "callback" },
211         { 205,          "initcb" },
212         { 206,          "probe" },
213         { 207,          "getlock" },
214         { 208,          "getce" },
215         { 209,          "xstatver" },
216         { 210,          "getxstat" },
217         { 211,          "initcb2" },
218         { 212,          "whoareyou" },
219         { 213,          "initcb3" },
220         { 214,          "probeuuid" },
221         { 215,          "getsrvprefs" },
222         { 216,          "getcellservdb" },
223         { 217,          "getlocalcell" },
224         { 218,          "getcacheconf" },
225         { 65536,        "getce64" },
226         { 65537,        "getcellbynum" },
227         { 65538,        "tellmeaboutyourself" },
228         { 0,            NULL },
229 };
230
231 static const struct tok pt_req[] = {
232         { 500,          "new-user" },
233         { 501,          "where-is-it" },
234         { 502,          "dump-entry" },
235         { 503,          "add-to-group" },
236         { 504,          "name-to-id" },
237         { 505,          "id-to-name" },
238         { 506,          "delete" },
239         { 507,          "remove-from-group" },
240         { 508,          "get-cps" },
241         { 509,          "new-entry" },
242         { 510,          "list-max" },
243         { 511,          "set-max" },
244         { 512,          "list-entry" },
245         { 513,          "change-entry" },
246         { 514,          "list-elements" },
247         { 515,          "same-mbr-of" },
248         { 516,          "set-fld-sentry" },
249         { 517,          "list-owned" },
250         { 518,          "get-cps2" },
251         { 519,          "get-host-cps" },
252         { 520,          "update-entry" },
253         { 521,          "list-entries" },
254         { 530,          "list-super-groups" },
255         { 0,            NULL },
256 };
257
258 static const struct tok vldb_req[] = {
259         { 501,          "create-entry" },
260         { 502,          "delete-entry" },
261         { 503,          "get-entry-by-id" },
262         { 504,          "get-entry-by-name" },
263         { 505,          "get-new-volume-id" },
264         { 506,          "replace-entry" },
265         { 507,          "update-entry" },
266         { 508,          "setlock" },
267         { 509,          "releaselock" },
268         { 510,          "list-entry" },
269         { 511,          "list-attrib" },
270         { 512,          "linked-list" },
271         { 513,          "get-stats" },
272         { 514,          "probe" },
273         { 515,          "get-addrs" },
274         { 516,          "change-addr" },
275         { 517,          "create-entry-n" },
276         { 518,          "get-entry-by-id-n" },
277         { 519,          "get-entry-by-name-n" },
278         { 520,          "replace-entry-n" },
279         { 521,          "list-entry-n" },
280         { 522,          "list-attrib-n" },
281         { 523,          "linked-list-n" },
282         { 524,          "update-entry-by-name" },
283         { 525,          "create-entry-u" },
284         { 526,          "get-entry-by-id-u" },
285         { 527,          "get-entry-by-name-u" },
286         { 528,          "replace-entry-u" },
287         { 529,          "list-entry-u" },
288         { 530,          "list-attrib-u" },
289         { 531,          "linked-list-u" },
290         { 532,          "regaddr" },
291         { 533,          "get-addrs-u" },
292         { 534,          "list-attrib-n2" },
293         { 0,            NULL },
294 };
295
296 static const struct tok kauth_req[] = {
297         { 1,            "auth-old" },
298         { 21,           "authenticate" },
299         { 22,           "authenticate-v2" },
300         { 2,            "change-pw" },
301         { 3,            "get-ticket-old" },
302         { 23,           "get-ticket" },
303         { 4,            "set-pw" },
304         { 5,            "set-fields" },
305         { 6,            "create-user" },
306         { 7,            "delete-user" },
307         { 8,            "get-entry" },
308         { 9,            "list-entry" },
309         { 10,           "get-stats" },
310         { 11,           "debug" },
311         { 12,           "get-pw" },
312         { 13,           "get-random-key" },
313         { 14,           "unlock" },
314         { 15,           "lock-status" },
315         { 0,            NULL },
316 };
317
318 static const struct tok vol_req[] = {
319         { 100,          "create-volume" },
320         { 101,          "delete-volume" },
321         { 102,          "restore" },
322         { 103,          "forward" },
323         { 104,          "end-trans" },
324         { 105,          "clone" },
325         { 106,          "set-flags" },
326         { 107,          "get-flags" },
327         { 108,          "trans-create" },
328         { 109,          "dump" },
329         { 110,          "get-nth-volume" },
330         { 111,          "set-forwarding" },
331         { 112,          "get-name" },
332         { 113,          "get-status" },
333         { 114,          "sig-restore" },
334         { 115,          "list-partitions" },
335         { 116,          "list-volumes" },
336         { 117,          "set-id-types" },
337         { 118,          "monitor" },
338         { 119,          "partition-info" },
339         { 120,          "reclone" },
340         { 121,          "list-one-volume" },
341         { 122,          "nuke" },
342         { 123,          "set-date" },
343         { 124,          "x-list-volumes" },
344         { 125,          "x-list-one-volume" },
345         { 126,          "set-info" },
346         { 127,          "x-list-partitions" },
347         { 128,          "forward-multiple" },
348         { 65536,        "convert-ro" },
349         { 65537,        "get-size" },
350         { 65538,        "dump-v2" },
351         { 0,            NULL },
352 };
353
354 static const struct tok bos_req[] = {
355         { 80,           "create-bnode" },
356         { 81,           "delete-bnode" },
357         { 82,           "set-status" },
358         { 83,           "get-status" },
359         { 84,           "enumerate-instance" },
360         { 85,           "get-instance-info" },
361         { 86,           "get-instance-parm" },
362         { 87,           "add-superuser" },
363         { 88,           "delete-superuser" },
364         { 89,           "list-superusers" },
365         { 90,           "list-keys" },
366         { 91,           "add-key" },
367         { 92,           "delete-key" },
368         { 93,           "set-cell-name" },
369         { 94,           "get-cell-name" },
370         { 95,           "get-cell-host" },
371         { 96,           "add-cell-host" },
372         { 97,           "delete-cell-host" },
373         { 98,           "set-t-status" },
374         { 99,           "shutdown-all" },
375         { 100,          "restart-all" },
376         { 101,          "startup-all" },
377         { 102,          "set-noauth-flag" },
378         { 103,          "re-bozo" },
379         { 104,          "restart" },
380         { 105,          "start-bozo-install" },
381         { 106,          "uninstall" },
382         { 107,          "get-dates" },
383         { 108,          "exec" },
384         { 109,          "prune" },
385         { 110,          "set-restart-time" },
386         { 111,          "get-restart-time" },
387         { 112,          "start-bozo-log" },
388         { 113,          "wait-all" },
389         { 114,          "get-instance-strings" },
390         { 115,          "get-restricted" },
391         { 116,          "set-restricted" },
392         { 0,            NULL },
393 };
394
395 static const struct tok ubik_req[] = {
396         { 10000,        "vote-beacon" },
397         { 10001,        "vote-debug-old" },
398         { 10002,        "vote-sdebug-old" },
399         { 10003,        "vote-getsyncsite" },
400         { 10004,        "vote-debug" },
401         { 10005,        "vote-sdebug" },
402         { 10006,        "vote-xdebug" },
403         { 10007,        "vote-xsdebug" },
404         { 20000,        "disk-begin" },
405         { 20001,        "disk-commit" },
406         { 20002,        "disk-lock" },
407         { 20003,        "disk-write" },
408         { 20004,        "disk-getversion" },
409         { 20005,        "disk-getfile" },
410         { 20006,        "disk-sendfile" },
411         { 20007,        "disk-abort" },
412         { 20008,        "disk-releaselocks" },
413         { 20009,        "disk-truncate" },
414         { 20010,        "disk-probe" },
415         { 20011,        "disk-writev" },
416         { 20012,        "disk-interfaceaddr" },
417         { 20013,        "disk-setversion" },
418         { 0,            NULL },
419 };
420
421 #define VOTE_LOW        10000
422 #define VOTE_HIGH       10007
423 #define DISK_LOW        20000
424 #define DISK_HIGH       20013
425
426 static const struct tok cb_types[] = {
427         { 1,            "exclusive" },
428         { 2,            "shared" },
429         { 3,            "dropped" },
430         { 0,            NULL },
431 };
432
433 static const struct tok ubik_lock_types[] = {
434         { 1,            "read" },
435         { 2,            "write" },
436         { 3,            "wait" },
437         { 0,            NULL },
438 };
439
440 static const char *voltype[] = { "read-write", "read-only", "backup" };
441
442 static const struct tok afs_fs_errors[] = {
443         { 101,          "salvage volume" },
444         { 102,          "no such vnode" },
445         { 103,          "no such volume" },
446         { 104,          "volume exist" },
447         { 105,          "no service" },
448         { 106,          "volume offline" },
449         { 107,          "voline online" },
450         { 108,          "diskfull" },
451         { 109,          "diskquota exceeded" },
452         { 110,          "volume busy" },
453         { 111,          "volume moved" },
454         { 112,          "AFS IO error" },
455         { 0xffffff9c,   "restarting fileserver" }, /* -100, sic! */
456         { 0,            NULL }
457 };
458
459 /*
460  * Reasons for acknowledging a packet
461  */
462
463 static const struct tok rx_ack_reasons[] = {
464         { 1,            "ack requested" },
465         { 2,            "duplicate packet" },
466         { 3,            "out of sequence" },
467         { 4,            "exceeds window" },
468         { 5,            "no buffer space" },
469         { 6,            "ping" },
470         { 7,            "ping response" },
471         { 8,            "delay" },
472         { 9,            "idle" },
473         { 0,            NULL },
474 };
475
476 /*
477  * Cache entries we keep around so we can figure out the RX opcode
478  * numbers for replies.  This allows us to make sense of RX reply packets.
479  */
480
481 struct rx_cache_entry {
482         uint32_t        callnum;        /* Call number (net order) */
483         uint32_t        client;         /* client IP address (net order) */
484         uint32_t        server;         /* server IP address (net order) */
485         uint16_t        dport;          /* server UDP port (host order) */
486         uint16_t        serviceId;      /* Service identifier (net order) */
487         uint32_t        opcode;         /* RX opcode (host order) */
488 };
489
490 #define RX_CACHE_SIZE   64
491
492 static struct rx_cache_entry    rx_cache[RX_CACHE_SIZE];
493
494 static uint32_t rx_cache_next = 0;
495 static uint32_t rx_cache_hint = 0;
496 static void     rx_cache_insert(netdissect_options *, const u_char *, const struct ip *, uint16_t);
497 static int      rx_cache_find(netdissect_options *, const struct rx_header *,
498                               const struct ip *, uint16_t, uint32_t *);
499
500 static void fs_print(netdissect_options *, const u_char *, u_int);
501 static void fs_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
502 static void acl_print(netdissect_options *, u_char *, u_char *);
503 static void cb_print(netdissect_options *, const u_char *, u_int);
504 static void cb_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
505 static void prot_print(netdissect_options *, const u_char *, u_int);
506 static void prot_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
507 static void vldb_print(netdissect_options *, const u_char *, u_int);
508 static void vldb_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
509 static void kauth_print(netdissect_options *, const u_char *, u_int);
510 static void kauth_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
511 static void vol_print(netdissect_options *, const u_char *, u_int);
512 static void vol_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
513 static void bos_print(netdissect_options *, const u_char *, u_int);
514 static void bos_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
515 static void ubik_print(netdissect_options *, const u_char *);
516 static void ubik_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
517
518 static void rx_ack_print(netdissect_options *, const u_char *, u_int);
519
520 static int is_ubik(uint32_t);
521
522 /*
523  * Handle the rx-level packet.  See if we know what port it's going to so
524  * we can peek at the afs call inside
525  */
526
527 void
528 rx_print(netdissect_options *ndo,
529          const u_char *bp, u_int length, uint16_t sport, uint16_t dport,
530          const u_char *bp2)
531 {
532         const struct rx_header *rxh;
533         uint32_t i;
534         uint8_t type, flags;
535         uint32_t opcode;
536
537         ndo->ndo_protocol = "rx";
538         if (!ND_TTEST_LEN(bp, sizeof(struct rx_header))) {
539                 ND_PRINT(" [|rx] (%u)", length);
540                 return;
541         }
542
543         rxh = (const struct rx_header *) bp;
544
545         type = GET_U_1(rxh->type);
546         ND_PRINT(" rx %s", tok2str(rx_types, "type %u", type));
547
548         flags = GET_U_1(rxh->flags);
549         if (ndo->ndo_vflag) {
550                 int firstflag = 0;
551
552                 if (ndo->ndo_vflag > 1)
553                         ND_PRINT(" cid %08x call# %u",
554                                GET_BE_U_4(rxh->cid),
555                                GET_BE_U_4(rxh->callNumber));
556
557                 ND_PRINT(" seq %u ser %u",
558                        GET_BE_U_4(rxh->seq),
559                        GET_BE_U_4(rxh->serial));
560
561                 if (ndo->ndo_vflag > 2)
562                         ND_PRINT(" secindex %u serviceid %hu",
563                                 GET_U_1(rxh->securityIndex),
564                                 GET_BE_U_2(rxh->serviceId));
565
566                 if (ndo->ndo_vflag > 1)
567                         for (i = 0; i < NUM_RX_FLAGS; i++) {
568                                 if (flags & rx_flags[i].flag &&
569                                     (!rx_flags[i].packetType ||
570                                      type == rx_flags[i].packetType)) {
571                                         if (!firstflag) {
572                                                 firstflag = 1;
573                                                 ND_PRINT(" ");
574                                         } else {
575                                                 ND_PRINT(",");
576                                         }
577                                         ND_PRINT("<%s>", rx_flags[i].s);
578                                 }
579                         }
580         }
581
582         /*
583          * Try to handle AFS calls that we know about.  Check the destination
584          * port and make sure it's a data packet.  Also, make sure the
585          * seq number is 1 (because otherwise it's a continuation packet,
586          * and we can't interpret that).  Also, seems that reply packets
587          * do not have the client-init flag set, so we check for that
588          * as well.
589          */
590
591         if (type == RX_PACKET_TYPE_DATA &&
592             GET_BE_U_4(rxh->seq) == 1 &&
593             flags & RX_CLIENT_INITIATED) {
594
595                 /*
596                  * Insert this call into the call cache table, so we
597                  * have a chance to print out replies
598                  */
599
600                 rx_cache_insert(ndo, bp, (const struct ip *) bp2, dport);
601
602                 switch (dport) {
603                         case FS_RX_PORT:        /* AFS file service */
604                                 fs_print(ndo, bp, length);
605                                 break;
606                         case CB_RX_PORT:        /* AFS callback service */
607                                 cb_print(ndo, bp, length);
608                                 break;
609                         case PROT_RX_PORT:      /* AFS protection service */
610                                 prot_print(ndo, bp, length);
611                                 break;
612                         case VLDB_RX_PORT:      /* AFS VLDB service */
613                                 vldb_print(ndo, bp, length);
614                                 break;
615                         case KAUTH_RX_PORT:     /* AFS Kerberos auth service */
616                                 kauth_print(ndo, bp, length);
617                                 break;
618                         case VOL_RX_PORT:       /* AFS Volume service */
619                                 vol_print(ndo, bp, length);
620                                 break;
621                         case BOS_RX_PORT:       /* AFS BOS service */
622                                 bos_print(ndo, bp, length);
623                                 break;
624                         default:
625                                 ;
626                 }
627
628         /*
629          * If it's a reply (client-init is _not_ set, but seq is one)
630          * then look it up in the cache.  If we find it, call the reply
631          * printing functions  Note that we handle abort packets here,
632          * because printing out the return code can be useful at times.
633          */
634
635         } else if (((type == RX_PACKET_TYPE_DATA &&
636                                         GET_BE_U_4(rxh->seq) == 1) ||
637                     type == RX_PACKET_TYPE_ABORT) &&
638                    (flags & RX_CLIENT_INITIATED) == 0 &&
639                    rx_cache_find(ndo, rxh, (const struct ip *) bp2,
640                                  sport, &opcode)) {
641
642                 switch (sport) {
643                         case FS_RX_PORT:        /* AFS file service */
644                                 fs_reply_print(ndo, bp, length, opcode);
645                                 break;
646                         case CB_RX_PORT:        /* AFS callback service */
647                                 cb_reply_print(ndo, bp, length, opcode);
648                                 break;
649                         case PROT_RX_PORT:      /* AFS PT service */
650                                 prot_reply_print(ndo, bp, length, opcode);
651                                 break;
652                         case VLDB_RX_PORT:      /* AFS VLDB service */
653                                 vldb_reply_print(ndo, bp, length, opcode);
654                                 break;
655                         case KAUTH_RX_PORT:     /* AFS Kerberos auth service */
656                                 kauth_reply_print(ndo, bp, length, opcode);
657                                 break;
658                         case VOL_RX_PORT:       /* AFS Volume service */
659                                 vol_reply_print(ndo, bp, length, opcode);
660                                 break;
661                         case BOS_RX_PORT:       /* AFS BOS service */
662                                 bos_reply_print(ndo, bp, length, opcode);
663                                 break;
664                         default:
665                                 ;
666                 }
667
668         /*
669          * If it's an RX ack packet, then use the appropriate ack decoding
670          * function (there isn't any service-specific information in the
671          * ack packet, so we can use one for all AFS services)
672          */
673
674         } else if (type == RX_PACKET_TYPE_ACK)
675                 rx_ack_print(ndo, bp, length);
676
677
678         ND_PRINT(" (%u)", length);
679 }
680
681 /*
682  * Insert an entry into the cache.  Taken from print-nfs.c
683  */
684
685 static void
686 rx_cache_insert(netdissect_options *ndo,
687                 const u_char *bp, const struct ip *ip, uint16_t dport)
688 {
689         struct rx_cache_entry *rxent;
690         const struct rx_header *rxh = (const struct rx_header *) bp;
691
692         if (!ND_TTEST_4(bp + sizeof(struct rx_header)))
693                 return;
694
695         rxent = &rx_cache[rx_cache_next];
696
697         if (++rx_cache_next >= RX_CACHE_SIZE)
698                 rx_cache_next = 0;
699
700         rxent->callnum = GET_BE_U_4(rxh->callNumber);
701         rxent->client = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
702         rxent->server = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
703         rxent->dport = dport;
704         rxent->serviceId = GET_BE_U_2(rxh->serviceId);
705         rxent->opcode = GET_BE_U_4(bp + sizeof(struct rx_header));
706 }
707
708 /*
709  * Lookup an entry in the cache.  Also taken from print-nfs.c
710  *
711  * Note that because this is a reply, we're looking at the _source_
712  * port.
713  */
714
715 static int
716 rx_cache_find(netdissect_options *ndo, const struct rx_header *rxh,
717               const struct ip *ip, uint16_t sport, uint32_t *opcode)
718 {
719         uint32_t i;
720         struct rx_cache_entry *rxent;
721         uint32_t clip;
722         uint32_t sip;
723
724         clip = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
725         sip = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
726
727         /* Start the search where we last left off */
728
729         i = rx_cache_hint;
730         do {
731                 rxent = &rx_cache[i];
732                 if (rxent->callnum == GET_BE_U_4(rxh->callNumber) &&
733                     rxent->client == clip &&
734                     rxent->server == sip &&
735                     rxent->serviceId == GET_BE_U_2(rxh->serviceId) &&
736                     rxent->dport == sport) {
737
738                         /* We got a match! */
739
740                         rx_cache_hint = i;
741                         *opcode = rxent->opcode;
742                         return(1);
743                 }
744                 if (++i >= RX_CACHE_SIZE)
745                         i = 0;
746         } while (i != rx_cache_hint);
747
748         /* Our search failed */
749         return(0);
750 }
751
752 /*
753  * These extremely grody macros handle the printing of various AFS stuff.
754  */
755
756 #define FIDOUT() { uint32_t n1, n2, n3; \
757                         ND_TCHECK_LEN(bp, sizeof(uint32_t) * 3); \
758                         n1 = GET_BE_U_4(bp); \
759                         bp += sizeof(uint32_t); \
760                         n2 = GET_BE_U_4(bp); \
761                         bp += sizeof(uint32_t); \
762                         n3 = GET_BE_U_4(bp); \
763                         bp += sizeof(uint32_t); \
764                         ND_PRINT(" fid %u/%u/%u", n1, n2, n3); \
765                 }
766
767 #define STROUT(MAX) { uint32_t _i; \
768                         _i = GET_BE_U_4(bp); \
769                         if (_i > (MAX)) \
770                                 goto trunc; \
771                         bp += sizeof(uint32_t); \
772                         ND_PRINT(" \""); \
773                         if (nd_printn(ndo, bp, _i, ndo->ndo_snapend)) \
774                                 goto trunc; \
775                         ND_PRINT("\""); \
776                         bp += ((_i + sizeof(uint32_t) - 1) / sizeof(uint32_t)) * sizeof(uint32_t); \
777                 }
778
779 #define INTOUT() { int32_t _i; \
780                         _i = GET_BE_S_4(bp); \
781                         bp += sizeof(int32_t); \
782                         ND_PRINT(" %d", _i); \
783                 }
784
785 #define UINTOUT() { uint32_t _i; \
786                         _i = GET_BE_U_4(bp); \
787                         bp += sizeof(uint32_t); \
788                         ND_PRINT(" %u", _i); \
789                 }
790
791 #define UINT64OUT() { uint64_t _i; \
792                         _i = GET_BE_U_8(bp); \
793                         bp += sizeof(uint64_t); \
794                         ND_PRINT(" %" PRIu64, _i); \
795                 }
796
797 #define DATEOUT() { time_t _t; struct tm *tm; char str[256]; \
798                         _t = (time_t) GET_BE_S_4(bp); \
799                         bp += sizeof(int32_t); \
800                         tm = localtime(&_t); \
801                         strftime(str, 256, "%Y/%m/%d %H:%M:%S", tm); \
802                         ND_PRINT(" %s", str); \
803                 }
804
805 #define STOREATTROUT() { uint32_t mask, _i; \
806                         ND_TCHECK_LEN(bp, (sizeof(uint32_t) * 6)); \
807                         mask = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
808                         if (mask) ND_PRINT(" StoreStatus"); \
809                         if (mask & 1) { ND_PRINT(" date"); DATEOUT(); } \
810                         else bp += sizeof(uint32_t); \
811                         _i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
812                         if (mask & 2) ND_PRINT(" owner %u", _i);  \
813                         _i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
814                         if (mask & 4) ND_PRINT(" group %u", _i); \
815                         _i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
816                         if (mask & 8) ND_PRINT(" mode %o", _i & 07777); \
817                         _i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
818                         if (mask & 16) ND_PRINT(" segsize %u", _i); \
819                         /* undocumented in 3.3 docu */ \
820                         if (mask & 1024) ND_PRINT(" fsync");  \
821                 }
822
823 #define UBIK_VERSIONOUT() {uint32_t epoch; uint32_t counter; \
824                         ND_TCHECK_LEN(bp, sizeof(uint32_t) * 2); \
825                         epoch = GET_BE_U_4(bp); \
826                         bp += sizeof(uint32_t); \
827                         counter = GET_BE_U_4(bp); \
828                         bp += sizeof(uint32_t); \
829                         ND_PRINT(" %u.%u", epoch, counter); \
830                 }
831
832 #define AFSUUIDOUT() {uint32_t temp; int _i; \
833                         ND_TCHECK_LEN(bp, 11 * sizeof(uint32_t)); \
834                         temp = GET_BE_U_4(bp); \
835                         bp += sizeof(uint32_t); \
836                         ND_PRINT(" %08x", temp); \
837                         temp = GET_BE_U_4(bp); \
838                         bp += sizeof(uint32_t); \
839                         ND_PRINT("%04x", temp); \
840                         temp = GET_BE_U_4(bp); \
841                         bp += sizeof(uint32_t); \
842                         ND_PRINT("%04x", temp); \
843                         for (_i = 0; _i < 8; _i++) { \
844                                 temp = GET_BE_U_4(bp); \
845                                 bp += sizeof(uint32_t); \
846                                 ND_PRINT("%02x", (unsigned char) temp); \
847                         } \
848                 }
849
850 /*
851  * This is the sickest one of all
852  * MAX is expected to be a constant here
853  */
854
855 #define VECOUT(MAX) { u_char *sp; \
856                         u_char s[(MAX) + 1]; \
857                         uint32_t k; \
858                         ND_TCHECK_LEN(bp, (MAX) * sizeof(uint32_t)); \
859                         sp = s; \
860                         for (k = 0; k < (MAX); k++) { \
861                                 *sp++ = (u_char) GET_BE_U_4(bp); \
862                                 bp += sizeof(uint32_t); \
863                         } \
864                         s[(MAX)] = '\0'; \
865                         ND_PRINT(" \""); \
866                         fn_print_str(ndo, s); \
867                         ND_PRINT("\""); \
868                 }
869
870 #define DESTSERVEROUT() { uint32_t n1, n2, n3; \
871                         ND_TCHECK_LEN(bp, sizeof(uint32_t) * 3); \
872                         n1 = GET_BE_U_4(bp); \
873                         bp += sizeof(uint32_t); \
874                         n2 = GET_BE_U_4(bp); \
875                         bp += sizeof(uint32_t); \
876                         n3 = GET_BE_U_4(bp); \
877                         bp += sizeof(uint32_t); \
878                         ND_PRINT(" server %u:%u:%u", n1, n2, n3); \
879                 }
880
881 /*
882  * Handle calls to the AFS file service (fs)
883  */
884
885 static void
886 fs_print(netdissect_options *ndo,
887          const u_char *bp, u_int length)
888 {
889         uint32_t fs_op;
890         uint32_t i;
891
892         if (length <= sizeof(struct rx_header))
893                 return;
894
895         /*
896          * Print out the afs call we're invoking.  The table used here was
897          * gleaned from fsint/afsint.xg
898          */
899
900         fs_op = GET_BE_U_4(bp + sizeof(struct rx_header));
901
902         ND_PRINT(" fs call %s", tok2str(fs_req, "op#%u", fs_op));
903
904         /*
905          * Print out arguments to some of the AFS calls.  This stuff is
906          * all from afsint.xg
907          */
908
909         bp += sizeof(struct rx_header) + 4;
910
911         /*
912          * Sigh.  This is gross.  Ritchie forgive me.
913          */
914
915         switch (fs_op) {
916                 case 130:       /* Fetch data */
917                         FIDOUT();
918                         ND_PRINT(" offset");
919                         UINTOUT();
920                         ND_PRINT(" length");
921                         UINTOUT();
922                         break;
923                 case 131:       /* Fetch ACL */
924                 case 132:       /* Fetch Status */
925                 case 143:       /* Old set lock */
926                 case 144:       /* Old extend lock */
927                 case 145:       /* Old release lock */
928                 case 156:       /* Set lock */
929                 case 157:       /* Extend lock */
930                 case 158:       /* Release lock */
931                         FIDOUT();
932                         break;
933                 case 135:       /* Store status */
934                         FIDOUT();
935                         STOREATTROUT();
936                         break;
937                 case 133:       /* Store data */
938                         FIDOUT();
939                         STOREATTROUT();
940                         ND_PRINT(" offset");
941                         UINTOUT();
942                         ND_PRINT(" length");
943                         UINTOUT();
944                         ND_PRINT(" flen");
945                         UINTOUT();
946                         break;
947                 case 134:       /* Store ACL */
948                 {
949                         char a[AFSOPAQUEMAX+1];
950                         FIDOUT();
951                         i = GET_BE_U_4(bp);
952                         bp += sizeof(uint32_t);
953                         ND_TCHECK_LEN(bp, i);
954                         i = ND_MIN(AFSOPAQUEMAX, i);
955                         strncpy(a, (const char *) bp, i);
956                         a[i] = '\0';
957                         acl_print(ndo, (u_char *) a, (u_char *) a + i);
958                         break;
959                 }
960                 case 137:       /* Create file */
961                 case 141:       /* MakeDir */
962                         FIDOUT();
963                         STROUT(AFSNAMEMAX);
964                         STOREATTROUT();
965                         break;
966                 case 136:       /* Remove file */
967                 case 142:       /* Remove directory */
968                         FIDOUT();
969                         STROUT(AFSNAMEMAX);
970                         break;
971                 case 138:       /* Rename file */
972                         ND_PRINT(" old");
973                         FIDOUT();
974                         STROUT(AFSNAMEMAX);
975                         ND_PRINT(" new");
976                         FIDOUT();
977                         STROUT(AFSNAMEMAX);
978                         break;
979                 case 139:       /* Symlink */
980                         FIDOUT();
981                         STROUT(AFSNAMEMAX);
982                         ND_PRINT(" link to");
983                         STROUT(AFSNAMEMAX);
984                         break;
985                 case 140:       /* Link */
986                         FIDOUT();
987                         STROUT(AFSNAMEMAX);
988                         ND_PRINT(" link to");
989                         FIDOUT();
990                         break;
991                 case 148:       /* Get volume info */
992                         STROUT(AFSNAMEMAX);
993                         break;
994                 case 149:       /* Get volume stats */
995                 case 150:       /* Set volume stats */
996                         ND_PRINT(" volid");
997                         UINTOUT();
998                         break;
999                 case 154:       /* New get volume info */
1000                         ND_PRINT(" volname");
1001                         STROUT(AFSNAMEMAX);
1002                         break;
1003                 case 155:       /* Bulk stat */
1004                 case 65536:     /* Inline bulk stat */
1005                 {
1006                         uint32_t j;
1007                         j = GET_BE_U_4(bp);
1008                         bp += sizeof(uint32_t);
1009
1010                         for (i = 0; i < j; i++) {
1011                                 FIDOUT();
1012                                 if (i != j - 1)
1013                                         ND_PRINT(",");
1014                         }
1015                         if (j == 0)
1016                                 ND_PRINT(" <none!>");
1017                         break;
1018                 }
1019                 case 65537:     /* Fetch data 64 */
1020                         FIDOUT();
1021                         ND_PRINT(" offset");
1022                         UINT64OUT();
1023                         ND_PRINT(" length");
1024                         UINT64OUT();
1025                         break;
1026                 case 65538:     /* Store data 64 */
1027                         FIDOUT();
1028                         STOREATTROUT();
1029                         ND_PRINT(" offset");
1030                         UINT64OUT();
1031                         ND_PRINT(" length");
1032                         UINT64OUT();
1033                         ND_PRINT(" flen");
1034                         UINT64OUT();
1035                         break;
1036                 case 65541:    /* CallBack rx conn address */
1037                         ND_PRINT(" addr");
1038                         UINTOUT();
1039                 default:
1040                         ;
1041         }
1042
1043         return;
1044
1045 trunc:
1046         ND_PRINT(" [|fs]");
1047 }
1048
1049 /*
1050  * Handle replies to the AFS file service
1051  */
1052
1053 static void
1054 fs_reply_print(netdissect_options *ndo,
1055                const u_char *bp, u_int length, uint32_t opcode)
1056 {
1057         uint32_t i;
1058         const struct rx_header *rxh;
1059         uint8_t type;
1060
1061         if (length <= sizeof(struct rx_header))
1062                 return;
1063
1064         rxh = (const struct rx_header *) bp;
1065
1066         /*
1067          * Print out the afs call we're invoking.  The table used here was
1068          * gleaned from fsint/afsint.xg
1069          */
1070
1071         ND_PRINT(" fs reply %s", tok2str(fs_req, "op#%u", opcode));
1072
1073         type = GET_U_1(rxh->type);
1074         bp += sizeof(struct rx_header);
1075
1076         /*
1077          * If it was a data packet, interpret the response
1078          */
1079
1080         if (type == RX_PACKET_TYPE_DATA) {
1081                 switch (opcode) {
1082                 case 131:       /* Fetch ACL */
1083                 {
1084                         char a[AFSOPAQUEMAX+1];
1085                         i = GET_BE_U_4(bp);
1086                         bp += sizeof(uint32_t);
1087                         ND_TCHECK_LEN(bp, i);
1088                         i = ND_MIN(AFSOPAQUEMAX, i);
1089                         strncpy(a, (const char *) bp, i);
1090                         a[i] = '\0';
1091                         acl_print(ndo, (u_char *) a, (u_char *) a + i);
1092                         break;
1093                 }
1094                 case 137:       /* Create file */
1095                 case 141:       /* MakeDir */
1096                         ND_PRINT(" new");
1097                         FIDOUT();
1098                         break;
1099                 case 151:       /* Get root volume */
1100                         ND_PRINT(" root volume");
1101                         STROUT(AFSNAMEMAX);
1102                         break;
1103                 case 153:       /* Get time */
1104                         DATEOUT();
1105                         break;
1106                 default:
1107                         ;
1108                 }
1109         } else if (type == RX_PACKET_TYPE_ABORT) {
1110                 /*
1111                  * Otherwise, just print out the return code
1112                  */
1113                 int32_t errcode;
1114
1115                 errcode = GET_BE_S_4(bp);
1116                 bp += sizeof(int32_t);
1117
1118                 ND_PRINT(" error %s", tok2str(afs_fs_errors, "#%d", errcode));
1119         } else {
1120                 ND_PRINT(" strange fs reply of type %u", type);
1121         }
1122
1123         return;
1124
1125 trunc:
1126         ND_PRINT(" [|fs]");
1127 }
1128
1129 /*
1130  * Print out an AFS ACL string.  An AFS ACL is a string that has the
1131  * following format:
1132  *
1133  * <positive> <negative>
1134  * <uid1> <aclbits1>
1135  * ....
1136  *
1137  * "positive" and "negative" are integers which contain the number of
1138  * positive and negative ACL's in the string.  The uid/aclbits pair are
1139  * ASCII strings containing the UID/PTS record and an ASCII number
1140  * representing a logical OR of all the ACL permission bits
1141  */
1142
1143 #define NUMSTRINGIFY(x) XSTRINGIFY(x)
1144
1145 static void
1146 acl_print(netdissect_options *ndo,
1147           u_char *s, u_char *end)
1148 {
1149         int pos, neg, acl;
1150         int n, i;
1151         char user[USERNAMEMAX+1];
1152
1153         if (sscanf((char *) s, "%d %d\n%n", &pos, &neg, &n) != 2)
1154                 return;
1155
1156         s += n;
1157
1158         if (s > end)
1159                 return;
1160
1161         /*
1162          * This wacky order preserves the order used by the "fs" command
1163          */
1164
1165 #define ACLOUT(acl) \
1166         ND_PRINT("%s%s%s%s%s%s%s", \
1167                   acl & PRSFS_READ       ? "r" : "", \
1168                   acl & PRSFS_LOOKUP     ? "l" : "", \
1169                   acl & PRSFS_INSERT     ? "i" : "", \
1170                   acl & PRSFS_DELETE     ? "d" : "", \
1171                   acl & PRSFS_WRITE      ? "w" : "", \
1172                   acl & PRSFS_LOCK       ? "k" : "", \
1173                   acl & PRSFS_ADMINISTER ? "a" : "");
1174
1175         for (i = 0; i < pos; i++) {
1176                 if (sscanf((char *) s, "%" NUMSTRINGIFY(USERNAMEMAX) "s %d\n%n", user, &acl, &n) != 2)
1177                         return;
1178                 s += n;
1179                 ND_PRINT(" +{");
1180                 fn_print_str(ndo, (u_char *)user);
1181                 ND_PRINT(" ");
1182                 ACLOUT(acl);
1183                 ND_PRINT("}");
1184                 if (s > end)
1185                         return;
1186         }
1187
1188         for (i = 0; i < neg; i++) {
1189                 if (sscanf((char *) s, "%" NUMSTRINGIFY(USERNAMEMAX) "s %d\n%n", user, &acl, &n) != 2)
1190                         return;
1191                 s += n;
1192                 ND_PRINT(" -{");
1193                 fn_print_str(ndo, (u_char *)user);
1194                 ND_PRINT(" ");
1195                 ACLOUT(acl);
1196                 ND_PRINT("}");
1197                 if (s > end)
1198                         return;
1199         }
1200 }
1201
1202 #undef ACLOUT
1203
1204 /*
1205  * Handle calls to the AFS callback service
1206  */
1207
1208 static void
1209 cb_print(netdissect_options *ndo,
1210          const u_char *bp, u_int length)
1211 {
1212         uint32_t cb_op;
1213         uint32_t i;
1214
1215         if (length <= sizeof(struct rx_header))
1216                 return;
1217
1218         /*
1219          * Print out the afs call we're invoking.  The table used here was
1220          * gleaned from fsint/afscbint.xg
1221          */
1222
1223         cb_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1224
1225         ND_PRINT(" cb call %s", tok2str(cb_req, "op#%u", cb_op));
1226
1227         bp += sizeof(struct rx_header) + 4;
1228
1229         /*
1230          * Print out the afs call we're invoking.  The table used here was
1231          * gleaned from fsint/afscbint.xg
1232          */
1233
1234         switch (cb_op) {
1235                 case 204:               /* Callback */
1236                 {
1237                         uint32_t j, t;
1238                         j = GET_BE_U_4(bp);
1239                         bp += sizeof(uint32_t);
1240
1241                         for (i = 0; i < j; i++) {
1242                                 FIDOUT();
1243                                 if (i != j - 1)
1244                                         ND_PRINT(",");
1245                         }
1246
1247                         if (j == 0)
1248                                 ND_PRINT(" <none!>");
1249
1250                         j = GET_BE_U_4(bp);
1251                         bp += sizeof(uint32_t);
1252
1253                         if (j != 0)
1254                                 ND_PRINT(";");
1255
1256                         for (i = 0; i < j; i++) {
1257                                 ND_PRINT(" ver");
1258                                 INTOUT();
1259                                 ND_PRINT(" expires");
1260                                 DATEOUT();
1261                                 t = GET_BE_U_4(bp);
1262                                 bp += sizeof(uint32_t);
1263                                 tok2str(cb_types, "type %u", t);
1264                         }
1265                         break;
1266                 }
1267                 case 214: {
1268                         ND_PRINT(" afsuuid");
1269                         AFSUUIDOUT();
1270                         break;
1271                 }
1272                 default:
1273                         ;
1274         }
1275
1276         return;
1277
1278 trunc:
1279         ND_PRINT(" [|cb]");
1280 }
1281
1282 /*
1283  * Handle replies to the AFS Callback Service
1284  */
1285
1286 static void
1287 cb_reply_print(netdissect_options *ndo,
1288                const u_char *bp, u_int length, uint32_t opcode)
1289 {
1290         const struct rx_header *rxh;
1291         uint8_t type;
1292
1293         if (length <= sizeof(struct rx_header))
1294                 return;
1295
1296         rxh = (const struct rx_header *) bp;
1297
1298         /*
1299          * Print out the afs call we're invoking.  The table used here was
1300          * gleaned from fsint/afscbint.xg
1301          */
1302
1303         ND_PRINT(" cb reply %s", tok2str(cb_req, "op#%u", opcode));
1304
1305         type = GET_U_1(rxh->type);
1306         bp += sizeof(struct rx_header);
1307
1308         /*
1309          * If it was a data packet, interpret the response.
1310          */
1311
1312         if (type == RX_PACKET_TYPE_DATA)
1313                 switch (opcode) {
1314                 case 213:       /* InitCallBackState3 */
1315                         AFSUUIDOUT();
1316                         break;
1317                 default:
1318                 ;
1319                 }
1320         else {
1321                 /*
1322                  * Otherwise, just print out the return code
1323                  */
1324                 ND_PRINT(" errcode");
1325                 INTOUT();
1326         }
1327
1328         return;
1329
1330 trunc:
1331         ND_PRINT(" [|cb]");
1332 }
1333
1334 /*
1335  * Handle calls to the AFS protection database server
1336  */
1337
1338 static void
1339 prot_print(netdissect_options *ndo,
1340            const u_char *bp, u_int length)
1341 {
1342         uint32_t i;
1343         uint32_t pt_op;
1344
1345         if (length <= sizeof(struct rx_header))
1346                 return;
1347
1348         /*
1349          * Print out the afs call we're invoking.  The table used here was
1350          * gleaned from ptserver/ptint.xg
1351          */
1352
1353         pt_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1354
1355         ND_PRINT(" pt");
1356
1357         if (is_ubik(pt_op)) {
1358                 ubik_print(ndo, bp);
1359                 return;
1360         }
1361
1362         ND_PRINT(" call %s", tok2str(pt_req, "op#%u", pt_op));
1363
1364         /*
1365          * Decode some of the arguments to the PT calls
1366          */
1367
1368         bp += sizeof(struct rx_header) + 4;
1369
1370         switch (pt_op) {
1371                 case 500:       /* I New User */
1372                         STROUT(PRNAMEMAX);
1373                         ND_PRINT(" id");
1374                         INTOUT();
1375                         ND_PRINT(" oldid");
1376                         INTOUT();
1377                         break;
1378                 case 501:       /* Where is it */
1379                 case 506:       /* Delete */
1380                 case 508:       /* Get CPS */
1381                 case 512:       /* List entry */
1382                 case 514:       /* List elements */
1383                 case 517:       /* List owned */
1384                 case 518:       /* Get CPS2 */
1385                 case 519:       /* Get host CPS */
1386                 case 530:       /* List super groups */
1387                         ND_PRINT(" id");
1388                         INTOUT();
1389                         break;
1390                 case 502:       /* Dump entry */
1391                         ND_PRINT(" pos");
1392                         INTOUT();
1393                         break;
1394                 case 503:       /* Add to group */
1395                 case 507:       /* Remove from group */
1396                 case 515:       /* Is a member of? */
1397                         ND_PRINT(" uid");
1398                         INTOUT();
1399                         ND_PRINT(" gid");
1400                         INTOUT();
1401                         break;
1402                 case 504:       /* Name to ID */
1403                 {
1404                         uint32_t j;
1405                         j = GET_BE_U_4(bp);
1406                         bp += sizeof(uint32_t);
1407
1408                         /*
1409                          * Who designed this chicken-shit protocol?
1410                          *
1411                          * Each character is stored as a 32-bit
1412                          * integer!
1413                          */
1414
1415                         for (i = 0; i < j; i++) {
1416                                 VECOUT(PRNAMEMAX);
1417                         }
1418                         if (j == 0)
1419                                 ND_PRINT(" <none!>");
1420                 }
1421                         break;
1422                 case 505:       /* Id to name */
1423                 {
1424                         uint32_t j;
1425                         ND_PRINT(" ids:");
1426                         i = GET_BE_U_4(bp);
1427                         bp += sizeof(uint32_t);
1428                         for (j = 0; j < i; j++)
1429                                 INTOUT();
1430                         if (j == 0)
1431                                 ND_PRINT(" <none!>");
1432                 }
1433                         break;
1434                 case 509:       /* New entry */
1435                         STROUT(PRNAMEMAX);
1436                         ND_PRINT(" flag");
1437                         INTOUT();
1438                         ND_PRINT(" oid");
1439                         INTOUT();
1440                         break;
1441                 case 511:       /* Set max */
1442                         ND_PRINT(" id");
1443                         INTOUT();
1444                         ND_PRINT(" gflag");
1445                         INTOUT();
1446                         break;
1447                 case 513:       /* Change entry */
1448                         ND_PRINT(" id");
1449                         INTOUT();
1450                         STROUT(PRNAMEMAX);
1451                         ND_PRINT(" oldid");
1452                         INTOUT();
1453                         ND_PRINT(" newid");
1454                         INTOUT();
1455                         break;
1456                 case 520:       /* Update entry */
1457                         ND_PRINT(" id");
1458                         INTOUT();
1459                         STROUT(PRNAMEMAX);
1460                         break;
1461                 default:
1462                         ;
1463         }
1464
1465
1466         return;
1467
1468 trunc:
1469         ND_PRINT(" [|pt]");
1470 }
1471
1472 /*
1473  * Handle replies to the AFS protection service
1474  */
1475
1476 static void
1477 prot_reply_print(netdissect_options *ndo,
1478                  const u_char *bp, u_int length, uint32_t opcode)
1479 {
1480         const struct rx_header *rxh;
1481         uint8_t type;
1482         uint32_t i;
1483
1484         if (length < sizeof(struct rx_header))
1485                 return;
1486
1487         rxh = (const struct rx_header *) bp;
1488
1489         /*
1490          * Print out the afs call we're invoking.  The table used here was
1491          * gleaned from ptserver/ptint.xg.  Check to see if it's a
1492          * Ubik call, however.
1493          */
1494
1495         ND_PRINT(" pt");
1496
1497         if (is_ubik(opcode)) {
1498                 ubik_reply_print(ndo, bp, length, opcode);
1499                 return;
1500         }
1501
1502         ND_PRINT(" reply %s", tok2str(pt_req, "op#%u", opcode));
1503
1504         type = GET_U_1(rxh->type);
1505         bp += sizeof(struct rx_header);
1506
1507         /*
1508          * If it was a data packet, interpret the response
1509          */
1510
1511         if (type == RX_PACKET_TYPE_DATA)
1512                 switch (opcode) {
1513                 case 504:               /* Name to ID */
1514                 {
1515                         uint32_t j;
1516                         ND_PRINT(" ids:");
1517                         i = GET_BE_U_4(bp);
1518                         bp += sizeof(uint32_t);
1519                         for (j = 0; j < i; j++)
1520                                 INTOUT();
1521                         if (j == 0)
1522                                 ND_PRINT(" <none!>");
1523                 }
1524                         break;
1525                 case 505:               /* ID to name */
1526                 {
1527                         uint32_t j;
1528                         j = GET_BE_U_4(bp);
1529                         bp += sizeof(uint32_t);
1530
1531                         /*
1532                          * Who designed this chicken-shit protocol?
1533                          *
1534                          * Each character is stored as a 32-bit
1535                          * integer!
1536                          */
1537
1538                         for (i = 0; i < j; i++) {
1539                                 VECOUT(PRNAMEMAX);
1540                         }
1541                         if (j == 0)
1542                                 ND_PRINT(" <none!>");
1543                 }
1544                         break;
1545                 case 508:               /* Get CPS */
1546                 case 514:               /* List elements */
1547                 case 517:               /* List owned */
1548                 case 518:               /* Get CPS2 */
1549                 case 519:               /* Get host CPS */
1550                 {
1551                         uint32_t j;
1552                         j = GET_BE_U_4(bp);
1553                         bp += sizeof(uint32_t);
1554                         for (i = 0; i < j; i++) {
1555                                 INTOUT();
1556                         }
1557                         if (j == 0)
1558                                 ND_PRINT(" <none!>");
1559                 }
1560                         break;
1561                 case 510:               /* List max */
1562                         ND_PRINT(" maxuid");
1563                         INTOUT();
1564                         ND_PRINT(" maxgid");
1565                         INTOUT();
1566                         break;
1567                 default:
1568                         ;
1569                 }
1570         else {
1571                 /*
1572                  * Otherwise, just print out the return code
1573                  */
1574                 ND_PRINT(" errcode");
1575                 INTOUT();
1576         }
1577
1578         return;
1579
1580 trunc:
1581         ND_PRINT(" [|pt]");
1582 }
1583
1584 /*
1585  * Handle calls to the AFS volume location database service
1586  */
1587
1588 static void
1589 vldb_print(netdissect_options *ndo,
1590            const u_char *bp, u_int length)
1591 {
1592         uint32_t vldb_op;
1593         uint32_t i;
1594
1595         if (length <= sizeof(struct rx_header))
1596                 return;
1597
1598         /*
1599          * Print out the afs call we're invoking.  The table used here was
1600          * gleaned from vlserver/vldbint.xg
1601          */
1602
1603         vldb_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1604
1605         ND_PRINT(" vldb");
1606
1607         if (is_ubik(vldb_op)) {
1608                 ubik_print(ndo, bp);
1609                 return;
1610         }
1611         ND_PRINT(" call %s", tok2str(vldb_req, "op#%u", vldb_op));
1612
1613         /*
1614          * Decode some of the arguments to the VLDB calls
1615          */
1616
1617         bp += sizeof(struct rx_header) + 4;
1618
1619         switch (vldb_op) {
1620                 case 501:       /* Create new volume */
1621                 case 517:       /* Create entry N */
1622                         VECOUT(VLNAMEMAX);
1623                         break;
1624                 case 502:       /* Delete entry */
1625                 case 503:       /* Get entry by ID */
1626                 case 507:       /* Update entry */
1627                 case 508:       /* Set lock */
1628                 case 509:       /* Release lock */
1629                 case 518:       /* Get entry by ID N */
1630                         ND_PRINT(" volid");
1631                         INTOUT();
1632                         i = GET_BE_U_4(bp);
1633                         bp += sizeof(uint32_t);
1634                         if (i <= 2)
1635                                 ND_PRINT(" type %s", voltype[i]);
1636                         break;
1637                 case 504:       /* Get entry by name */
1638                 case 519:       /* Get entry by name N */
1639                 case 524:       /* Update entry by name */
1640                 case 527:       /* Get entry by name U */
1641                         STROUT(VLNAMEMAX);
1642                         break;
1643                 case 505:       /* Get new vol id */
1644                         ND_PRINT(" bump");
1645                         INTOUT();
1646                         break;
1647                 case 506:       /* Replace entry */
1648                 case 520:       /* Replace entry N */
1649                         ND_PRINT(" volid");
1650                         INTOUT();
1651                         i = GET_BE_U_4(bp);
1652                         bp += sizeof(uint32_t);
1653                         if (i <= 2)
1654                                 ND_PRINT(" type %s", voltype[i]);
1655                         VECOUT(VLNAMEMAX);
1656                         break;
1657                 case 510:       /* List entry */
1658                 case 521:       /* List entry N */
1659                         ND_PRINT(" index");
1660                         INTOUT();
1661                         break;
1662                 default:
1663                         ;
1664         }
1665
1666         return;
1667
1668 trunc:
1669         ND_PRINT(" [|vldb]");
1670 }
1671
1672 /*
1673  * Handle replies to the AFS volume location database service
1674  */
1675
1676 static void
1677 vldb_reply_print(netdissect_options *ndo,
1678                  const u_char *bp, u_int length, uint32_t opcode)
1679 {
1680         const struct rx_header *rxh;
1681         uint8_t type;
1682         uint32_t i;
1683
1684         if (length < sizeof(struct rx_header))
1685                 return;
1686
1687         rxh = (const struct rx_header *) bp;
1688
1689         /*
1690          * Print out the afs call we're invoking.  The table used here was
1691          * gleaned from vlserver/vldbint.xg.  Check to see if it's a
1692          * Ubik call, however.
1693          */
1694
1695         ND_PRINT(" vldb");
1696
1697         if (is_ubik(opcode)) {
1698                 ubik_reply_print(ndo, bp, length, opcode);
1699                 return;
1700         }
1701
1702         ND_PRINT(" reply %s", tok2str(vldb_req, "op#%u", opcode));
1703
1704         type = GET_U_1(rxh->type);
1705         bp += sizeof(struct rx_header);
1706
1707         /*
1708          * If it was a data packet, interpret the response
1709          */
1710
1711         if (type == RX_PACKET_TYPE_DATA)
1712                 switch (opcode) {
1713                 case 510:       /* List entry */
1714                         ND_PRINT(" count");
1715                         INTOUT();
1716                         ND_PRINT(" nextindex");
1717                         INTOUT();
1718                         ND_FALL_THROUGH;
1719                 case 503:       /* Get entry by id */
1720                 case 504:       /* Get entry by name */
1721                 {       uint32_t nservers, j;
1722                         VECOUT(VLNAMEMAX);
1723                         ND_TCHECK_4(bp);
1724                         bp += sizeof(uint32_t);
1725                         ND_PRINT(" numservers");
1726                         nservers = GET_BE_U_4(bp);
1727                         bp += sizeof(uint32_t);
1728                         ND_PRINT(" %u", nservers);
1729                         ND_PRINT(" servers");
1730                         for (i = 0; i < 8; i++) {
1731                                 ND_TCHECK_4(bp);
1732                                 if (i < nservers)
1733                                         ND_PRINT(" %s",
1734                                            intoa(GET_IPV4_TO_NETWORK_ORDER(bp)));
1735                                 bp += sizeof(nd_ipv4);
1736                         }
1737                         ND_PRINT(" partitions");
1738                         for (i = 0; i < 8; i++) {
1739                                 j = GET_BE_U_4(bp);
1740                                 if (i < nservers && j <= 26)
1741                                         ND_PRINT(" %c", 'a' + j);
1742                                 else if (i < nservers)
1743                                         ND_PRINT(" %u", j);
1744                                 bp += sizeof(uint32_t);
1745                         }
1746                         ND_TCHECK_LEN(bp, 8 * sizeof(uint32_t));
1747                         bp += 8 * sizeof(uint32_t);
1748                         ND_PRINT(" rwvol");
1749                         UINTOUT();
1750                         ND_PRINT(" rovol");
1751                         UINTOUT();
1752                         ND_PRINT(" backup");
1753                         UINTOUT();
1754                 }
1755                         break;
1756                 case 505:       /* Get new volume ID */
1757                         ND_PRINT(" newvol");
1758                         UINTOUT();
1759                         break;
1760                 case 521:       /* List entry */
1761                 case 529:       /* List entry U */
1762                         ND_PRINT(" count");
1763                         INTOUT();
1764                         ND_PRINT(" nextindex");
1765                         INTOUT();
1766                         ND_FALL_THROUGH;
1767                 case 518:       /* Get entry by ID N */
1768                 case 519:       /* Get entry by name N */
1769                 {       uint32_t nservers, j;
1770                         VECOUT(VLNAMEMAX);
1771                         ND_PRINT(" numservers");
1772                         nservers = GET_BE_U_4(bp);
1773                         bp += sizeof(uint32_t);
1774                         ND_PRINT(" %u", nservers);
1775                         ND_PRINT(" servers");
1776                         for (i = 0; i < 13; i++) {
1777                                 ND_TCHECK_4(bp);
1778                                 if (i < nservers)
1779                                         ND_PRINT(" %s",
1780                                            intoa(GET_IPV4_TO_NETWORK_ORDER(bp)));
1781                                 bp += sizeof(nd_ipv4);
1782                         }
1783                         ND_PRINT(" partitions");
1784                         for (i = 0; i < 13; i++) {
1785                                 j = GET_BE_U_4(bp);
1786                                 if (i < nservers && j <= 26)
1787                                         ND_PRINT(" %c", 'a' + j);
1788                                 else if (i < nservers)
1789                                         ND_PRINT(" %u", j);
1790                                 bp += sizeof(uint32_t);
1791                         }
1792                         ND_TCHECK_LEN(bp, 13 * sizeof(uint32_t));
1793                         bp += 13 * sizeof(uint32_t);
1794                         ND_PRINT(" rwvol");
1795                         UINTOUT();
1796                         ND_PRINT(" rovol");
1797                         UINTOUT();
1798                         ND_PRINT(" backup");
1799                         UINTOUT();
1800                 }
1801                         break;
1802                 case 526:       /* Get entry by ID U */
1803                 case 527:       /* Get entry by name U */
1804                 {       uint32_t nservers, j;
1805                         VECOUT(VLNAMEMAX);
1806                         ND_PRINT(" numservers");
1807                         nservers = GET_BE_U_4(bp);
1808                         bp += sizeof(uint32_t);
1809                         ND_PRINT(" %u", nservers);
1810                         ND_PRINT(" servers");
1811                         for (i = 0; i < 13; i++) {
1812                                 if (i < nservers) {
1813                                         ND_PRINT(" afsuuid");
1814                                         AFSUUIDOUT();
1815                                 } else {
1816                                         ND_TCHECK_LEN(bp, 44);
1817                                         bp += 44;
1818                                 }
1819                         }
1820                         ND_TCHECK_LEN(bp, 4 * 13);
1821                         bp += 4 * 13;
1822                         ND_PRINT(" partitions");
1823                         for (i = 0; i < 13; i++) {
1824                                 j = GET_BE_U_4(bp);
1825                                 if (i < nservers && j <= 26)
1826                                         ND_PRINT(" %c", 'a' + j);
1827                                 else if (i < nservers)
1828                                         ND_PRINT(" %u", j);
1829                                 bp += sizeof(uint32_t);
1830                         }
1831                         ND_TCHECK_LEN(bp, 13 * sizeof(uint32_t));
1832                         bp += 13 * sizeof(uint32_t);
1833                         ND_PRINT(" rwvol");
1834                         UINTOUT();
1835                         ND_PRINT(" rovol");
1836                         UINTOUT();
1837                         ND_PRINT(" backup");
1838                         UINTOUT();
1839                 }
1840                 default:
1841                         ;
1842                 }
1843
1844         else {
1845                 /*
1846                  * Otherwise, just print out the return code
1847                  */
1848                 ND_PRINT(" errcode");
1849                 INTOUT();
1850         }
1851
1852         return;
1853
1854 trunc:
1855         ND_PRINT(" [|vldb]");
1856 }
1857
1858 /*
1859  * Handle calls to the AFS Kerberos Authentication service
1860  */
1861
1862 static void
1863 kauth_print(netdissect_options *ndo,
1864             const u_char *bp, u_int length)
1865 {
1866         uint32_t kauth_op;
1867
1868         if (length <= sizeof(struct rx_header))
1869                 return;
1870
1871         /*
1872          * Print out the afs call we're invoking.  The table used here was
1873          * gleaned from kauth/kauth.rg
1874          */
1875
1876         kauth_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1877
1878         ND_PRINT(" kauth");
1879
1880         if (is_ubik(kauth_op)) {
1881                 ubik_print(ndo, bp);
1882                 return;
1883         }
1884
1885
1886         ND_PRINT(" call %s", tok2str(kauth_req, "op#%u", kauth_op));
1887
1888         /*
1889          * Decode some of the arguments to the KA calls
1890          */
1891
1892         bp += sizeof(struct rx_header) + 4;
1893
1894         switch (kauth_op) {
1895                 case 1:         /* Authenticate old */
1896                 case 21:        /* Authenticate */
1897                 case 22:        /* Authenticate-V2 */
1898                 case 2:         /* Change PW */
1899                 case 5:         /* Set fields */
1900                 case 6:         /* Create user */
1901                 case 7:         /* Delete user */
1902                 case 8:         /* Get entry */
1903                 case 14:        /* Unlock */
1904                 case 15:        /* Lock status */
1905                         ND_PRINT(" principal");
1906                         STROUT(KANAMEMAX);
1907                         STROUT(KANAMEMAX);
1908                         break;
1909                 case 3:         /* GetTicket-old */
1910                 case 23:        /* GetTicket */
1911                 {
1912                         uint32_t i;
1913                         ND_PRINT(" kvno");
1914                         INTOUT();
1915                         ND_PRINT(" domain");
1916                         STROUT(KANAMEMAX);
1917                         i = GET_BE_U_4(bp);
1918                         bp += sizeof(uint32_t);
1919                         ND_TCHECK_LEN(bp, i);
1920                         bp += i;
1921                         ND_PRINT(" principal");
1922                         STROUT(KANAMEMAX);
1923                         STROUT(KANAMEMAX);
1924                         break;
1925                 }
1926                 case 4:         /* Set Password */
1927                         ND_PRINT(" principal");
1928                         STROUT(KANAMEMAX);
1929                         STROUT(KANAMEMAX);
1930                         ND_PRINT(" kvno");
1931                         INTOUT();
1932                         break;
1933                 case 12:        /* Get password */
1934                         ND_PRINT(" name");
1935                         STROUT(KANAMEMAX);
1936                         break;
1937                 default:
1938                         ;
1939         }
1940
1941         return;
1942
1943 trunc:
1944         ND_PRINT(" [|kauth]");
1945 }
1946
1947 /*
1948  * Handle replies to the AFS Kerberos Authentication Service
1949  */
1950
1951 static void
1952 kauth_reply_print(netdissect_options *ndo,
1953                   const u_char *bp, u_int length, uint32_t opcode)
1954 {
1955         const struct rx_header *rxh;
1956         uint8_t type;
1957
1958         if (length <= sizeof(struct rx_header))
1959                 return;
1960
1961         rxh = (const struct rx_header *) bp;
1962
1963         /*
1964          * Print out the afs call we're invoking.  The table used here was
1965          * gleaned from kauth/kauth.rg
1966          */
1967
1968         ND_PRINT(" kauth");
1969
1970         if (is_ubik(opcode)) {
1971                 ubik_reply_print(ndo, bp, length, opcode);
1972                 return;
1973         }
1974
1975         ND_PRINT(" reply %s", tok2str(kauth_req, "op#%u", opcode));
1976
1977         type = GET_U_1(rxh->type);
1978         bp += sizeof(struct rx_header);
1979
1980         /*
1981          * If it was a data packet, interpret the response.
1982          */
1983
1984         if (type == RX_PACKET_TYPE_DATA)
1985                 /* Well, no, not really.  Leave this for later */
1986                 ;
1987         else {
1988                 /*
1989                  * Otherwise, just print out the return code
1990                  */
1991                 ND_PRINT(" errcode");
1992                 INTOUT();
1993         }
1994 }
1995
1996 /*
1997  * Handle calls to the AFS Volume location service
1998  */
1999
2000 static void
2001 vol_print(netdissect_options *ndo,
2002           const u_char *bp, u_int length)
2003 {
2004         uint32_t vol_op;
2005
2006         if (length <= sizeof(struct rx_header))
2007                 return;
2008
2009         /*
2010          * Print out the afs call we're invoking.  The table used here was
2011          * gleaned from volser/volint.xg
2012          */
2013
2014         vol_op = GET_BE_U_4(bp + sizeof(struct rx_header));
2015
2016         ND_PRINT(" vol call %s", tok2str(vol_req, "op#%u", vol_op));
2017
2018         bp += sizeof(struct rx_header) + 4;
2019
2020         switch (vol_op) {
2021                 case 100:       /* Create volume */
2022                         ND_PRINT(" partition");
2023                         UINTOUT();
2024                         ND_PRINT(" name");
2025                         STROUT(AFSNAMEMAX);
2026                         ND_PRINT(" type");
2027                         UINTOUT();
2028                         ND_PRINT(" parent");
2029                         UINTOUT();
2030                         break;
2031                 case 101:       /* Delete volume */
2032                 case 107:       /* Get flags */
2033                         ND_PRINT(" trans");
2034                         UINTOUT();
2035                         break;
2036                 case 102:       /* Restore */
2037                         ND_PRINT(" totrans");
2038                         UINTOUT();
2039                         ND_PRINT(" flags");
2040                         UINTOUT();
2041                         break;
2042                 case 103:       /* Forward */
2043                         ND_PRINT(" fromtrans");
2044                         UINTOUT();
2045                         ND_PRINT(" fromdate");
2046                         DATEOUT();
2047                         DESTSERVEROUT();
2048                         ND_PRINT(" desttrans");
2049                         INTOUT();
2050                         break;
2051                 case 104:       /* End trans */
2052                         ND_PRINT(" trans");
2053                         UINTOUT();
2054                         break;
2055                 case 105:       /* Clone */
2056                         ND_PRINT(" trans");
2057                         UINTOUT();
2058                         ND_PRINT(" purgevol");
2059                         UINTOUT();
2060                         ND_PRINT(" newtype");
2061                         UINTOUT();
2062                         ND_PRINT(" newname");
2063                         STROUT(AFSNAMEMAX);
2064                         break;
2065                 case 106:       /* Set flags */
2066                         ND_PRINT(" trans");
2067                         UINTOUT();
2068                         ND_PRINT(" flags");
2069                         UINTOUT();
2070                         break;
2071                 case 108:       /* Trans create */
2072                         ND_PRINT(" vol");
2073                         UINTOUT();
2074                         ND_PRINT(" partition");
2075                         UINTOUT();
2076                         ND_PRINT(" flags");
2077                         UINTOUT();
2078                         break;
2079                 case 109:       /* Dump */
2080                 case 655537:    /* Get size */
2081                         ND_PRINT(" fromtrans");
2082                         UINTOUT();
2083                         ND_PRINT(" fromdate");
2084                         DATEOUT();
2085                         break;
2086                 case 110:       /* Get n-th volume */
2087                         ND_PRINT(" index");
2088                         UINTOUT();
2089                         break;
2090                 case 111:       /* Set forwarding */
2091                         ND_PRINT(" tid");
2092                         UINTOUT();
2093                         ND_PRINT(" newsite");
2094                         UINTOUT();
2095                         break;
2096                 case 112:       /* Get name */
2097                 case 113:       /* Get status */
2098                         ND_PRINT(" tid");
2099                         break;
2100                 case 114:       /* Signal restore */
2101                         ND_PRINT(" name");
2102                         STROUT(AFSNAMEMAX);
2103                         ND_PRINT(" type");
2104                         UINTOUT();
2105                         ND_PRINT(" pid");
2106                         UINTOUT();
2107                         ND_PRINT(" cloneid");
2108                         UINTOUT();
2109                         break;
2110                 case 116:       /* List volumes */
2111                         ND_PRINT(" partition");
2112                         UINTOUT();
2113                         ND_PRINT(" flags");
2114                         UINTOUT();
2115                         break;
2116                 case 117:       /* Set id types */
2117                         ND_PRINT(" tid");
2118                         UINTOUT();
2119                         ND_PRINT(" name");
2120                         STROUT(AFSNAMEMAX);
2121                         ND_PRINT(" type");
2122                         UINTOUT();
2123                         ND_PRINT(" pid");
2124                         UINTOUT();
2125                         ND_PRINT(" clone");
2126                         UINTOUT();
2127                         ND_PRINT(" backup");
2128                         UINTOUT();
2129                         break;
2130                 case 119:       /* Partition info */
2131                         ND_PRINT(" name");
2132                         STROUT(AFSNAMEMAX);
2133                         break;
2134                 case 120:       /* Reclone */
2135                         ND_PRINT(" tid");
2136                         UINTOUT();
2137                         break;
2138                 case 121:       /* List one volume */
2139                 case 122:       /* Nuke volume */
2140                 case 124:       /* Extended List volumes */
2141                 case 125:       /* Extended List one volume */
2142                 case 65536:     /* Convert RO to RW volume */
2143                         ND_PRINT(" partid");
2144                         UINTOUT();
2145                         ND_PRINT(" volid");
2146                         UINTOUT();
2147                         break;
2148                 case 123:       /* Set date */
2149                         ND_PRINT(" tid");
2150                         UINTOUT();
2151                         ND_PRINT(" date");
2152                         DATEOUT();
2153                         break;
2154                 case 126:       /* Set info */
2155                         ND_PRINT(" tid");
2156                         UINTOUT();
2157                         break;
2158                 case 128:       /* Forward multiple */
2159                         ND_PRINT(" fromtrans");
2160                         UINTOUT();
2161                         ND_PRINT(" fromdate");
2162                         DATEOUT();
2163                         {
2164                                 uint32_t i, j;
2165                                 j = GET_BE_U_4(bp);
2166                                 bp += sizeof(uint32_t);
2167                                 for (i = 0; i < j; i++) {
2168                                         DESTSERVEROUT();
2169                                         if (i != j - 1)
2170                                                 ND_PRINT(",");
2171                                 }
2172                                 if (j == 0)
2173                                         ND_PRINT(" <none!>");
2174                         }
2175                         break;
2176                 case 65538:     /* Dump version 2 */
2177                         ND_PRINT(" fromtrans");
2178                         UINTOUT();
2179                         ND_PRINT(" fromdate");
2180                         DATEOUT();
2181                         ND_PRINT(" flags");
2182                         UINTOUT();
2183                         break;
2184                 default:
2185                         ;
2186         }
2187         return;
2188
2189 trunc:
2190         ND_PRINT(" [|vol]");
2191 }
2192
2193 /*
2194  * Handle replies to the AFS Volume Service
2195  */
2196
2197 static void
2198 vol_reply_print(netdissect_options *ndo,
2199                 const u_char *bp, u_int length, uint32_t opcode)
2200 {
2201         const struct rx_header *rxh;
2202         uint8_t type;
2203
2204         if (length <= sizeof(struct rx_header))
2205                 return;
2206
2207         rxh = (const struct rx_header *) bp;
2208
2209         /*
2210          * Print out the afs call we're invoking.  The table used here was
2211          * gleaned from volser/volint.xg
2212          */
2213
2214         ND_PRINT(" vol reply %s", tok2str(vol_req, "op#%u", opcode));
2215
2216         type = GET_U_1(rxh->type);
2217         bp += sizeof(struct rx_header);
2218
2219         /*
2220          * If it was a data packet, interpret the response.
2221          */
2222
2223         if (type == RX_PACKET_TYPE_DATA) {
2224                 switch (opcode) {
2225                         case 100:       /* Create volume */
2226                                 ND_PRINT(" volid");
2227                                 UINTOUT();
2228                                 ND_PRINT(" trans");
2229                                 UINTOUT();
2230                                 break;
2231                         case 104:       /* End transaction */
2232                                 UINTOUT();
2233                                 break;
2234                         case 105:       /* Clone */
2235                                 ND_PRINT(" newvol");
2236                                 UINTOUT();
2237                                 break;
2238                         case 107:       /* Get flags */
2239                                 UINTOUT();
2240                                 break;
2241                         case 108:       /* Transaction create */
2242                                 ND_PRINT(" trans");
2243                                 UINTOUT();
2244                                 break;
2245                         case 110:       /* Get n-th volume */
2246                                 ND_PRINT(" volume");
2247                                 UINTOUT();
2248                                 ND_PRINT(" partition");
2249                                 UINTOUT();
2250                                 break;
2251                         case 112:       /* Get name */
2252                                 STROUT(AFSNAMEMAX);
2253                                 break;
2254                         case 113:       /* Get status */
2255                                 ND_PRINT(" volid");
2256                                 UINTOUT();
2257                                 ND_PRINT(" nextuniq");
2258                                 UINTOUT();
2259                                 ND_PRINT(" type");
2260                                 UINTOUT();
2261                                 ND_PRINT(" parentid");
2262                                 UINTOUT();
2263                                 ND_PRINT(" clone");
2264                                 UINTOUT();
2265                                 ND_PRINT(" backup");
2266                                 UINTOUT();
2267                                 ND_PRINT(" restore");
2268                                 UINTOUT();
2269                                 ND_PRINT(" maxquota");
2270                                 UINTOUT();
2271                                 ND_PRINT(" minquota");
2272                                 UINTOUT();
2273                                 ND_PRINT(" owner");
2274                                 UINTOUT();
2275                                 ND_PRINT(" create");
2276                                 DATEOUT();
2277                                 ND_PRINT(" access");
2278                                 DATEOUT();
2279                                 ND_PRINT(" update");
2280                                 DATEOUT();
2281                                 ND_PRINT(" expire");
2282                                 DATEOUT();
2283                                 ND_PRINT(" backup");
2284                                 DATEOUT();
2285                                 ND_PRINT(" copy");
2286                                 DATEOUT();
2287                                 break;
2288                         case 115:       /* Old list partitions */
2289                                 break;
2290                         case 116:       /* List volumes */
2291                         case 121:       /* List one volume */
2292                                 {
2293                                         uint32_t i, j;
2294                                         j = GET_BE_U_4(bp);
2295                                         bp += sizeof(uint32_t);
2296                                         for (i = 0; i < j; i++) {
2297                                                 ND_PRINT(" name");
2298                                                 VECOUT(32);
2299                                                 ND_PRINT(" volid");
2300                                                 UINTOUT();
2301                                                 ND_PRINT(" type");
2302                                                 bp += sizeof(uint32_t) * 21;
2303                                                 if (i != j - 1)
2304                                                         ND_PRINT(",");
2305                                         }
2306                                         if (j == 0)
2307                                                 ND_PRINT(" <none!>");
2308                                 }
2309                                 break;
2310
2311
2312                         default:
2313                                 ;
2314                 }
2315         } else {
2316                 /*
2317                  * Otherwise, just print out the return code
2318                  */
2319                 ND_PRINT(" errcode");
2320                 INTOUT();
2321         }
2322
2323         return;
2324
2325 trunc:
2326         ND_PRINT(" [|vol]");
2327 }
2328
2329 /*
2330  * Handle calls to the AFS BOS service
2331  */
2332
2333 static void
2334 bos_print(netdissect_options *ndo,
2335           const u_char *bp, u_int length)
2336 {
2337         uint32_t bos_op;
2338
2339         if (length <= sizeof(struct rx_header))
2340                 return;
2341
2342         /*
2343          * Print out the afs call we're invoking.  The table used here was
2344          * gleaned from bozo/bosint.xg
2345          */
2346
2347         bos_op = GET_BE_U_4(bp + sizeof(struct rx_header));
2348
2349         ND_PRINT(" bos call %s", tok2str(bos_req, "op#%u", bos_op));
2350
2351         /*
2352          * Decode some of the arguments to the BOS calls
2353          */
2354
2355         bp += sizeof(struct rx_header) + 4;
2356
2357         switch (bos_op) {
2358                 case 80:        /* Create B node */
2359                         ND_PRINT(" type");
2360                         STROUT(BOSNAMEMAX);
2361                         ND_PRINT(" instance");
2362                         STROUT(BOSNAMEMAX);
2363                         break;
2364                 case 81:        /* Delete B node */
2365                 case 83:        /* Get status */
2366                 case 85:        /* Get instance info */
2367                 case 87:        /* Add super user */
2368                 case 88:        /* Delete super user */
2369                 case 93:        /* Set cell name */
2370                 case 96:        /* Add cell host */
2371                 case 97:        /* Delete cell host */
2372                 case 104:       /* Restart */
2373                 case 106:       /* Uninstall */
2374                 case 108:       /* Exec */
2375                 case 112:       /* Getlog */
2376                 case 114:       /* Get instance strings */
2377                         STROUT(BOSNAMEMAX);
2378                         break;
2379                 case 82:        /* Set status */
2380                 case 98:        /* Set T status */
2381                         STROUT(BOSNAMEMAX);
2382                         ND_PRINT(" status");
2383                         INTOUT();
2384                         break;
2385                 case 86:        /* Get instance parm */
2386                         STROUT(BOSNAMEMAX);
2387                         ND_PRINT(" num");
2388                         INTOUT();
2389                         break;
2390                 case 84:        /* Enumerate instance */
2391                 case 89:        /* List super users */
2392                 case 90:        /* List keys */
2393                 case 91:        /* Add key */
2394                 case 92:        /* Delete key */
2395                 case 95:        /* Get cell host */
2396                         INTOUT();
2397                         break;
2398                 case 105:       /* Install */
2399                         STROUT(BOSNAMEMAX);
2400                         ND_PRINT(" size");
2401                         INTOUT();
2402                         ND_PRINT(" flags");
2403                         INTOUT();
2404                         ND_PRINT(" date");
2405                         INTOUT();
2406                         break;
2407                 default:
2408                         ;
2409         }
2410
2411         return;
2412
2413 trunc:
2414         ND_PRINT(" [|bos]");
2415 }
2416
2417 /*
2418  * Handle replies to the AFS BOS Service
2419  */
2420
2421 static void
2422 bos_reply_print(netdissect_options *ndo,
2423                 const u_char *bp, u_int length, uint32_t opcode)
2424 {
2425         const struct rx_header *rxh;
2426         uint8_t type;
2427
2428         if (length <= sizeof(struct rx_header))
2429                 return;
2430
2431         rxh = (const struct rx_header *) bp;
2432
2433         /*
2434          * Print out the afs call we're invoking.  The table used here was
2435          * gleaned from volser/volint.xg
2436          */
2437
2438         ND_PRINT(" bos reply %s", tok2str(bos_req, "op#%u", opcode));
2439
2440         type = GET_U_1(rxh->type);
2441         bp += sizeof(struct rx_header);
2442
2443         /*
2444          * If it was a data packet, interpret the response.
2445          */
2446
2447         if (type == RX_PACKET_TYPE_DATA)
2448                 /* Well, no, not really.  Leave this for later */
2449                 ;
2450         else {
2451                 /*
2452                  * Otherwise, just print out the return code
2453                  */
2454                 ND_PRINT(" errcode");
2455                 INTOUT();
2456         }
2457 }
2458
2459 /*
2460  * Check to see if this is a Ubik opcode.
2461  */
2462
2463 static int
2464 is_ubik(uint32_t opcode)
2465 {
2466         if ((opcode >= VOTE_LOW && opcode <= VOTE_HIGH) ||
2467             (opcode >= DISK_LOW && opcode <= DISK_HIGH))
2468                 return(1);
2469         else
2470                 return(0);
2471 }
2472
2473 /*
2474  * Handle Ubik opcodes to any one of the replicated database services
2475  */
2476
2477 static void
2478 ubik_print(netdissect_options *ndo,
2479            const u_char *bp)
2480 {
2481         uint32_t ubik_op;
2482         uint32_t temp;
2483
2484         /*
2485          * Print out the afs call we're invoking.  The table used here was
2486          * gleaned from ubik/ubik_int.xg
2487          */
2488
2489         /* Every function that calls this function first makes a bounds check
2490          * for (sizeof(rx_header) + 4) bytes, so long as it remains this way
2491          * the line below will not over-read.
2492          */
2493         ubik_op = GET_BE_U_4(bp + sizeof(struct rx_header));
2494
2495         ND_PRINT(" ubik call %s", tok2str(ubik_req, "op#%u", ubik_op));
2496
2497         /*
2498          * Decode some of the arguments to the Ubik calls
2499          */
2500
2501         bp += sizeof(struct rx_header) + 4;
2502
2503         switch (ubik_op) {
2504                 case 10000:             /* Beacon */
2505                         temp = GET_BE_U_4(bp);
2506                         bp += sizeof(uint32_t);
2507                         ND_PRINT(" syncsite %s", temp ? "yes" : "no");
2508                         ND_PRINT(" votestart");
2509                         DATEOUT();
2510                         ND_PRINT(" dbversion");
2511                         UBIK_VERSIONOUT();
2512                         ND_PRINT(" tid");
2513                         UBIK_VERSIONOUT();
2514                         break;
2515                 case 10003:             /* Get sync site */
2516                         ND_PRINT(" site");
2517                         UINTOUT();
2518                         break;
2519                 case 20000:             /* Begin */
2520                 case 20001:             /* Commit */
2521                 case 20007:             /* Abort */
2522                 case 20008:             /* Release locks */
2523                 case 20010:             /* Writev */
2524                         ND_PRINT(" tid");
2525                         UBIK_VERSIONOUT();
2526                         break;
2527                 case 20002:             /* Lock */
2528                         ND_PRINT(" tid");
2529                         UBIK_VERSIONOUT();
2530                         ND_PRINT(" file");
2531                         INTOUT();
2532                         ND_PRINT(" pos");
2533                         INTOUT();
2534                         ND_PRINT(" length");
2535                         INTOUT();
2536                         temp = GET_BE_U_4(bp);
2537                         bp += sizeof(uint32_t);
2538                         tok2str(ubik_lock_types, "type %u", temp);
2539                         break;
2540                 case 20003:             /* Write */
2541                         ND_PRINT(" tid");
2542                         UBIK_VERSIONOUT();
2543                         ND_PRINT(" file");
2544                         INTOUT();
2545                         ND_PRINT(" pos");
2546                         INTOUT();
2547                         break;
2548                 case 20005:             /* Get file */
2549                         ND_PRINT(" file");
2550                         INTOUT();
2551                         break;
2552                 case 20006:             /* Send file */
2553                         ND_PRINT(" file");
2554                         INTOUT();
2555                         ND_PRINT(" length");
2556                         INTOUT();
2557                         ND_PRINT(" dbversion");
2558                         UBIK_VERSIONOUT();
2559                         break;
2560                 case 20009:             /* Truncate */
2561                         ND_PRINT(" tid");
2562                         UBIK_VERSIONOUT();
2563                         ND_PRINT(" file");
2564                         INTOUT();
2565                         ND_PRINT(" length");
2566                         INTOUT();
2567                         break;
2568                 case 20012:             /* Set version */
2569                         ND_PRINT(" tid");
2570                         UBIK_VERSIONOUT();
2571                         ND_PRINT(" oldversion");
2572                         UBIK_VERSIONOUT();
2573                         ND_PRINT(" newversion");
2574                         UBIK_VERSIONOUT();
2575                         break;
2576                 default:
2577                         ;
2578         }
2579
2580         return;
2581
2582 trunc:
2583         ND_PRINT(" [|ubik]");
2584 }
2585
2586 /*
2587  * Handle Ubik replies to any one of the replicated database services
2588  */
2589
2590 static void
2591 ubik_reply_print(netdissect_options *ndo,
2592                  const u_char *bp, u_int length, uint32_t opcode)
2593 {
2594         const struct rx_header *rxh;
2595         uint8_t type;
2596
2597         if (length < sizeof(struct rx_header))
2598                 return;
2599
2600         rxh = (const struct rx_header *) bp;
2601
2602         /*
2603          * Print out the ubik call we're invoking.  This table was gleaned
2604          * from ubik/ubik_int.xg
2605          */
2606
2607         ND_PRINT(" ubik reply %s", tok2str(ubik_req, "op#%u", opcode));
2608
2609         type = GET_U_1(rxh->type);
2610         bp += sizeof(struct rx_header);
2611
2612         /*
2613          * If it was a data packet, print out the arguments to the Ubik calls
2614          */
2615
2616         if (type == RX_PACKET_TYPE_DATA)
2617                 switch (opcode) {
2618                 case 10000:             /* Beacon */
2619                         ND_PRINT(" vote no");
2620                         break;
2621                 case 20004:             /* Get version */
2622                         ND_PRINT(" dbversion");
2623                         UBIK_VERSIONOUT();
2624                         break;
2625                 default:
2626                         ;
2627                 }
2628
2629         /*
2630          * Otherwise, print out "yes" if it was a beacon packet (because
2631          * that's how yes votes are returned, go figure), otherwise
2632          * just print out the error code.
2633          */
2634
2635         else
2636                 switch (opcode) {
2637                 case 10000:             /* Beacon */
2638                         ND_PRINT(" vote yes until");
2639                         DATEOUT();
2640                         break;
2641                 default:
2642                         ND_PRINT(" errcode");
2643                         INTOUT();
2644                 }
2645
2646         return;
2647
2648 trunc:
2649         ND_PRINT(" [|ubik]");
2650 }
2651
2652 /*
2653  * Handle RX ACK packets.
2654  */
2655
2656 static void
2657 rx_ack_print(netdissect_options *ndo,
2658              const u_char *bp, u_int length)
2659 {
2660         const struct rx_ackPacket *rxa;
2661         uint8_t nAcks;
2662         int i, start, last;
2663         uint32_t firstPacket;
2664
2665         if (length < sizeof(struct rx_header))
2666                 return;
2667
2668         bp += sizeof(struct rx_header);
2669
2670         ND_TCHECK_LEN(bp, sizeof(struct rx_ackPacket));
2671
2672         rxa = (const struct rx_ackPacket *) bp;
2673         bp += sizeof(struct rx_ackPacket);
2674
2675         /*
2676          * Print out a few useful things from the ack packet structure
2677          */
2678
2679         if (ndo->ndo_vflag > 2)
2680                 ND_PRINT(" bufspace %u maxskew %u",
2681                        GET_BE_U_2(rxa->bufferSpace),
2682                        GET_BE_U_2(rxa->maxSkew));
2683
2684         firstPacket = GET_BE_U_4(rxa->firstPacket);
2685         ND_PRINT(" first %u serial %u reason %s",
2686                firstPacket, GET_BE_U_4(rxa->serial),
2687                tok2str(rx_ack_reasons, "#%u", GET_U_1(rxa->reason)));
2688
2689         /*
2690          * Okay, now we print out the ack array.  The way _this_ works
2691          * is that we start at "first", and step through the ack array.
2692          * If we have a contiguous range of acks/nacks, try to
2693          * collapse them into a range.
2694          *
2695          * If you're really clever, you might have noticed that this
2696          * doesn't seem quite correct.  Specifically, due to structure
2697          * padding, sizeof(struct rx_ackPacket) - RX_MAXACKS won't actually
2698          * yield the start of the ack array (because RX_MAXACKS is 255
2699          * and the structure will likely get padded to a 2 or 4 byte
2700          * boundary).  However, this is the way it's implemented inside
2701          * of AFS - the start of the extra fields are at
2702          * sizeof(struct rx_ackPacket) - RX_MAXACKS + nAcks, which _isn't_
2703          * the exact start of the ack array.  Sigh.  That's why we aren't
2704          * using bp, but instead use rxa->acks[].  But nAcks gets added
2705          * to bp after this, so bp ends up at the right spot.  Go figure.
2706          */
2707
2708         nAcks = GET_U_1(rxa->nAcks);
2709         if (nAcks != 0) {
2710
2711                 ND_TCHECK_LEN(bp, nAcks);
2712
2713                 /*
2714                  * Sigh, this is gross, but it seems to work to collapse
2715                  * ranges correctly.
2716                  */
2717
2718                 for (i = 0, start = last = -2; i < nAcks; i++)
2719                         if (GET_U_1(bp + i) == RX_ACK_TYPE_ACK) {
2720
2721                                 /*
2722                                  * I figured this deserved _some_ explanation.
2723                                  * First, print "acked" and the packet seq
2724                                  * number if this is the first time we've
2725                                  * seen an acked packet.
2726                                  */
2727
2728                                 if (last == -2) {
2729                                         ND_PRINT(" acked %u", firstPacket + i);
2730                                         start = i;
2731                                 }
2732
2733                                 /*
2734                                  * Otherwise, if there is a skip in
2735                                  * the range (such as an nacked packet in
2736                                  * the middle of some acked packets),
2737                                  * then print the current packet number
2738                                  * separated from the last number by
2739                                  * a comma.
2740                                  */
2741
2742                                 else if (last != i - 1) {
2743                                         ND_PRINT(",%u", firstPacket + i);
2744                                         start = i;
2745                                 }
2746
2747                                 /*
2748                                  * We always set last to the value of
2749                                  * the last ack we saw.  Conversely, start
2750                                  * is set to the value of the first ack
2751                                  * we saw in a range.
2752                                  */
2753
2754                                 last = i;
2755
2756                                 /*
2757                                  * Okay, this bit a code gets executed when
2758                                  * we hit a nack ... in _this_ case we
2759                                  * want to print out the range of packets
2760                                  * that were acked, so we need to print
2761                                  * the _previous_ packet number separated
2762                                  * from the first by a dash (-).  Since we
2763                                  * already printed the first packet above,
2764                                  * just print the final packet.  Don't
2765                                  * do this if there will be a single-length
2766                                  * range.
2767                                  */
2768                         } else if (last == i - 1 && start != last)
2769                                 ND_PRINT("-%u", firstPacket + i - 1);
2770
2771                 /*
2772                  * So, what's going on here?  We ran off the end of the
2773                  * ack list, and if we got a range we need to finish it up.
2774                  * So we need to determine if the last packet in the list
2775                  * was an ack (if so, then last will be set to it) and
2776                  * we need to see if the last range didn't start with the
2777                  * last packet (because if it _did_, then that would mean
2778                  * that the packet number has already been printed and
2779                  * we don't need to print it again).
2780                  */
2781
2782                 if (last == i - 1 && start != last)
2783                         ND_PRINT("-%u", firstPacket + i - 1);
2784
2785                 /*
2786                  * Same as above, just without comments
2787                  */
2788
2789                 for (i = 0, start = last = -2; i < nAcks; i++)
2790                         if (GET_U_1(bp + i) == RX_ACK_TYPE_NACK) {
2791                                 if (last == -2) {
2792                                         ND_PRINT(" nacked %u", firstPacket + i);
2793                                         start = i;
2794                                 } else if (last != i - 1) {
2795                                         ND_PRINT(",%u", firstPacket + i);
2796                                         start = i;
2797                                 }
2798                                 last = i;
2799                         } else if (last == i - 1 && start != last)
2800                                 ND_PRINT("-%u", firstPacket + i - 1);
2801
2802                 if (last == i - 1 && start != last)
2803                         ND_PRINT("-%u", firstPacket + i - 1);
2804
2805                 bp += nAcks;
2806         }
2807
2808         /* Padding. */
2809         bp += 3;
2810
2811         /*
2812          * These are optional fields; depending on your version of AFS,
2813          * you may or may not see them
2814          */
2815
2816 #define TRUNCRET(n)     if (ndo->ndo_snapend - bp + 1 <= n) return;
2817
2818         if (ndo->ndo_vflag > 1) {
2819                 TRUNCRET(4);
2820                 ND_PRINT(" ifmtu");
2821                 UINTOUT();
2822
2823                 TRUNCRET(4);
2824                 ND_PRINT(" maxmtu");
2825                 UINTOUT();
2826
2827                 TRUNCRET(4);
2828                 ND_PRINT(" rwind");
2829                 UINTOUT();
2830
2831                 TRUNCRET(4);
2832                 ND_PRINT(" maxpackets");
2833                 UINTOUT();
2834         }
2835
2836         return;
2837
2838 trunc:
2839         ND_PRINT(" [|ack]");
2840 }
2841 #undef TRUNCRET