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