Move tcpdump-3.9/ to tcpdump/. No need for a versioned dir.
[dragonfly.git] / contrib / tcpdump / print-rx.c
1 /*
2  * Copyright: (c) 2000 United States Government as represented by the
3  *      Secretary of the Navy. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *   2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in
13  *      the documentation and/or other materials provided with the
14  *      distribution.
15  *   3. The names of the authors may not be used to endorse or promote
16  *      products derived from this software without specific prior
17  *      written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23 /*
24  * 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.2 2007/06/15 19:43:15 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         char fmt[1024];
1017
1018         if ((user = (char *)malloc(maxsize)) == NULL)
1019                 return;
1020
1021         if (sscanf((char *) s, "%d %d\n%n", &pos, &neg, &n) != 2)
1022                 goto finish;
1023
1024         s += n;
1025
1026         if (s > end)
1027                 goto finish;
1028
1029         /*
1030          * This wacky order preserves the order used by the "fs" command
1031          */
1032
1033 #define ACLOUT(acl) \
1034         if (acl & PRSFS_READ) \
1035                 printf("r"); \
1036         if (acl & PRSFS_LOOKUP) \
1037                 printf("l"); \
1038         if (acl & PRSFS_INSERT) \
1039                 printf("i"); \
1040         if (acl & PRSFS_DELETE) \
1041                 printf("d"); \
1042         if (acl & PRSFS_WRITE) \
1043                 printf("w"); \
1044         if (acl & PRSFS_LOCK) \
1045                 printf("k"); \
1046         if (acl & PRSFS_ADMINISTER) \
1047                 printf("a");
1048
1049         for (i = 0; i < pos; i++) {
1050                 snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1);
1051                 if (sscanf((char *) s, fmt, user, &acl, &n) != 2)
1052                         goto finish;
1053                 s += n;
1054                 printf(" +{");
1055                 fn_print((u_char *)user, NULL);
1056                 printf(" ");
1057                 ACLOUT(acl);
1058                 printf("}");
1059                 if (s > end)
1060                         goto finish;
1061         }
1062
1063         for (i = 0; i < neg; i++) {
1064                 snprintf(fmt, sizeof(fmt), "%%%ds %%d\n%%n", maxsize - 1);
1065                 if (sscanf((char *) s, fmt, user, &acl, &n) != 2)
1066                         goto finish;
1067                 s += n;
1068                 printf(" -{");
1069                 fn_print((u_char *)user, NULL);
1070                 printf(" ");
1071                 ACLOUT(acl);
1072                 printf("}");
1073                 if (s > end)
1074                         goto finish;
1075         }
1076
1077 finish:
1078         free(user);
1079         return;
1080 }
1081
1082 #undef ACLOUT
1083
1084 /*
1085  * Handle calls to the AFS callback service
1086  */
1087
1088 static void
1089 cb_print(register const u_char *bp, int length)
1090 {
1091         int cb_op;
1092         unsigned long i;
1093
1094         if (length <= (int)sizeof(struct rx_header))
1095                 return;
1096
1097         if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1098                 goto trunc;
1099         }
1100
1101         /*
1102          * Print out the afs call we're invoking.  The table used here was
1103          * gleaned from fsint/afscbint.xg
1104          */
1105
1106         cb_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1107
1108         printf(" cb call %s", tok2str(cb_req, "op#%d", cb_op));
1109
1110         bp += sizeof(struct rx_header) + 4;
1111
1112         /*
1113          * Print out the afs call we're invoking.  The table used here was
1114          * gleaned from fsint/afscbint.xg
1115          */
1116
1117         switch (cb_op) {
1118                 case 204:               /* Callback */
1119                 {
1120                         unsigned long j, t;
1121                         TCHECK2(bp[0], 4);
1122                         j = EXTRACT_32BITS(bp);
1123                         bp += sizeof(int32_t);
1124
1125                         for (i = 0; i < j; i++) {
1126                                 FIDOUT();
1127                                 if (i != j - 1)
1128                                         printf(",");
1129                         }
1130
1131                         if (j == 0)
1132                                 printf(" <none!>");
1133
1134                         j = EXTRACT_32BITS(bp);
1135                         bp += sizeof(int32_t);
1136
1137                         if (j != 0)
1138                                 printf(";");
1139
1140                         for (i = 0; i < j; i++) {
1141                                 printf(" ver");
1142                                 INTOUT();
1143                                 printf(" expires");
1144                                 DATEOUT();
1145                                 TCHECK2(bp[0], 4);
1146                                 t = EXTRACT_32BITS(bp);
1147                                 bp += sizeof(int32_t);
1148                                 tok2str(cb_types, "type %d", t);
1149                         }
1150                 }
1151                 case 214: {
1152                         printf(" afsuuid");
1153                         AFSUUIDOUT();
1154                         break;
1155                 }
1156                 default:
1157                         ;
1158         }
1159
1160         return;
1161
1162 trunc:
1163         printf(" [|cb]");
1164 }
1165
1166 /*
1167  * Handle replies to the AFS Callback Service
1168  */
1169
1170 static void
1171 cb_reply_print(register const u_char *bp, int length, int32_t opcode)
1172 {
1173         struct rx_header *rxh;
1174
1175         if (length <= (int)sizeof(struct rx_header))
1176                 return;
1177
1178         rxh = (struct rx_header *) bp;
1179
1180         /*
1181          * Print out the afs call we're invoking.  The table used here was
1182          * gleaned from fsint/afscbint.xg
1183          */
1184
1185         printf(" cb reply %s", tok2str(cb_req, "op#%d", opcode));
1186
1187         bp += sizeof(struct rx_header);
1188
1189         /*
1190          * If it was a data packet, interpret the response.
1191          */
1192
1193         if (rxh->type == RX_PACKET_TYPE_DATA)
1194                 switch (opcode) {
1195                 case 213:       /* InitCallBackState3 */
1196                         AFSUUIDOUT();
1197                         break;
1198                 default:
1199                 ;
1200                 }
1201         else {
1202                 /*
1203                  * Otherwise, just print out the return code
1204                  */
1205                 printf(" errcode");
1206                 INTOUT();
1207         }
1208
1209         return;
1210
1211 trunc:
1212         printf(" [|cb]");
1213 }
1214
1215 /*
1216  * Handle calls to the AFS protection database server
1217  */
1218
1219 static void
1220 prot_print(register const u_char *bp, int length)
1221 {
1222         unsigned long i;
1223         int pt_op;
1224
1225         if (length <= (int)sizeof(struct rx_header))
1226                 return;
1227
1228         if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1229                 goto trunc;
1230         }
1231
1232         /*
1233          * Print out the afs call we're invoking.  The table used here was
1234          * gleaned from ptserver/ptint.xg
1235          */
1236
1237         pt_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1238
1239         printf(" pt");
1240
1241         if (is_ubik(pt_op)) {
1242                 ubik_print(bp);
1243                 return;
1244         }
1245
1246         printf(" call %s", tok2str(pt_req, "op#%d", pt_op));
1247
1248         /*
1249          * Decode some of the arguments to the PT calls
1250          */
1251
1252         bp += sizeof(struct rx_header) + 4;
1253
1254         switch (pt_op) {
1255                 case 500:       /* I New User */
1256                         STROUT(PRNAMEMAX);
1257                         printf(" id");
1258                         INTOUT();
1259                         printf(" oldid");
1260                         INTOUT();
1261                         break;
1262                 case 501:       /* Where is it */
1263                 case 506:       /* Delete */
1264                 case 508:       /* Get CPS */
1265                 case 512:       /* List entry */
1266                 case 514:       /* List elements */
1267                 case 517:       /* List owned */
1268                 case 518:       /* Get CPS2 */
1269                 case 519:       /* Get host CPS */
1270                         printf(" id");
1271                         INTOUT();
1272                         break;
1273                 case 502:       /* Dump entry */
1274                         printf(" pos");
1275                         INTOUT();
1276                         break;
1277                 case 503:       /* Add to group */
1278                 case 507:       /* Remove from group */
1279                 case 515:       /* Is a member of? */
1280                         printf(" uid");
1281                         INTOUT();
1282                         printf(" gid");
1283                         INTOUT();
1284                         break;
1285                 case 504:       /* Name to ID */
1286                 {
1287                         unsigned long j;
1288                         TCHECK2(bp[0], 4);
1289                         j = EXTRACT_32BITS(bp);
1290                         bp += sizeof(int32_t);
1291
1292                         /*
1293                          * Who designed this chicken-shit protocol?
1294                          *
1295                          * Each character is stored as a 32-bit
1296                          * integer!
1297                          */
1298
1299                         for (i = 0; i < j; i++) {
1300                                 VECOUT(PRNAMEMAX);
1301                         }
1302                         if (j == 0)
1303                                 printf(" <none!>");
1304                 }
1305                         break;
1306                 case 505:       /* Id to name */
1307                 {
1308                         unsigned long j;
1309                         printf(" ids:");
1310                         TCHECK2(bp[0], 4);
1311                         i = EXTRACT_32BITS(bp);
1312                         bp += sizeof(int32_t);
1313                         for (j = 0; j < i; j++)
1314                                 INTOUT();
1315                         if (j == 0)
1316                                 printf(" <none!>");
1317                 }
1318                         break;
1319                 case 509:       /* New entry */
1320                         STROUT(PRNAMEMAX);
1321                         printf(" flag");
1322                         INTOUT();
1323                         printf(" oid");
1324                         INTOUT();
1325                         break;
1326                 case 511:       /* Set max */
1327                         printf(" id");
1328                         INTOUT();
1329                         printf(" gflag");
1330                         INTOUT();
1331                         break;
1332                 case 513:       /* Change entry */
1333                         printf(" id");
1334                         INTOUT();
1335                         STROUT(PRNAMEMAX);
1336                         printf(" oldid");
1337                         INTOUT();
1338                         printf(" newid");
1339                         INTOUT();
1340                         break;
1341                 case 520:       /* Update entry */
1342                         printf(" id");
1343                         INTOUT();
1344                         STROUT(PRNAMEMAX);
1345                         break;
1346                 default:
1347                         ;
1348         }
1349
1350
1351         return;
1352
1353 trunc:
1354         printf(" [|pt]");
1355 }
1356
1357 /*
1358  * Handle replies to the AFS protection service
1359  */
1360
1361 static void
1362 prot_reply_print(register const u_char *bp, int length, int32_t opcode)
1363 {
1364         struct rx_header *rxh;
1365         unsigned long i;
1366
1367         if (length < (int)sizeof(struct rx_header))
1368                 return;
1369
1370         rxh = (struct rx_header *) bp;
1371
1372         /*
1373          * Print out the afs call we're invoking.  The table used here was
1374          * gleaned from ptserver/ptint.xg.  Check to see if it's a
1375          * Ubik call, however.
1376          */
1377
1378         printf(" pt");
1379
1380         if (is_ubik(opcode)) {
1381                 ubik_reply_print(bp, length, opcode);
1382                 return;
1383         }
1384
1385         printf(" reply %s", tok2str(pt_req, "op#%d", opcode));
1386
1387         bp += sizeof(struct rx_header);
1388
1389         /*
1390          * If it was a data packet, interpret the response
1391          */
1392
1393         if (rxh->type == RX_PACKET_TYPE_DATA)
1394                 switch (opcode) {
1395                 case 504:               /* Name to ID */
1396                 {
1397                         unsigned long j;
1398                         printf(" ids:");
1399                         TCHECK2(bp[0], 4);
1400                         i = EXTRACT_32BITS(bp);
1401                         bp += sizeof(int32_t);
1402                         for (j = 0; j < i; j++)
1403                                 INTOUT();
1404                         if (j == 0)
1405                                 printf(" <none!>");
1406                 }
1407                         break;
1408                 case 505:               /* ID to name */
1409                 {
1410                         unsigned long j;
1411                         TCHECK2(bp[0], 4);
1412                         j = EXTRACT_32BITS(bp);
1413                         bp += sizeof(int32_t);
1414
1415                         /*
1416                          * Who designed this chicken-shit protocol?
1417                          *
1418                          * Each character is stored as a 32-bit
1419                          * integer!
1420                          */
1421
1422                         for (i = 0; i < j; i++) {
1423                                 VECOUT(PRNAMEMAX);
1424                         }
1425                         if (j == 0)
1426                                 printf(" <none!>");
1427                 }
1428                         break;
1429                 case 508:               /* Get CPS */
1430                 case 514:               /* List elements */
1431                 case 517:               /* List owned */
1432                 case 518:               /* Get CPS2 */
1433                 case 519:               /* Get host CPS */
1434                 {
1435                         unsigned long j;
1436                         TCHECK2(bp[0], 4);
1437                         j = EXTRACT_32BITS(bp);
1438                         bp += sizeof(int32_t);
1439                         for (i = 0; i < j; i++) {
1440                                 INTOUT();
1441                         }
1442                         if (j == 0)
1443                                 printf(" <none!>");
1444                 }
1445                         break;
1446                 case 510:               /* List max */
1447                         printf(" maxuid");
1448                         INTOUT();
1449                         printf(" maxgid");
1450                         INTOUT();
1451                         break;
1452                 default:
1453                         ;
1454                 }
1455         else {
1456                 /*
1457                  * Otherwise, just print out the return code
1458                  */
1459                 printf(" errcode");
1460                 INTOUT();
1461         }
1462
1463         return;
1464
1465 trunc:
1466         printf(" [|pt]");
1467 }
1468
1469 /*
1470  * Handle calls to the AFS volume location database service
1471  */
1472
1473 static void
1474 vldb_print(register const u_char *bp, int length)
1475 {
1476         int vldb_op;
1477         unsigned long i;
1478
1479         if (length <= (int)sizeof(struct rx_header))
1480                 return;
1481
1482         if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1483                 goto trunc;
1484         }
1485
1486         /*
1487          * Print out the afs call we're invoking.  The table used here was
1488          * gleaned from vlserver/vldbint.xg
1489          */
1490
1491         vldb_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1492
1493         printf(" vldb");
1494
1495         if (is_ubik(vldb_op)) {
1496                 ubik_print(bp);
1497                 return;
1498         }
1499         printf(" call %s", tok2str(vldb_req, "op#%d", vldb_op));
1500
1501         /*
1502          * Decode some of the arguments to the VLDB calls
1503          */
1504
1505         bp += sizeof(struct rx_header) + 4;
1506
1507         switch (vldb_op) {
1508                 case 501:       /* Create new volume */
1509                 case 517:       /* Create entry N */
1510                         VECOUT(VLNAMEMAX);
1511                         break;
1512                 case 502:       /* Delete entry */
1513                 case 503:       /* Get entry by ID */
1514                 case 507:       /* Update entry */
1515                 case 508:       /* Set lock */
1516                 case 509:       /* Release lock */
1517                 case 518:       /* Get entry by ID N */
1518                         printf(" volid");
1519                         INTOUT();
1520                         TCHECK2(bp[0], sizeof(int32_t));
1521                         i = EXTRACT_32BITS(bp);
1522                         bp += sizeof(int32_t);
1523                         if (i <= 2)
1524                                 printf(" type %s", voltype[i]);
1525                         break;
1526                 case 504:       /* Get entry by name */
1527                 case 519:       /* Get entry by name N */
1528                 case 524:       /* Update entry by name */
1529                 case 527:       /* Get entry by name U */
1530                         STROUT(VLNAMEMAX);
1531                         break;
1532                 case 505:       /* Get new vol id */
1533                         printf(" bump");
1534                         INTOUT();
1535                         break;
1536                 case 506:       /* Replace entry */
1537                 case 520:       /* Replace entry N */
1538                         printf(" volid");
1539                         INTOUT();
1540                         TCHECK2(bp[0], sizeof(int32_t));
1541                         i = EXTRACT_32BITS(bp);
1542                         bp += sizeof(int32_t);
1543                         if (i <= 2)
1544                                 printf(" type %s", voltype[i]);
1545                         VECOUT(VLNAMEMAX);
1546                         break;
1547                 case 510:       /* List entry */
1548                 case 521:       /* List entry N */
1549                         printf(" index");
1550                         INTOUT();
1551                         break;
1552                 default:
1553                         ;
1554         }
1555
1556         return;
1557
1558 trunc:
1559         printf(" [|vldb]");
1560 }
1561
1562 /*
1563  * Handle replies to the AFS volume location database service
1564  */
1565
1566 static void
1567 vldb_reply_print(register const u_char *bp, int length, int32_t opcode)
1568 {
1569         struct rx_header *rxh;
1570         unsigned long i;
1571
1572         if (length < (int)sizeof(struct rx_header))
1573                 return;
1574
1575         rxh = (struct rx_header *) bp;
1576
1577         /*
1578          * Print out the afs call we're invoking.  The table used here was
1579          * gleaned from vlserver/vldbint.xg.  Check to see if it's a
1580          * Ubik call, however.
1581          */
1582
1583         printf(" vldb");
1584
1585         if (is_ubik(opcode)) {
1586                 ubik_reply_print(bp, length, opcode);
1587                 return;
1588         }
1589
1590         printf(" reply %s", tok2str(vldb_req, "op#%d", opcode));
1591
1592         bp += sizeof(struct rx_header);
1593
1594         /*
1595          * If it was a data packet, interpret the response
1596          */
1597
1598         if (rxh->type == RX_PACKET_TYPE_DATA)
1599                 switch (opcode) {
1600                 case 510:       /* List entry */
1601                         printf(" count");
1602                         INTOUT();
1603                         printf(" nextindex");
1604                         INTOUT();
1605                 case 503:       /* Get entry by id */
1606                 case 504:       /* Get entry by name */
1607                 {       unsigned long nservers, j;
1608                         VECOUT(VLNAMEMAX);
1609                         TCHECK2(bp[0], sizeof(int32_t));
1610                         bp += sizeof(int32_t);
1611                         printf(" numservers");
1612                         TCHECK2(bp[0], sizeof(int32_t));
1613                         nservers = EXTRACT_32BITS(bp);
1614                         bp += sizeof(int32_t);
1615                         printf(" %lu", nservers);
1616                         printf(" servers");
1617                         for (i = 0; i < 8; i++) {
1618                                 TCHECK2(bp[0], sizeof(int32_t));
1619                                 if (i < nservers)
1620                                         printf(" %s",
1621                                            intoa(((struct in_addr *) bp)->s_addr));
1622                                 bp += sizeof(int32_t);
1623                         }
1624                         printf(" partitions");
1625                         for (i = 0; i < 8; i++) {
1626                                 TCHECK2(bp[0], sizeof(int32_t));
1627                                 j = EXTRACT_32BITS(bp);
1628                                 if (i < nservers && j <= 26)
1629                                         printf(" %c", 'a' + (int)j);
1630                                 else if (i < nservers)
1631                                         printf(" %lu", j);
1632                                 bp += sizeof(int32_t);
1633                         }
1634                         TCHECK2(bp[0], 8 * sizeof(int32_t));
1635                         bp += 8 * sizeof(int32_t);
1636                         printf(" rwvol");
1637                         UINTOUT();
1638                         printf(" rovol");
1639                         UINTOUT();
1640                         printf(" backup");
1641                         UINTOUT();
1642                 }
1643                         break;
1644                 case 505:       /* Get new volume ID */
1645                         printf(" newvol");
1646                         UINTOUT();
1647                         break;
1648                 case 521:       /* List entry */
1649                 case 529:       /* List entry U */
1650                         printf(" count");
1651                         INTOUT();
1652                         printf(" nextindex");
1653                         INTOUT();
1654                 case 518:       /* Get entry by ID N */
1655                 case 519:       /* Get entry by name N */
1656                 {       unsigned long nservers, j;
1657                         VECOUT(VLNAMEMAX);
1658                         printf(" numservers");
1659                         TCHECK2(bp[0], sizeof(int32_t));
1660                         nservers = EXTRACT_32BITS(bp);
1661                         bp += sizeof(int32_t);
1662                         printf(" %lu", nservers);
1663                         printf(" servers");
1664                         for (i = 0; i < 13; i++) {
1665                                 TCHECK2(bp[0], sizeof(int32_t));
1666                                 if (i < nservers)
1667                                         printf(" %s",
1668                                            intoa(((struct in_addr *) bp)->s_addr));
1669                                 bp += sizeof(int32_t);
1670                         }
1671                         printf(" partitions");
1672                         for (i = 0; i < 13; i++) {
1673                                 TCHECK2(bp[0], sizeof(int32_t));
1674                                 j = EXTRACT_32BITS(bp);
1675                                 if (i < nservers && j <= 26)
1676                                         printf(" %c", 'a' + (int)j);
1677                                 else if (i < nservers)
1678                                         printf(" %lu", j);
1679                                 bp += sizeof(int32_t);
1680                         }
1681                         TCHECK2(bp[0], 13 * sizeof(int32_t));
1682                         bp += 13 * sizeof(int32_t);
1683                         printf(" rwvol");
1684                         UINTOUT();
1685                         printf(" rovol");
1686                         UINTOUT();
1687                         printf(" backup");
1688                         UINTOUT();
1689                 }
1690                         break;
1691                 case 526:       /* Get entry by ID U */
1692                 case 527:       /* Get entry by name U */
1693                 {       unsigned long nservers, j;
1694                         VECOUT(VLNAMEMAX);
1695                         printf(" numservers");
1696                         TCHECK2(bp[0], sizeof(int32_t));
1697                         nservers = EXTRACT_32BITS(bp);
1698                         bp += sizeof(int32_t);
1699                         printf(" %lu", nservers);
1700                         printf(" servers");
1701                         for (i = 0; i < 13; i++) {
1702                                 if (i < nservers) {
1703                                         printf(" afsuuid");
1704                                         AFSUUIDOUT();
1705                                 } else {
1706                                         TCHECK2(bp[0], 44);
1707                                         bp += 44;
1708                                 }
1709                         }
1710                         TCHECK2(bp[0], 4 * 13);
1711                         bp += 4 * 13;
1712                         printf(" partitions");
1713                         for (i = 0; i < 13; i++) {
1714                                 TCHECK2(bp[0], sizeof(int32_t));
1715                                 j = EXTRACT_32BITS(bp);
1716                                 if (i < nservers && j <= 26)
1717                                         printf(" %c", 'a' + (int)j);
1718                                 else if (i < nservers)
1719                                         printf(" %lu", j);
1720                                 bp += sizeof(int32_t);
1721                         }
1722                         TCHECK2(bp[0], 13 * sizeof(int32_t));
1723                         bp += 13 * sizeof(int32_t);
1724                         printf(" rwvol");
1725                         UINTOUT();
1726                         printf(" rovol");
1727                         UINTOUT();
1728                         printf(" backup");
1729                         UINTOUT();
1730                 }
1731                 default:
1732                         ;
1733                 }
1734
1735         else {
1736                 /*
1737                  * Otherwise, just print out the return code
1738                  */
1739                 printf(" errcode");
1740                 INTOUT();
1741         }
1742
1743         return;
1744
1745 trunc:
1746         printf(" [|vldb]");
1747 }
1748
1749 /*
1750  * Handle calls to the AFS Kerberos Authentication service
1751  */
1752
1753 static void
1754 kauth_print(register const u_char *bp, int length)
1755 {
1756         int kauth_op;
1757
1758         if (length <= (int)sizeof(struct rx_header))
1759                 return;
1760
1761         if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1762                 goto trunc;
1763         }
1764
1765         /*
1766          * Print out the afs call we're invoking.  The table used here was
1767          * gleaned from kauth/kauth.rg
1768          */
1769
1770         kauth_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1771
1772         printf(" kauth");
1773
1774         if (is_ubik(kauth_op)) {
1775                 ubik_print(bp);
1776                 return;
1777         }
1778
1779
1780         printf(" call %s", tok2str(kauth_req, "op#%d", kauth_op));
1781
1782         /*
1783          * Decode some of the arguments to the KA calls
1784          */
1785
1786         bp += sizeof(struct rx_header) + 4;
1787
1788         switch (kauth_op) {
1789                 case 1:         /* Authenticate old */;
1790                 case 21:        /* Authenticate */
1791                 case 22:        /* Authenticate-V2 */
1792                 case 2:         /* Change PW */
1793                 case 5:         /* Set fields */
1794                 case 6:         /* Create user */
1795                 case 7:         /* Delete user */
1796                 case 8:         /* Get entry */
1797                 case 14:        /* Unlock */
1798                 case 15:        /* Lock status */
1799                         printf(" principal");
1800                         STROUT(KANAMEMAX);
1801                         STROUT(KANAMEMAX);
1802                         break;
1803                 case 3:         /* GetTicket-old */
1804                 case 23:        /* GetTicket */
1805                 {
1806                         int i;
1807                         printf(" kvno");
1808                         INTOUT();
1809                         printf(" domain");
1810                         STROUT(KANAMEMAX);
1811                         TCHECK2(bp[0], sizeof(int32_t));
1812                         i = (int) EXTRACT_32BITS(bp);
1813                         bp += sizeof(int32_t);
1814                         TCHECK2(bp[0], i);
1815                         bp += i;
1816                         printf(" principal");
1817                         STROUT(KANAMEMAX);
1818                         STROUT(KANAMEMAX);
1819                         break;
1820                 }
1821                 case 4:         /* Set Password */
1822                         printf(" principal");
1823                         STROUT(KANAMEMAX);
1824                         STROUT(KANAMEMAX);
1825                         printf(" kvno");
1826                         INTOUT();
1827                         break;
1828                 case 12:        /* Get password */
1829                         printf(" name");
1830                         STROUT(KANAMEMAX);
1831                         break;
1832                 default:
1833                         ;
1834         }
1835
1836         return;
1837
1838 trunc:
1839         printf(" [|kauth]");
1840 }
1841
1842 /*
1843  * Handle replies to the AFS Kerberos Authentication Service
1844  */
1845
1846 static void
1847 kauth_reply_print(register const u_char *bp, int length, int32_t opcode)
1848 {
1849         struct rx_header *rxh;
1850
1851         if (length <= (int)sizeof(struct rx_header))
1852                 return;
1853
1854         rxh = (struct rx_header *) bp;
1855
1856         /*
1857          * Print out the afs call we're invoking.  The table used here was
1858          * gleaned from kauth/kauth.rg
1859          */
1860
1861         printf(" kauth");
1862
1863         if (is_ubik(opcode)) {
1864                 ubik_reply_print(bp, length, opcode);
1865                 return;
1866         }
1867
1868         printf(" reply %s", tok2str(kauth_req, "op#%d", opcode));
1869
1870         bp += sizeof(struct rx_header);
1871
1872         /*
1873          * If it was a data packet, interpret the response.
1874          */
1875
1876         if (rxh->type == RX_PACKET_TYPE_DATA)
1877                 /* Well, no, not really.  Leave this for later */
1878                 ;
1879         else {
1880                 /*
1881                  * Otherwise, just print out the return code
1882                  */
1883                 printf(" errcode");
1884                 INTOUT();
1885         }
1886
1887         return;
1888
1889 trunc:
1890         printf(" [|kauth]");
1891 }
1892
1893 /*
1894  * Handle calls to the AFS Volume location service
1895  */
1896
1897 static void
1898 vol_print(register const u_char *bp, int length)
1899 {
1900         int vol_op;
1901
1902         if (length <= (int)sizeof(struct rx_header))
1903                 return;
1904
1905         if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1906                 goto trunc;
1907         }
1908
1909         /*
1910          * Print out the afs call we're invoking.  The table used here was
1911          * gleaned from volser/volint.xg
1912          */
1913
1914         vol_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1915
1916         printf(" vol call %s", tok2str(vol_req, "op#%d", vol_op));
1917
1918         /*
1919          * Normally there would be a switch statement here to decode the
1920          * arguments to the AFS call, but since I don't have access to
1921          * an AFS server (yet) and I'm not an AFS admin, I can't
1922          * test any of these calls.  Leave this blank for now.
1923          */
1924
1925         return;
1926
1927 trunc:
1928         printf(" [|vol]");
1929 }
1930
1931 /*
1932  * Handle replies to the AFS Volume Service
1933  */
1934
1935 static void
1936 vol_reply_print(register const u_char *bp, int length, int32_t opcode)
1937 {
1938         struct rx_header *rxh;
1939
1940         if (length <= (int)sizeof(struct rx_header))
1941                 return;
1942
1943         rxh = (struct rx_header *) bp;
1944
1945         /*
1946          * Print out the afs call we're invoking.  The table used here was
1947          * gleaned from volser/volint.xg
1948          */
1949
1950         printf(" vol reply %s", tok2str(vol_req, "op#%d", opcode));
1951
1952         bp += sizeof(struct rx_header);
1953
1954         /*
1955          * If it was a data packet, interpret the response.
1956          */
1957
1958         if (rxh->type == RX_PACKET_TYPE_DATA)
1959                 /* Well, no, not really.  Leave this for later */
1960                 ;
1961         else {
1962                 /*
1963                  * Otherwise, just print out the return code
1964                  */
1965                 printf(" errcode");
1966                 INTOUT();
1967         }
1968
1969         return;
1970
1971 trunc:
1972         printf(" [|vol]");
1973 }
1974
1975 /*
1976  * Handle calls to the AFS BOS service
1977  */
1978
1979 static void
1980 bos_print(register const u_char *bp, int length)
1981 {
1982         int bos_op;
1983
1984         if (length <= (int)sizeof(struct rx_header))
1985                 return;
1986
1987         if (snapend - bp + 1 <= (int)(sizeof(struct rx_header) + sizeof(int32_t))) {
1988                 goto trunc;
1989         }
1990
1991         /*
1992          * Print out the afs call we're invoking.  The table used here was
1993          * gleaned from bozo/bosint.xg
1994          */
1995
1996         bos_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
1997
1998         printf(" bos call %s", tok2str(bos_req, "op#%d", bos_op));
1999
2000         /*
2001          * Decode some of the arguments to the BOS calls
2002          */
2003
2004         bp += sizeof(struct rx_header) + 4;
2005
2006         switch (bos_op) {
2007                 case 80:        /* Create B node */
2008                         printf(" type");
2009                         STROUT(BOSNAMEMAX);
2010                         printf(" instance");
2011                         STROUT(BOSNAMEMAX);
2012                         break;
2013                 case 81:        /* Delete B node */
2014                 case 83:        /* Get status */
2015                 case 85:        /* Get instance info */
2016                 case 87:        /* Add super user */
2017                 case 88:        /* Delete super user */
2018                 case 93:        /* Set cell name */
2019                 case 96:        /* Add cell host */
2020                 case 97:        /* Delete cell host */
2021                 case 104:       /* Restart */
2022                 case 106:       /* Uninstall */
2023                 case 108:       /* Exec */
2024                 case 112:       /* Getlog */
2025                 case 114:       /* Get instance strings */
2026                         STROUT(BOSNAMEMAX);
2027                         break;
2028                 case 82:        /* Set status */
2029                 case 98:        /* Set T status */
2030                         STROUT(BOSNAMEMAX);
2031                         printf(" status");
2032                         INTOUT();
2033                         break;
2034                 case 86:        /* Get instance parm */
2035                         STROUT(BOSNAMEMAX);
2036                         printf(" num");
2037                         INTOUT();
2038                         break;
2039                 case 84:        /* Enumerate instance */
2040                 case 89:        /* List super users */
2041                 case 90:        /* List keys */
2042                 case 91:        /* Add key */
2043                 case 92:        /* Delete key */
2044                 case 95:        /* Get cell host */
2045                         INTOUT();
2046                         break;
2047                 case 105:       /* Install */
2048                         STROUT(BOSNAMEMAX);
2049                         printf(" size");
2050                         INTOUT();
2051                         printf(" flags");
2052                         INTOUT();
2053                         printf(" date");
2054                         INTOUT();
2055                         break;
2056                 default:
2057                         ;
2058         }
2059
2060         return;
2061
2062 trunc:
2063         printf(" [|bos]");
2064 }
2065
2066 /*
2067  * Handle replies to the AFS BOS Service
2068  */
2069
2070 static void
2071 bos_reply_print(register const u_char *bp, int length, int32_t opcode)
2072 {
2073         struct rx_header *rxh;
2074
2075         if (length <= (int)sizeof(struct rx_header))
2076                 return;
2077
2078         rxh = (struct rx_header *) bp;
2079
2080         /*
2081          * Print out the afs call we're invoking.  The table used here was
2082          * gleaned from volser/volint.xg
2083          */
2084
2085         printf(" bos reply %s", tok2str(bos_req, "op#%d", opcode));
2086
2087         bp += sizeof(struct rx_header);
2088
2089         /*
2090          * If it was a data packet, interpret the response.
2091          */
2092
2093         if (rxh->type == RX_PACKET_TYPE_DATA)
2094                 /* Well, no, not really.  Leave this for later */
2095                 ;
2096         else {
2097                 /*
2098                  * Otherwise, just print out the return code
2099                  */
2100                 printf(" errcode");
2101                 INTOUT();
2102         }
2103
2104         return;
2105
2106 trunc:
2107         printf(" [|bos]");
2108 }
2109
2110 /*
2111  * Check to see if this is a Ubik opcode.
2112  */
2113
2114 static int
2115 is_ubik(u_int32_t opcode)
2116 {
2117         if ((opcode >= VOTE_LOW && opcode <= VOTE_HIGH) ||
2118             (opcode >= DISK_LOW && opcode <= DISK_HIGH))
2119                 return(1);
2120         else
2121                 return(0);
2122 }
2123
2124 /*
2125  * Handle Ubik opcodes to any one of the replicated database services
2126  */
2127
2128 static void
2129 ubik_print(register const u_char *bp)
2130 {
2131         int ubik_op;
2132         int32_t temp;
2133
2134         /*
2135          * Print out the afs call we're invoking.  The table used here was
2136          * gleaned from ubik/ubik_int.xg
2137          */
2138
2139         ubik_op = EXTRACT_32BITS(bp + sizeof(struct rx_header));
2140
2141         printf(" ubik call %s", tok2str(ubik_req, "op#%d", ubik_op));
2142
2143         /*
2144          * Decode some of the arguments to the Ubik calls
2145          */
2146
2147         bp += sizeof(struct rx_header) + 4;
2148
2149         switch (ubik_op) {
2150                 case 10000:             /* Beacon */
2151                         TCHECK2(bp[0], 4);
2152                         temp = EXTRACT_32BITS(bp);
2153                         bp += sizeof(int32_t);
2154                         printf(" syncsite %s", temp ? "yes" : "no");
2155                         printf(" votestart");
2156                         DATEOUT();
2157                         printf(" dbversion");
2158                         UBIK_VERSIONOUT();
2159                         printf(" tid");
2160                         UBIK_VERSIONOUT();
2161                         break;
2162                 case 10003:             /* Get sync site */
2163                         printf(" site");
2164                         UINTOUT();
2165                         break;
2166                 case 20000:             /* Begin */
2167                 case 20001:             /* Commit */
2168                 case 20007:             /* Abort */
2169                 case 20008:             /* Release locks */
2170                 case 20010:             /* Writev */
2171                         printf(" tid");
2172                         UBIK_VERSIONOUT();
2173                         break;
2174                 case 20002:             /* Lock */
2175                         printf(" tid");
2176                         UBIK_VERSIONOUT();
2177                         printf(" file");
2178                         INTOUT();
2179                         printf(" pos");
2180                         INTOUT();
2181                         printf(" length");
2182                         INTOUT();
2183                         temp = EXTRACT_32BITS(bp);
2184                         bp += sizeof(int32_t);
2185                         tok2str(ubik_lock_types, "type %d", temp);
2186                         break;
2187                 case 20003:             /* Write */
2188                         printf(" tid");
2189                         UBIK_VERSIONOUT();
2190                         printf(" file");
2191                         INTOUT();
2192                         printf(" pos");
2193                         INTOUT();
2194                         break;
2195                 case 20005:             /* Get file */
2196                         printf(" file");
2197                         INTOUT();
2198                         break;
2199                 case 20006:             /* Send file */
2200                         printf(" file");
2201                         INTOUT();
2202                         printf(" length");
2203                         INTOUT();
2204                         printf(" dbversion");
2205                         UBIK_VERSIONOUT();
2206                         break;
2207                 case 20009:             /* Truncate */
2208                         printf(" tid");
2209                         UBIK_VERSIONOUT();
2210                         printf(" file");
2211                         INTOUT();
2212                         printf(" length");
2213                         INTOUT();
2214                         break;
2215                 case 20012:             /* Set version */
2216                         printf(" tid");
2217                         UBIK_VERSIONOUT();
2218                         printf(" oldversion");
2219                         UBIK_VERSIONOUT();
2220                         printf(" newversion");
2221                         UBIK_VERSIONOUT();
2222                         break;
2223                 default:
2224                         ;
2225         }
2226
2227         return;
2228
2229 trunc:
2230         printf(" [|ubik]");
2231 }
2232
2233 /*
2234  * Handle Ubik replies to any one of the replicated database services
2235  */
2236
2237 static void
2238 ubik_reply_print(register const u_char *bp, int length, int32_t opcode)
2239 {
2240         struct rx_header *rxh;
2241
2242         if (length < (int)sizeof(struct rx_header))
2243                 return;
2244
2245         rxh = (struct rx_header *) bp;
2246
2247         /*
2248          * Print out the ubik call we're invoking.  This table was gleaned
2249          * from ubik/ubik_int.xg
2250          */
2251
2252         printf(" ubik reply %s", tok2str(ubik_req, "op#%d", opcode));
2253
2254         bp += sizeof(struct rx_header);
2255
2256         /*
2257          * If it was a data packet, print out the arguments to the Ubik calls
2258          */
2259
2260         if (rxh->type == RX_PACKET_TYPE_DATA)
2261                 switch (opcode) {
2262                 case 10000:             /* Beacon */
2263                         printf(" vote no");
2264                         break;
2265                 case 20004:             /* Get version */
2266                         printf(" dbversion");
2267                         UBIK_VERSIONOUT();
2268                         break;
2269                 default:
2270                         ;
2271                 }
2272
2273         /*
2274          * Otherwise, print out "yes" it it was a beacon packet (because
2275          * that's how yes votes are returned, go figure), otherwise
2276          * just print out the error code.
2277          */
2278
2279         else
2280                 switch (opcode) {
2281                 case 10000:             /* Beacon */
2282                         printf(" vote yes until");
2283                         DATEOUT();
2284                         break;
2285                 default:
2286                         printf(" errcode");
2287                         INTOUT();
2288                 }
2289
2290         return;
2291
2292 trunc:
2293         printf(" [|ubik]");
2294 }
2295
2296 /*
2297  * Handle RX ACK packets.
2298  */
2299
2300 static void
2301 rx_ack_print(register const u_char *bp, int length)
2302 {
2303         struct rx_ackPacket *rxa;
2304         int i, start, last;
2305         u_int32_t firstPacket;
2306
2307         if (length < (int)sizeof(struct rx_header))
2308                 return;
2309
2310         bp += sizeof(struct rx_header);
2311
2312         /*
2313          * This may seem a little odd .... the rx_ackPacket structure
2314          * contains an array of individual packet acknowledgements
2315          * (used for selective ack/nack), but since it's variable in size,
2316          * we don't want to truncate based on the size of the whole
2317          * rx_ackPacket structure.
2318          */
2319
2320         TCHECK2(bp[0], sizeof(struct rx_ackPacket) - RX_MAXACKS);
2321
2322         rxa = (struct rx_ackPacket *) bp;
2323         bp += (sizeof(struct rx_ackPacket) - RX_MAXACKS);
2324
2325         /*
2326          * Print out a few useful things from the ack packet structure
2327          */
2328
2329         if (vflag > 2)
2330                 printf(" bufspace %d maxskew %d",
2331                        (int) EXTRACT_16BITS(&rxa->bufferSpace),
2332                        (int) EXTRACT_16BITS(&rxa->maxSkew));
2333
2334         firstPacket = EXTRACT_32BITS(&rxa->firstPacket);
2335         printf(" first %d serial %d reason %s",
2336                firstPacket, EXTRACT_32BITS(&rxa->serial),
2337                tok2str(rx_ack_reasons, "#%d", (int) rxa->reason));
2338
2339         /*
2340          * Okay, now we print out the ack array.  The way _this_ works
2341          * is that we start at "first", and step through the ack array.
2342          * If we have a contiguous range of acks/nacks, try to
2343          * collapse them into a range.
2344          *
2345          * If you're really clever, you might have noticed that this
2346          * doesn't seem quite correct.  Specifically, due to structure
2347          * padding, sizeof(struct rx_ackPacket) - RX_MAXACKS won't actually
2348          * yield the start of the ack array (because RX_MAXACKS is 255
2349          * and the structure will likely get padded to a 2 or 4 byte
2350          * boundary).  However, this is the way it's implemented inside
2351          * of AFS - the start of the extra fields are at
2352          * sizeof(struct rx_ackPacket) - RX_MAXACKS + nAcks, which _isn't_
2353          * the exact start of the ack array.  Sigh.  That's why we aren't
2354          * using bp, but instead use rxa->acks[].  But nAcks gets added
2355          * to bp after this, so bp ends up at the right spot.  Go figure.
2356          */
2357
2358         if (rxa->nAcks != 0) {
2359
2360                 TCHECK2(bp[0], rxa->nAcks);
2361
2362                 /*
2363                  * Sigh, this is gross, but it seems to work to collapse
2364                  * ranges correctly.
2365                  */
2366
2367                 for (i = 0, start = last = -2; i < rxa->nAcks; i++)
2368                         if (rxa->acks[i] == RX_ACK_TYPE_ACK) {
2369
2370                                 /*
2371                                  * I figured this deserved _some_ explanation.
2372                                  * First, print "acked" and the packet seq
2373                                  * number if this is the first time we've
2374                                  * seen an acked packet.
2375                                  */
2376
2377                                 if (last == -2) {
2378                                         printf(" acked %d",
2379                                                firstPacket + i);
2380                                         start = i;
2381                                 }
2382
2383                                 /*
2384                                  * Otherwise, if the there is a skip in
2385                                  * the range (such as an nacked packet in
2386                                  * the middle of some acked packets),
2387                                  * then print the current packet number
2388                                  * seperated from the last number by
2389                                  * a comma.
2390                                  */
2391
2392                                 else if (last != i - 1) {
2393                                         printf(",%d", firstPacket + i);
2394                                         start = i;
2395                                 }
2396
2397                                 /*
2398                                  * We always set last to the value of
2399                                  * the last ack we saw.  Conversely, start
2400                                  * is set to the value of the first ack
2401                                  * we saw in a range.
2402                                  */
2403
2404                                 last = i;
2405
2406                                 /*
2407                                  * Okay, this bit a code gets executed when
2408                                  * we hit a nack ... in _this_ case we
2409                                  * want to print out the range of packets
2410                                  * that were acked, so we need to print
2411                                  * the _previous_ packet number seperated
2412                                  * from the first by a dash (-).  Since we
2413                                  * already printed the first packet above,
2414                                  * just print the final packet.  Don't
2415                                  * do this if there will be a single-length
2416                                  * range.
2417                                  */
2418                         } else if (last == i - 1 && start != last)
2419                                 printf("-%d", firstPacket + i - 1);
2420
2421                 /*
2422                  * So, what's going on here?  We ran off the end of the
2423                  * ack list, and if we got a range we need to finish it up.
2424                  * So we need to determine if the last packet in the list
2425                  * was an ack (if so, then last will be set to it) and
2426                  * we need to see if the last range didn't start with the
2427                  * last packet (because if it _did_, then that would mean
2428                  * that the packet number has already been printed and
2429                  * we don't need to print it again).
2430                  */
2431
2432                 if (last == i - 1 && start != last)
2433                         printf("-%d", firstPacket + i - 1);
2434
2435                 /*
2436                  * Same as above, just without comments
2437                  */
2438
2439                 for (i = 0, start = last = -2; i < rxa->nAcks; i++)
2440                         if (rxa->acks[i] == RX_ACK_TYPE_NACK) {
2441                                 if (last == -2) {
2442                                         printf(" nacked %d",
2443                                                firstPacket + i);
2444                                         start = i;
2445                                 } else if (last != i - 1) {
2446                                         printf(",%d", firstPacket + i);
2447                                         start = i;
2448                                 }
2449                                 last = i;
2450                         } else if (last == i - 1 && start != last)
2451                                 printf("-%d", firstPacket + i - 1);
2452
2453                 if (last == i - 1 && start != last)
2454                         printf("-%d", firstPacket + i - 1);
2455
2456                 bp += rxa->nAcks;
2457         }
2458
2459
2460         /*
2461          * These are optional fields; depending on your version of AFS,
2462          * you may or may not see them
2463          */
2464
2465 #define TRUNCRET(n)     if (snapend - bp + 1 <= n) return;
2466
2467         if (vflag > 1) {
2468                 TRUNCRET(4);
2469                 printf(" ifmtu");
2470                 INTOUT();
2471
2472                 TRUNCRET(4);
2473                 printf(" maxmtu");
2474                 INTOUT();
2475
2476                 TRUNCRET(4);
2477                 printf(" rwind");
2478                 INTOUT();
2479
2480                 TRUNCRET(4);
2481                 printf(" maxpackets");
2482                 INTOUT();
2483         }
2484
2485         return;
2486
2487 trunc:
2488         printf(" [|ack]");
2489 }
2490 #undef TRUNCRET