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