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