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