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
38static 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$");
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
62static 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
76static 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
90static 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
135static 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
157static 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
184static 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
222static 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
244static 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
280static 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
321static 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
352static struct tok cb_types[] = {
353	{ 1,		"exclusive" },
354	{ 2,		"shared" },
355	{ 3,		"dropped" },
356	{ 0,		NULL },
357};
358
359static struct tok ubik_lock_types[] = {
360	{ 1,		"read" },
361	{ 2,		"write" },
362	{ 3,		"wait" },
363	{ 0,		NULL },
364};
365
366static const char *voltype[] = { "read-write", "read-only", "backup" };
367
368static 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
389static 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
407struct 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
418static struct rx_cache_entry	rx_cache[RX_CACHE_SIZE];
419
420static int	rx_cache_next = 0;
421static int	rx_cache_hint = 0;
422static void	rx_cache_insert(const u_char *, const struct ip *, int);
423static int	rx_cache_find(const struct rx_header *, const struct ip *,
424			      int, int32_t *);
425
426static void fs_print(const u_char *, int);
427static void fs_reply_print(const u_char *, int, int32_t);
428static void acl_print(u_char *, int, u_char *);
429static void cb_print(const u_char *, int);
430static void cb_reply_print(const u_char *, int, int32_t);
431static void prot_print(const u_char *, int);
432static void prot_reply_print(const u_char *, int, int32_t);
433static void vldb_print(const u_char *, int);
434static void vldb_reply_print(const u_char *, int, int32_t);
435static void kauth_print(const u_char *, int);
436static void kauth_reply_print(const u_char *, int, int32_t);
437static void vol_print(const u_char *, int);
438static void vol_reply_print(const u_char *, int, int32_t);
439static void bos_print(const u_char *, int);
440static void bos_reply_print(const u_char *, int, int32_t);
441static void ubik_print(const u_char *);
442static void ubik_reply_print(const u_char *, int, int32_t);
443
444static void rx_ack_print(const u_char *, int);
445
446static 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
453void
454rx_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
606static void
607rx_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
635static int
636rx_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
808static void
809fs_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
972trunc:
973	printf(" [|fs]");
974}
975
976/*
977 * Handle replies to the AFS file service
978 */
979
980static void
981fs_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
1051trunc:
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
1069static void
1070acl_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
1136finish:
1137	free(user);
1138	return;
1139}
1140
1141#undef ACLOUT
1142
1143/*
1144 * Handle calls to the AFS callback service
1145 */
1146
1147static void
1148cb_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
1221trunc:
1222	printf(" [|cb]");
1223}
1224
1225/*
1226 * Handle replies to the AFS Callback Service
1227 */
1228
1229static void
1230cb_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
1270trunc:
1271	printf(" [|cb]");
1272}
1273
1274/*
1275 * Handle calls to the AFS protection database server
1276 */
1277
1278static void
1279prot_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
1413trunc:
1414	printf(" [|pt]");
1415}
1416
1417/*
1418 * Handle replies to the AFS protection service
1419 */
1420
1421static void
1422prot_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
1525trunc:
1526	printf(" [|pt]");
1527}
1528
1529/*
1530 * Handle calls to the AFS volume location database service
1531 */
1532
1533static void
1534vldb_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
1618trunc:
1619	printf(" [|vldb]");
1620}
1621
1622/*
1623 * Handle replies to the AFS volume location database service
1624 */
1625
1626static void
1627vldb_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
1805trunc:
1806	printf(" [|vldb]");
1807}
1808
1809/*
1810 * Handle calls to the AFS Kerberos Authentication service
1811 */
1812
1813static void
1814kauth_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
1898trunc:
1899	printf(" [|kauth]");
1900}
1901
1902/*
1903 * Handle replies to the AFS Kerberos Authentication Service
1904 */
1905
1906static void
1907kauth_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
1949trunc:
1950	printf(" [|kauth]");
1951}
1952
1953/*
1954 * Handle calls to the AFS Volume location service
1955 */
1956
1957static void
1958vol_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
2150trunc:
2151	printf(" [|vol]");
2152}
2153
2154/*
2155 * Handle replies to the AFS Volume Service
2156 */
2157
2158static void
2159vol_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
2284trunc:
2285	printf(" [|vol]");
2286}
2287
2288/*
2289 * Handle calls to the AFS BOS service
2290 */
2291
2292static void
2293bos_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
2375trunc:
2376	printf(" [|bos]");
2377}
2378
2379/*
2380 * Handle replies to the AFS BOS Service
2381 */
2382
2383static void
2384bos_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
2419trunc:
2420	printf(" [|bos]");
2421}
2422
2423/*
2424 * Check to see if this is a Ubik opcode.
2425 */
2426
2427static int
2428is_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
2441static void
2442ubik_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
2542trunc:
2543	printf(" [|ubik]");
2544}
2545
2546/*
2547 * Handle Ubik replies to any one of the replicated database services
2548 */
2549
2550static void
2551ubik_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
2605trunc:
2606	printf(" [|ubik]");
2607}
2608
2609/*
2610 * Handle RX ACK packets.
2611 */
2612
2613static void
2614rx_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
2800trunc:
2801	printf(" [|ack]");
2802}
2803#undef TRUNCRET
2804