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