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