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