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