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