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