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