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