xref: /freebsd/contrib/tcpdump/print-nfs.c (revision 2ebf6c05136945eb89ae7597c7daaf1e1cfa04e2)
14edb46e9SPaul Traina /*
24edb46e9SPaul Traina  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
34edb46e9SPaul Traina  *	The Regents of the University of California.  All rights reserved.
44edb46e9SPaul Traina  *
54edb46e9SPaul Traina  * Redistribution and use in source and binary forms, with or without
64edb46e9SPaul Traina  * modification, are permitted provided that: (1) source code distributions
74edb46e9SPaul Traina  * retain the above copyright notice and this paragraph in its entirety, (2)
84edb46e9SPaul Traina  * distributions including binary code include the above copyright notice and
94edb46e9SPaul Traina  * this paragraph in its entirety in the documentation or other materials
104edb46e9SPaul Traina  * provided with the distribution, and (3) all advertising materials mentioning
114edb46e9SPaul Traina  * features or use of this software display the following acknowledgement:
124edb46e9SPaul Traina  * ``This product includes software developed by the University of California,
134edb46e9SPaul Traina  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
144edb46e9SPaul Traina  * the University nor the names of its contributors may be used to endorse
154edb46e9SPaul Traina  * or promote products derived from this software without specific prior
164edb46e9SPaul Traina  * written permission.
174edb46e9SPaul Traina  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
184edb46e9SPaul Traina  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
194edb46e9SPaul Traina  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
204edb46e9SPaul Traina  */
214edb46e9SPaul Traina 
224edb46e9SPaul Traina #ifndef lint
232ebf6c05SBill Fenner static const char rcsid[] =
242ebf6c05SBill Fenner     "@(#) $Header: print-nfs.c,v 1.63 96/12/10 23:18:07 leres Exp $ (LBL)";
254edb46e9SPaul Traina #endif
264edb46e9SPaul Traina 
274edb46e9SPaul Traina #include <sys/param.h>
284edb46e9SPaul Traina #include <sys/time.h>
294edb46e9SPaul Traina #include <sys/socket.h>
304edb46e9SPaul Traina 
314edb46e9SPaul Traina #include <net/if.h>
324edb46e9SPaul Traina 
334edb46e9SPaul Traina #include <netinet/in.h>
34ee3e7633SGarrett Wollman #include <net/ethernet.h>
354edb46e9SPaul Traina #include <netinet/in_systm.h>
364edb46e9SPaul Traina #include <netinet/ip.h>
374edb46e9SPaul Traina #include <netinet/ip_var.h>
384edb46e9SPaul Traina 
394edb46e9SPaul Traina #include <rpc/rpc.h>
404edb46e9SPaul Traina 
414edb46e9SPaul Traina #include <ctype.h>
422ebf6c05SBill Fenner #include <pcap.h>
434edb46e9SPaul Traina #include <stdio.h>
444edb46e9SPaul Traina #include <string.h>
454edb46e9SPaul Traina 
464edb46e9SPaul Traina #include "interface.h"
474edb46e9SPaul Traina #include "addrtoname.h"
48647f50c3SDoug Rabson #include "extract.h"			/* must come after interface.h */
494edb46e9SPaul Traina 
50647f50c3SDoug Rabson #include "nfs.h"
514edb46e9SPaul Traina #include "nfsfh.h"
524edb46e9SPaul Traina 
53647f50c3SDoug Rabson static void nfs_printfh(const u_int32_t *, const int);
544edb46e9SPaul Traina static void xid_map_enter(const struct rpc_msg *, const struct ip *);
55647f50c3SDoug Rabson static int32_t xid_map_find(const struct rpc_msg *, const struct ip *, u_int32_t *,
56647f50c3SDoug Rabson 			  u_int32_t *);
57647f50c3SDoug Rabson static void interp_reply(const struct rpc_msg *, u_int32_t, u_int32_t, int);
58647f50c3SDoug Rabson static const u_int32_t *parse_post_op_attr(const u_int32_t *, int);
59647f50c3SDoug Rabson 
602ebf6c05SBill Fenner static int nfserr;		/* true if we error rather than trunc */
612ebf6c05SBill Fenner 
62647f50c3SDoug Rabson /*
63647f50c3SDoug Rabson  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
64647f50c3SDoug Rabson  */
65647f50c3SDoug Rabson u_int32_t nfsv3_procid[NFS_NPROCS] = {
66647f50c3SDoug Rabson 	NFSPROC_NULL,
67647f50c3SDoug Rabson 	NFSPROC_GETATTR,
68647f50c3SDoug Rabson 	NFSPROC_SETATTR,
69647f50c3SDoug Rabson 	NFSPROC_NOOP,
70647f50c3SDoug Rabson 	NFSPROC_LOOKUP,
71647f50c3SDoug Rabson 	NFSPROC_READLINK,
72647f50c3SDoug Rabson 	NFSPROC_READ,
73647f50c3SDoug Rabson 	NFSPROC_NOOP,
74647f50c3SDoug Rabson 	NFSPROC_WRITE,
75647f50c3SDoug Rabson 	NFSPROC_CREATE,
76647f50c3SDoug Rabson 	NFSPROC_REMOVE,
77647f50c3SDoug Rabson 	NFSPROC_RENAME,
78647f50c3SDoug Rabson 	NFSPROC_LINK,
79647f50c3SDoug Rabson 	NFSPROC_SYMLINK,
80647f50c3SDoug Rabson 	NFSPROC_MKDIR,
81647f50c3SDoug Rabson 	NFSPROC_RMDIR,
82647f50c3SDoug Rabson 	NFSPROC_READDIR,
83647f50c3SDoug Rabson 	NFSPROC_FSSTAT,
84647f50c3SDoug Rabson 	NFSPROC_NOOP,
85647f50c3SDoug Rabson 	NFSPROC_NOOP,
86647f50c3SDoug Rabson 	NFSPROC_NOOP,
87647f50c3SDoug Rabson 	NFSPROC_NOOP,
88647f50c3SDoug Rabson 	NFSPROC_NOOP,
89647f50c3SDoug Rabson 	NFSPROC_NOOP,
90647f50c3SDoug Rabson 	NFSPROC_NOOP,
91647f50c3SDoug Rabson 	NFSPROC_NOOP
92647f50c3SDoug Rabson };
93647f50c3SDoug Rabson 
94647f50c3SDoug Rabson const char *nfsv3_writemodes[NFSV3WRITE_NMODES] = {
95647f50c3SDoug Rabson 	"unstable",
96647f50c3SDoug Rabson 	"datasync",
97647f50c3SDoug Rabson 	"filesync"
98647f50c3SDoug Rabson };
99647f50c3SDoug Rabson 
100647f50c3SDoug Rabson static struct tok type2str[] = {
101647f50c3SDoug Rabson 	{ NFNON,	"NON" },
102647f50c3SDoug Rabson 	{ NFREG,	"REG" },
103647f50c3SDoug Rabson 	{ NFDIR,	"DIR" },
104647f50c3SDoug Rabson 	{ NFBLK,	"BLK" },
105647f50c3SDoug Rabson 	{ NFCHR,	"CHR" },
106647f50c3SDoug Rabson 	{ NFLNK,	"LNK" },
107647f50c3SDoug Rabson 	{ NFFIFO,	"FIFO" },
108647f50c3SDoug Rabson 	{ 0,		NULL }
109647f50c3SDoug Rabson };
110647f50c3SDoug Rabson 
111647f50c3SDoug Rabson /*
112647f50c3SDoug Rabson  * Print out a 64-bit integer. This appears to be different on each system,
113647f50c3SDoug Rabson  * try to make the best of it. The integer stored as 2 consecutive XDR
114647f50c3SDoug Rabson  * encoded 32-bit integers, to which a pointer is passed.
115647f50c3SDoug Rabson  *
116647f50c3SDoug Rabson  * Assume that a system that has INT64_FORMAT defined, has a 64-bit
117647f50c3SDoug Rabson  * integer datatype and can print it.
118647f50c3SDoug Rabson  */
119647f50c3SDoug Rabson 
120647f50c3SDoug Rabson #define UNSIGNED 0
121647f50c3SDoug Rabson #define SIGNED   1
122647f50c3SDoug Rabson #define HEX      2
123647f50c3SDoug Rabson 
124647f50c3SDoug Rabson #define   INT64_FORMAT   "%qd"
125647f50c3SDoug Rabson #define U_INT64_FORMAT   "%qu"
126647f50c3SDoug Rabson #define HEX_INT64_FORMAT "%qx"
127647f50c3SDoug Rabson 
128647f50c3SDoug Rabson int print_int64(const u_int32_t *dp, int how)
129647f50c3SDoug Rabson {
130647f50c3SDoug Rabson #ifdef INT64_FORMAT
131647f50c3SDoug Rabson 	u_int64_t res;
132647f50c3SDoug Rabson 
133647f50c3SDoug Rabson 	res = ((u_int64_t)ntohl(dp[0]) << 32) | (u_int64_t)ntohl(dp[1]);
134647f50c3SDoug Rabson 	switch (how) {
135647f50c3SDoug Rabson 	case SIGNED:
136647f50c3SDoug Rabson 		printf(INT64_FORMAT, res);
137647f50c3SDoug Rabson 		break;
138647f50c3SDoug Rabson 	case UNSIGNED:
139647f50c3SDoug Rabson 		printf(U_INT64_FORMAT, res);
140647f50c3SDoug Rabson 		break;
141647f50c3SDoug Rabson 	case HEX:
142647f50c3SDoug Rabson 		printf(HEX_INT64_FORMAT, res);
143647f50c3SDoug Rabson 		break;
144647f50c3SDoug Rabson 	default:
145647f50c3SDoug Rabson 		return (0);
146647f50c3SDoug Rabson 	}
147647f50c3SDoug Rabson #else
148647f50c3SDoug Rabson 	/*
149647f50c3SDoug Rabson 	 * XXX - throw upper 32 bits away.
150647f50c3SDoug Rabson 	 * Could also go for hex: printf("0x%x%x", dp[0], dp[1]);
151647f50c3SDoug Rabson 	 */
152647f50c3SDoug Rabson 	if (how == SIGNED)
153647f50c3SDoug Rabson 		printf("%ld", (int)dp[1]);
154647f50c3SDoug Rabson 	else
155647f50c3SDoug Rabson 		printf("%lu", (unsigned int)dp[1]);
156647f50c3SDoug Rabson #endif
157647f50c3SDoug Rabson 	return 1;
158647f50c3SDoug Rabson }
159647f50c3SDoug Rabson 
160647f50c3SDoug Rabson static const u_int32_t *
161647f50c3SDoug Rabson parse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3)
162647f50c3SDoug Rabson {
163647f50c3SDoug Rabson 	register const u_int32_t *ep = (u_int32_t *)snapend;
164647f50c3SDoug Rabson 
165647f50c3SDoug Rabson 	if (dp + 1 > ep)
1662ebf6c05SBill Fenner 		return (NULL);
167647f50c3SDoug Rabson 	if ((sa3->sa_modeset = ntohl(*dp++))) {
168647f50c3SDoug Rabson 		if (dp + 1 > ep)
1692ebf6c05SBill Fenner 			return (NULL);
170647f50c3SDoug Rabson 		sa3->sa_mode = ntohl(*dp++);
171647f50c3SDoug Rabson 	}
172647f50c3SDoug Rabson 
173647f50c3SDoug Rabson 	if (dp + 1 > ep)
1742ebf6c05SBill Fenner 		return (NULL);
175647f50c3SDoug Rabson 	if ((sa3->sa_uidset = ntohl(*dp++))) {
176647f50c3SDoug Rabson 		if (dp + 1 > ep)
1772ebf6c05SBill Fenner 			return (NULL);
178647f50c3SDoug Rabson 		sa3->sa_uid = ntohl(*dp++);
179647f50c3SDoug Rabson 	}
180647f50c3SDoug Rabson 
181647f50c3SDoug Rabson 	if (dp + 1 > ep)
1822ebf6c05SBill Fenner 		return (NULL);
183647f50c3SDoug Rabson 	if ((sa3->sa_gidset = ntohl(*dp++))) {
184647f50c3SDoug Rabson 		if (dp + 1 > ep)
1852ebf6c05SBill Fenner 			return (NULL);
186647f50c3SDoug Rabson 		sa3->sa_gid = ntohl(*dp++);
187647f50c3SDoug Rabson 	}
188647f50c3SDoug Rabson 
189647f50c3SDoug Rabson 	if (dp + 1 > ep)
1902ebf6c05SBill Fenner 		return (NULL);
191647f50c3SDoug Rabson 	if ((sa3->sa_sizeset = ntohl(*dp++))) {
192647f50c3SDoug Rabson 		if (dp + 1 > ep)
1932ebf6c05SBill Fenner 			return (NULL);
194647f50c3SDoug Rabson 		sa3->sa_size = ntohl(*dp++);
195647f50c3SDoug Rabson 	}
196647f50c3SDoug Rabson 
197647f50c3SDoug Rabson 	if (dp + 1 > ep)
1982ebf6c05SBill Fenner 		return (NULL);
199647f50c3SDoug Rabson 	if ((sa3->sa_atimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) {
200647f50c3SDoug Rabson 		if (dp + 2 > ep)
2012ebf6c05SBill Fenner 			return (NULL);
202647f50c3SDoug Rabson 		sa3->sa_atime.nfsv3_sec = ntohl(*dp++);
203647f50c3SDoug Rabson 		sa3->sa_atime.nfsv3_nsec = ntohl(*dp++);
204647f50c3SDoug Rabson 	}
205647f50c3SDoug Rabson 
206647f50c3SDoug Rabson 	if (dp + 1 > ep)
2072ebf6c05SBill Fenner 		return (NULL);
208647f50c3SDoug Rabson 	if ((sa3->sa_mtimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) {
209647f50c3SDoug Rabson 		if (dp + 2 > ep)
2102ebf6c05SBill Fenner 			return (NULL);
211647f50c3SDoug Rabson 		sa3->sa_mtime.nfsv3_sec = ntohl(*dp++);
212647f50c3SDoug Rabson 		sa3->sa_mtime.nfsv3_nsec = ntohl(*dp++);
213647f50c3SDoug Rabson 	}
214647f50c3SDoug Rabson 
215647f50c3SDoug Rabson 	return dp;
216647f50c3SDoug Rabson }
217647f50c3SDoug Rabson 
218647f50c3SDoug Rabson void
219647f50c3SDoug Rabson print_sattr3(const struct nfsv3_sattr *sa3, int verbose)
220647f50c3SDoug Rabson {
221647f50c3SDoug Rabson 	if (sa3->sa_modeset)
222647f50c3SDoug Rabson 		printf(" mode %o", sa3->sa_mode);
223647f50c3SDoug Rabson 	if (sa3->sa_uidset)
224647f50c3SDoug Rabson 		printf(" uid %u", sa3->sa_uid);
225647f50c3SDoug Rabson 	if (sa3->sa_gidset)
226647f50c3SDoug Rabson 		printf(" gid %u", sa3->sa_gid);
227647f50c3SDoug Rabson 	if (verbose > 1) {
228647f50c3SDoug Rabson 		if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
229647f50c3SDoug Rabson 			printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec,
230647f50c3SDoug Rabson 			       sa3->sa_atime.nfsv3_nsec);
231647f50c3SDoug Rabson 		if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
232647f50c3SDoug Rabson 			printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
233647f50c3SDoug Rabson 			       sa3->sa_mtime.nfsv3_nsec);
234647f50c3SDoug Rabson 	}
235647f50c3SDoug Rabson }
2364edb46e9SPaul Traina 
2374edb46e9SPaul Traina void
2384edb46e9SPaul Traina nfsreply_print(register const u_char *bp, u_int length,
2394edb46e9SPaul Traina 	       register const u_char *bp2)
2404edb46e9SPaul Traina {
2414edb46e9SPaul Traina 	register const struct rpc_msg *rp;
2424edb46e9SPaul Traina 	register const struct ip *ip;
243647f50c3SDoug Rabson 	u_int32_t proc, vers;
2444edb46e9SPaul Traina 
2452ebf6c05SBill Fenner 	nfserr = 0;		/* assume no error */
2464edb46e9SPaul Traina 	rp = (const struct rpc_msg *)bp;
2474edb46e9SPaul Traina 	ip = (const struct ip *)bp2;
2484edb46e9SPaul Traina 
2494edb46e9SPaul Traina 	if (!nflag)
2504edb46e9SPaul Traina 		(void)printf("%s.nfs > %s.%x: reply %s %d",
2514edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_src),
2524edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_dst),
2534edb46e9SPaul Traina 			     (u_int32_t)ntohl(rp->rm_xid),
2544edb46e9SPaul Traina 			     ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED?
2554edb46e9SPaul Traina 				     "ok":"ERR",
2564edb46e9SPaul Traina 			     length);
2574edb46e9SPaul Traina 	else
2584edb46e9SPaul Traina 		(void)printf("%s.%x > %s.%x: reply %s %d",
2594edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_src),
2604edb46e9SPaul Traina 			     NFS_PORT,
2614edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_dst),
2624edb46e9SPaul Traina 			     (u_int32_t)ntohl(rp->rm_xid),
2634edb46e9SPaul Traina 			     ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED?
2644edb46e9SPaul Traina 			     	"ok":"ERR",
2654edb46e9SPaul Traina 			     length);
2664edb46e9SPaul Traina 
267647f50c3SDoug Rabson 	if (xid_map_find(rp, ip, &proc, &vers) >= 0)
268647f50c3SDoug Rabson 		interp_reply(rp, proc, vers, length);
2694edb46e9SPaul Traina }
2704edb46e9SPaul Traina 
2714edb46e9SPaul Traina /*
2724edb46e9SPaul Traina  * Return a pointer to the first file handle in the packet.
2732ebf6c05SBill Fenner  * If the packet was truncated, return NULL.
2744edb46e9SPaul Traina  */
2754edb46e9SPaul Traina static const u_int32_t *
276647f50c3SDoug Rabson parsereq(register const struct rpc_msg *rp, register int length)
2774edb46e9SPaul Traina {
2782ebf6c05SBill Fenner 	register const u_int32_t *dp;
2794edb46e9SPaul Traina 	register u_int len;
2804edb46e9SPaul Traina 
2814edb46e9SPaul Traina 	/*
2824edb46e9SPaul Traina 	 * find the start of the req data (if we captured it)
2834edb46e9SPaul Traina 	 */
2842ebf6c05SBill Fenner 	dp = (u_int32_t *)&rp->rm_call.cb_cred;
2852ebf6c05SBill Fenner 	TCHECK(dp[1]);
2864edb46e9SPaul Traina 	len = ntohl(dp[1]);
2872ebf6c05SBill Fenner 	if (len < length) {
2882ebf6c05SBill Fenner 		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
2892ebf6c05SBill Fenner 		TCHECK(dp[1]);
2904edb46e9SPaul Traina 		len = ntohl(dp[1]);
2912ebf6c05SBill Fenner 		if (len < length) {
2922ebf6c05SBill Fenner 			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
2932ebf6c05SBill Fenner 			TCHECK2(dp[0], 0);
2944edb46e9SPaul Traina 			return (dp);
2954edb46e9SPaul Traina 		}
2964edb46e9SPaul Traina 	}
2972ebf6c05SBill Fenner trunc:
2982ebf6c05SBill Fenner 	return (NULL);
2994edb46e9SPaul Traina }
3004edb46e9SPaul Traina 
3014edb46e9SPaul Traina /*
3024edb46e9SPaul Traina  * Print out an NFS file handle and return a pointer to following word.
3032ebf6c05SBill Fenner  * If packet was truncated, return NULL.
3044edb46e9SPaul Traina  */
3054edb46e9SPaul Traina static const u_int32_t *
306647f50c3SDoug Rabson parsefh(register const u_int32_t *dp, int v3)
3074edb46e9SPaul Traina {
308647f50c3SDoug Rabson 	int len;
309647f50c3SDoug Rabson 
310647f50c3SDoug Rabson 	if (v3) {
3112ebf6c05SBill Fenner 		TCHECK(dp[0]);
312647f50c3SDoug Rabson 		len = (int)ntohl(*dp) / 4;
313647f50c3SDoug Rabson 		dp++;
314647f50c3SDoug Rabson 	} else
315647f50c3SDoug Rabson 		len = NFSX_V2FH / 4;
316647f50c3SDoug Rabson 
3172ebf6c05SBill Fenner 	if (TTEST2(*dp, len * sizeof(*dp))) {
318647f50c3SDoug Rabson 		nfs_printfh(dp, len);
319647f50c3SDoug Rabson 		return (dp + len);
3204edb46e9SPaul Traina 	}
3212ebf6c05SBill Fenner trunc:
3222ebf6c05SBill Fenner 	return (NULL);
3234edb46e9SPaul Traina }
3244edb46e9SPaul Traina 
3254edb46e9SPaul Traina /*
3264edb46e9SPaul Traina  * Print out a file name and return pointer to 32-bit word past it.
3272ebf6c05SBill Fenner  * If packet was truncated, return NULL.
3284edb46e9SPaul Traina  */
3294edb46e9SPaul Traina static const u_int32_t *
3304edb46e9SPaul Traina parsefn(register const u_int32_t *dp)
3314edb46e9SPaul Traina {
3324edb46e9SPaul Traina 	register u_int32_t len;
3334edb46e9SPaul Traina 	register const u_char *cp;
3344edb46e9SPaul Traina 
3354edb46e9SPaul Traina 	/* Bail if we don't have the string length */
3364edb46e9SPaul Traina 	if ((u_char *)dp > snapend - sizeof(*dp))
3372ebf6c05SBill Fenner 		return (NULL);
3384edb46e9SPaul Traina 
3394edb46e9SPaul Traina 	/* Fetch string length; convert to host order */
3404edb46e9SPaul Traina 	len = *dp++;
3414edb46e9SPaul Traina 	NTOHL(len);
3424edb46e9SPaul Traina 
3434edb46e9SPaul Traina 	cp = (u_char *)dp;
3444edb46e9SPaul Traina 	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
3454edb46e9SPaul Traina 	dp += ((len + 3) & ~3) / sizeof(*dp);
3464edb46e9SPaul Traina 	if ((u_char *)dp > snapend)
3472ebf6c05SBill Fenner 		return (NULL);
3484edb46e9SPaul Traina 	/* XXX seems like we should be checking the length */
3492ebf6c05SBill Fenner 	putchar('"');
3504edb46e9SPaul Traina 	(void) fn_printn(cp, len, NULL);
3512ebf6c05SBill Fenner 	putchar('"');
3524edb46e9SPaul Traina 
3534edb46e9SPaul Traina 	return (dp);
3544edb46e9SPaul Traina }
3554edb46e9SPaul Traina 
3564edb46e9SPaul Traina /*
3574edb46e9SPaul Traina  * Print out file handle and file name.
3584edb46e9SPaul Traina  * Return pointer to 32-bit word past file name.
3592ebf6c05SBill Fenner  * If packet was truncated (or there was some other error), return NULL.
3604edb46e9SPaul Traina  */
3614edb46e9SPaul Traina static const u_int32_t *
362647f50c3SDoug Rabson parsefhn(register const u_int32_t *dp, int v3)
3634edb46e9SPaul Traina {
364647f50c3SDoug Rabson 	dp = parsefh(dp, v3);
3652ebf6c05SBill Fenner 	if (dp == NULL)
3662ebf6c05SBill Fenner 		return (NULL);
3674edb46e9SPaul Traina 	putchar(' ');
3684edb46e9SPaul Traina 	return (parsefn(dp));
3694edb46e9SPaul Traina }
3704edb46e9SPaul Traina 
3714edb46e9SPaul Traina void
3724edb46e9SPaul Traina nfsreq_print(register const u_char *bp, u_int length,
3734edb46e9SPaul Traina     register const u_char *bp2)
3744edb46e9SPaul Traina {
3754edb46e9SPaul Traina 	register const struct rpc_msg *rp;
3764edb46e9SPaul Traina 	register const struct ip *ip;
3774edb46e9SPaul Traina 	register const u_int32_t *dp;
378647f50c3SDoug Rabson 	nfstype type;
379647f50c3SDoug Rabson 	int proc, v3;
380647f50c3SDoug Rabson 	struct nfsv3_sattr sa3;
3814edb46e9SPaul Traina 
3822ebf6c05SBill Fenner 	nfserr = 0;		/* assume no error */
3834edb46e9SPaul Traina 	rp = (const struct rpc_msg *)bp;
3844edb46e9SPaul Traina 	ip = (const struct ip *)bp2;
3854edb46e9SPaul Traina 	if (!nflag)
3864edb46e9SPaul Traina 		(void)printf("%s.%x > %s.nfs: %d",
3874edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_src),
3884edb46e9SPaul Traina 			     (u_int32_t)ntohl(rp->rm_xid),
3894edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_dst),
3904edb46e9SPaul Traina 			     length);
3914edb46e9SPaul Traina 	else
3924edb46e9SPaul Traina 		(void)printf("%s.%x > %s.%x: %d",
3934edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_src),
3944edb46e9SPaul Traina 			     (u_int32_t)ntohl(rp->rm_xid),
3954edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_dst),
3964edb46e9SPaul Traina 			     NFS_PORT,
3974edb46e9SPaul Traina 			     length);
3984edb46e9SPaul Traina 
3994edb46e9SPaul Traina 	xid_map_enter(rp, ip);	/* record proc number for later on */
4004edb46e9SPaul Traina 
401647f50c3SDoug Rabson 	v3 = (ntohl(rp->rm_call.cb_vers) == NFS_VER3);
402647f50c3SDoug Rabson 	proc = ntohl(rp->rm_call.cb_proc);
403647f50c3SDoug Rabson 
404647f50c3SDoug Rabson 	if (!v3 && proc < NFS_NPROCS)
405647f50c3SDoug Rabson 		proc =  nfsv3_procid[proc];
406647f50c3SDoug Rabson 
407647f50c3SDoug Rabson 	switch (proc) {
4084edb46e9SPaul Traina 	case NFSPROC_NOOP:
4094edb46e9SPaul Traina 		printf(" nop");
4104edb46e9SPaul Traina 		return;
4114edb46e9SPaul Traina 	case NFSPROC_NULL:
4124edb46e9SPaul Traina 		printf(" null");
4134edb46e9SPaul Traina 		return;
4144edb46e9SPaul Traina 
4154edb46e9SPaul Traina 	case NFSPROC_GETATTR:
4164edb46e9SPaul Traina 		printf(" getattr");
4172ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL)
4184edb46e9SPaul Traina 			return;
4194edb46e9SPaul Traina 		break;
4204edb46e9SPaul Traina 
4214edb46e9SPaul Traina 	case NFSPROC_SETATTR:
4224edb46e9SPaul Traina 		printf(" setattr");
4232ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL)
4244edb46e9SPaul Traina 			return;
4254edb46e9SPaul Traina 		break;
4264edb46e9SPaul Traina 
4274edb46e9SPaul Traina 	case NFSPROC_LOOKUP:
4284edb46e9SPaul Traina 		printf(" lookup");
4292ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL)
4304edb46e9SPaul Traina 			return;
4314edb46e9SPaul Traina 		break;
4324edb46e9SPaul Traina 
433647f50c3SDoug Rabson 	case NFSPROC_ACCESS:
434647f50c3SDoug Rabson 		printf(" access");
4352ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
4362ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
437647f50c3SDoug Rabson 			TCHECK(*dp);
4382ebf6c05SBill Fenner 			printf(" %04lx", ntohl(dp[0]));
439647f50c3SDoug Rabson 			return;
440647f50c3SDoug Rabson 		}
441647f50c3SDoug Rabson 		break;
442647f50c3SDoug Rabson 
4434edb46e9SPaul Traina 	case NFSPROC_READLINK:
4444edb46e9SPaul Traina 		printf(" readlink");
4452ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL)
4464edb46e9SPaul Traina 			return;
4474edb46e9SPaul Traina 		break;
4484edb46e9SPaul Traina 
4494edb46e9SPaul Traina 	case NFSPROC_READ:
4504edb46e9SPaul Traina 		printf(" read");
4512ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
4522ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
453647f50c3SDoug Rabson 			if (v3) {
454647f50c3SDoug Rabson 				TCHECK2(*dp, 3 * sizeof(*dp));
455647f50c3SDoug Rabson 				printf(" %lu bytes @ ", ntohl(dp[2]));
456647f50c3SDoug Rabson 				print_int64(dp, UNSIGNED);
457647f50c3SDoug Rabson 			} else {
458647f50c3SDoug Rabson 				TCHECK2(*dp, 2 * sizeof(*dp));
459647f50c3SDoug Rabson 				printf(" %lu bytes @ %lu",
460647f50c3SDoug Rabson 				       ntohl(dp[1]), ntohl(dp[0]));
461647f50c3SDoug Rabson 			}
4624edb46e9SPaul Traina 			return;
4634edb46e9SPaul Traina 		}
4644edb46e9SPaul Traina 		break;
4654edb46e9SPaul Traina 
4664edb46e9SPaul Traina 	case NFSPROC_WRITE:
4674edb46e9SPaul Traina 		printf(" write");
4682ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
4692ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
470647f50c3SDoug Rabson 			if (v3) {
471647f50c3SDoug Rabson 				TCHECK2(*dp, 3 * sizeof(*dp));
472647f50c3SDoug Rabson 				printf(" %lu bytes @ ", ntohl(dp[4]));
473647f50c3SDoug Rabson 				print_int64(dp, UNSIGNED);
474647f50c3SDoug Rabson 				if (vflag) {
475647f50c3SDoug Rabson 					dp += 3;
476647f50c3SDoug Rabson 					TCHECK2(*dp, sizeof(*dp));
477647f50c3SDoug Rabson 					printf(" <%s>",
478647f50c3SDoug Rabson 					       nfsv3_writemodes[ntohl(*dp)]);
479647f50c3SDoug Rabson 				}
480647f50c3SDoug Rabson 			} else {
481647f50c3SDoug Rabson 				TCHECK2(*dp, 4 * sizeof(*dp));
482647f50c3SDoug Rabson 				printf(" %lu (%lu) bytes @ %lu (%lu)",
483647f50c3SDoug Rabson 				       ntohl(dp[3]), ntohl(dp[2]),
484647f50c3SDoug Rabson 				       ntohl(dp[1]), ntohl(dp[0]));
485647f50c3SDoug Rabson 			}
4864edb46e9SPaul Traina 			return;
4874edb46e9SPaul Traina 		}
4884edb46e9SPaul Traina 		break;
4894edb46e9SPaul Traina 
4904edb46e9SPaul Traina 	case NFSPROC_CREATE:
4914edb46e9SPaul Traina 		printf(" create");
4922ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL)
4934edb46e9SPaul Traina 			return;
4944edb46e9SPaul Traina 		break;
4954edb46e9SPaul Traina 
496647f50c3SDoug Rabson 	case NFSPROC_MKDIR:
497647f50c3SDoug Rabson 		printf(" mkdir");
4982ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL)
499647f50c3SDoug Rabson 			return;
500647f50c3SDoug Rabson 		break;
501647f50c3SDoug Rabson 
502647f50c3SDoug Rabson 	case NFSPROC_SYMLINK:
503647f50c3SDoug Rabson 		printf(" symlink");
5042ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
5052ebf6c05SBill Fenner 		    (dp = parsefhn(dp, v3)) != NULL) {
506647f50c3SDoug Rabson 			fputs(" -> ", stdout);
5072ebf6c05SBill Fenner 			if (v3 && (dp = parse_sattr3(dp, &sa3)) == NULL)
508647f50c3SDoug Rabson 				break;
5092ebf6c05SBill Fenner 			if (parsefn(dp) == NULL)
510647f50c3SDoug Rabson 				break;
511647f50c3SDoug Rabson 			if (v3 && vflag)
512647f50c3SDoug Rabson 				print_sattr3(&sa3, vflag);
513647f50c3SDoug Rabson 			return;
514647f50c3SDoug Rabson 		}
515647f50c3SDoug Rabson 		break;
516647f50c3SDoug Rabson 
517647f50c3SDoug Rabson 	case NFSPROC_MKNOD:
518647f50c3SDoug Rabson 		printf(" mknod");
5192ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
5202ebf6c05SBill Fenner 		    (dp = parsefhn(dp, v3)) != NULL) {
521647f50c3SDoug Rabson 			if (dp + 1 > (u_int32_t *)snapend)
522647f50c3SDoug Rabson 				break;
523647f50c3SDoug Rabson 			type = (nfstype)ntohl(*dp++);
5242ebf6c05SBill Fenner 			if ((dp = parse_sattr3(dp, &sa3)) == NULL)
525647f50c3SDoug Rabson 				break;
526647f50c3SDoug Rabson 			printf(" %s", tok2str(type2str, "unk-ft %d", type));
527647f50c3SDoug Rabson 			if (vflag && (type == NFCHR || type == NFBLK)) {
528647f50c3SDoug Rabson 				if (dp + 2 > (u_int32_t *)snapend)
529647f50c3SDoug Rabson 					break;
5302ebf6c05SBill Fenner 				printf(" %lu/%lu", ntohl(dp[0]), ntohl(dp[1]));
531647f50c3SDoug Rabson 				dp += 2;
532647f50c3SDoug Rabson 			}
533647f50c3SDoug Rabson 			if (vflag)
534647f50c3SDoug Rabson 				print_sattr3(&sa3, vflag);
535647f50c3SDoug Rabson 			return;
536647f50c3SDoug Rabson 		}
537647f50c3SDoug Rabson 		break;
538647f50c3SDoug Rabson 
5394edb46e9SPaul Traina 	case NFSPROC_REMOVE:
5404edb46e9SPaul Traina 		printf(" remove");
5412ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL)
542647f50c3SDoug Rabson 			return;
543647f50c3SDoug Rabson 		break;
544647f50c3SDoug Rabson 
545647f50c3SDoug Rabson 	case NFSPROC_RMDIR:
546647f50c3SDoug Rabson 		printf(" rmdir");
5472ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL)
5484edb46e9SPaul Traina 			return;
5494edb46e9SPaul Traina 		break;
5504edb46e9SPaul Traina 
5514edb46e9SPaul Traina 	case NFSPROC_RENAME:
5524edb46e9SPaul Traina 		printf(" rename");
5532ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
5542ebf6c05SBill Fenner 		    (dp = parsefhn(dp, v3)) != NULL) {
5554edb46e9SPaul Traina 			fputs(" ->", stdout);
5562ebf6c05SBill Fenner 			if (parsefhn(dp, v3) != NULL)
5574edb46e9SPaul Traina 				return;
5584edb46e9SPaul Traina 		}
5594edb46e9SPaul Traina 		break;
5604edb46e9SPaul Traina 
5614edb46e9SPaul Traina 	case NFSPROC_LINK:
5624edb46e9SPaul Traina 		printf(" link");
5632ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
5642ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
5654edb46e9SPaul Traina 			fputs(" ->", stdout);
5662ebf6c05SBill Fenner 			if (parsefhn(dp, v3) != NULL)
5674edb46e9SPaul Traina 				return;
5684edb46e9SPaul Traina 		}
5694edb46e9SPaul Traina 		break;
5704edb46e9SPaul Traina 
5714edb46e9SPaul Traina 	case NFSPROC_READDIR:
5724edb46e9SPaul Traina 		printf(" readdir");
5732ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
5742ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
575647f50c3SDoug Rabson 			if (v3) {
576647f50c3SDoug Rabson 				TCHECK2(*dp, 20);
5774edb46e9SPaul Traina 				/*
578647f50c3SDoug Rabson 				 * We shouldn't really try to interpret the
579647f50c3SDoug Rabson 				 * offset cookie here.
5804edb46e9SPaul Traina 				 */
581647f50c3SDoug Rabson 				printf(" %lu bytes @ ", ntohl(dp[4]));
582647f50c3SDoug Rabson 				print_int64(dp, SIGNED);
583647f50c3SDoug Rabson 				if (vflag)
5842ebf6c05SBill Fenner 					printf(" verf %08x%08x", dp[2],
585647f50c3SDoug Rabson 					       dp[3]);
586647f50c3SDoug Rabson 			} else {
587647f50c3SDoug Rabson 				TCHECK2(*dp, 2 * sizeof(*dp));
588647f50c3SDoug Rabson 				/*
589647f50c3SDoug Rabson 				 * Print the offset as signed, since -1 is
590647f50c3SDoug Rabson 				 * common, but offsets > 2^31 aren't.
591647f50c3SDoug Rabson 				 */
592647f50c3SDoug Rabson 				printf(" %lu bytes @ %ld", ntohl(dp[1]),
593647f50c3SDoug Rabson 				       ntohl(dp[0]));
594647f50c3SDoug Rabson 			}
5954edb46e9SPaul Traina 			return;
5964edb46e9SPaul Traina 		}
5974edb46e9SPaul Traina 		break;
5984edb46e9SPaul Traina 
599647f50c3SDoug Rabson 	case NFSPROC_READDIRPLUS:
600647f50c3SDoug Rabson 		printf(" readdirplus");
6012ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
6022ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
603647f50c3SDoug Rabson 			TCHECK2(*dp, 20);
604647f50c3SDoug Rabson 			/*
605647f50c3SDoug Rabson 			 * We don't try to interpret the offset
606647f50c3SDoug Rabson 			 * cookie here.
607647f50c3SDoug Rabson 			 */
608647f50c3SDoug Rabson 			printf(" %lu bytes @ ", ntohl(dp[4]));
609647f50c3SDoug Rabson 			print_int64(dp, SIGNED);
610647f50c3SDoug Rabson 			if (vflag)
6112ebf6c05SBill Fenner 				printf(" max %lu verf %08x%08x",
612647f50c3SDoug Rabson 				       ntohl(dp[5]), dp[2], dp[3]);
613647f50c3SDoug Rabson 			return;
614647f50c3SDoug Rabson 		}
615647f50c3SDoug Rabson 		break;
616647f50c3SDoug Rabson 
617647f50c3SDoug Rabson 	case NFSPROC_FSSTAT:
618647f50c3SDoug Rabson 		printf(" fsstat");
6192ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL)
6204edb46e9SPaul Traina 			return;
6214edb46e9SPaul Traina 		break;
6224edb46e9SPaul Traina 
623647f50c3SDoug Rabson 	case NFSPROC_FSINFO:
624647f50c3SDoug Rabson 		printf(" fsinfo");
625647f50c3SDoug Rabson 		break;
626647f50c3SDoug Rabson 
627647f50c3SDoug Rabson 	case NFSPROC_PATHCONF:
628647f50c3SDoug Rabson 		printf(" pathconf");
629647f50c3SDoug Rabson 		break;
630647f50c3SDoug Rabson 
631647f50c3SDoug Rabson 	case NFSPROC_COMMIT:
632647f50c3SDoug Rabson 		printf(" commit");
6332ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
6342ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
635647f50c3SDoug Rabson 			printf(" %lu bytes @ ", ntohl(dp[2]));
636647f50c3SDoug Rabson 			print_int64(dp, UNSIGNED);
637647f50c3SDoug Rabson 			return;
638647f50c3SDoug Rabson 		}
639647f50c3SDoug Rabson 		break;
640647f50c3SDoug Rabson 
6414edb46e9SPaul Traina 	default:
642647f50c3SDoug Rabson 		printf(" proc-%lu", ntohl(rp->rm_call.cb_proc));
6434edb46e9SPaul Traina 		return;
6444edb46e9SPaul Traina 	}
6454edb46e9SPaul Traina trunc:
6462ebf6c05SBill Fenner 	if (!nfserr)
6474edb46e9SPaul Traina 		fputs(" [|nfs]", stdout);
6484edb46e9SPaul Traina }
6494edb46e9SPaul Traina 
6504edb46e9SPaul Traina /*
6514edb46e9SPaul Traina  * Print out an NFS file handle.
6524edb46e9SPaul Traina  * We assume packet was not truncated before the end of the
6534edb46e9SPaul Traina  * file handle pointed to by dp.
6544edb46e9SPaul Traina  *
6554edb46e9SPaul Traina  * Note: new version (using portable file-handle parser) doesn't produce
6564edb46e9SPaul Traina  * generation number.  It probably could be made to do that, with some
6574edb46e9SPaul Traina  * additional hacking on the parser code.
6584edb46e9SPaul Traina  */
6594edb46e9SPaul Traina static void
660647f50c3SDoug Rabson nfs_printfh(register const u_int32_t *dp, const int len)
6614edb46e9SPaul Traina {
6624edb46e9SPaul Traina 	my_fsid fsid;
6634edb46e9SPaul Traina 	ino_t ino;
6644edb46e9SPaul Traina 	char *sfsname = NULL;
6654edb46e9SPaul Traina 
666647f50c3SDoug Rabson 	Parse_fh((caddr_t *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
6674edb46e9SPaul Traina 
6684edb46e9SPaul Traina 	if (sfsname) {
6694edb46e9SPaul Traina 		/* file system ID is ASCII, not numeric, for this server OS */
670647f50c3SDoug Rabson 		static char temp[NFSX_V3FHMAX+1];
6714edb46e9SPaul Traina 
6724edb46e9SPaul Traina 		/* Make sure string is null-terminated */
673647f50c3SDoug Rabson 		strncpy(temp, sfsname, NFSX_V3FHMAX);
6744edb46e9SPaul Traina 		/* Remove trailing spaces */
6754edb46e9SPaul Traina 		sfsname = strchr(temp, ' ');
6764edb46e9SPaul Traina 		if (sfsname)
6774edb46e9SPaul Traina 			*sfsname = 0;
6784edb46e9SPaul Traina 
6794edb46e9SPaul Traina 		(void)printf(" fh %s/%u", temp, (u_int32_t)ino);
6802ebf6c05SBill Fenner 	} else {
6814edb46e9SPaul Traina 		(void)printf(" fh %u,%u/%u",
6822ebf6c05SBill Fenner 		    fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor, (u_int32_t)ino);
6834edb46e9SPaul Traina 	}
6844edb46e9SPaul Traina }
6854edb46e9SPaul Traina 
6864edb46e9SPaul Traina /*
6874edb46e9SPaul Traina  * Maintain a small cache of recent client.XID.server/proc pairs, to allow
6884edb46e9SPaul Traina  * us to match up replies with requests and thus to know how to parse
6894edb46e9SPaul Traina  * the reply.
6904edb46e9SPaul Traina  */
6914edb46e9SPaul Traina 
6924edb46e9SPaul Traina struct xid_map_entry {
6934edb46e9SPaul Traina 	u_int32_t		xid;		/* transaction ID (net order) */
6944edb46e9SPaul Traina 	struct in_addr	client;		/* client IP address (net order) */
6954edb46e9SPaul Traina 	struct in_addr	server;		/* server IP address (net order) */
6964edb46e9SPaul Traina 	u_int32_t		proc;		/* call proc number (host order) */
697647f50c3SDoug Rabson 	u_int32_t		vers;		/* program version (host order) */
6984edb46e9SPaul Traina };
6994edb46e9SPaul Traina 
7004edb46e9SPaul Traina /*
7014edb46e9SPaul Traina  * Map entries are kept in an array that we manage as a ring;
7024edb46e9SPaul Traina  * new entries are always added at the tail of the ring.  Initially,
7034edb46e9SPaul Traina  * all the entries are zero and hence don't match anything.
7044edb46e9SPaul Traina  */
7054edb46e9SPaul Traina 
7064edb46e9SPaul Traina #define	XIDMAPSIZE	64
7074edb46e9SPaul Traina 
7084edb46e9SPaul Traina struct xid_map_entry xid_map[XIDMAPSIZE];
7094edb46e9SPaul Traina 
7104edb46e9SPaul Traina int	xid_map_next = 0;
7114edb46e9SPaul Traina int	xid_map_hint = 0;
7124edb46e9SPaul Traina 
7134edb46e9SPaul Traina static void
7144edb46e9SPaul Traina xid_map_enter(const struct rpc_msg *rp, const struct ip *ip)
7154edb46e9SPaul Traina {
7164edb46e9SPaul Traina 	struct xid_map_entry *xmep;
7174edb46e9SPaul Traina 
7184edb46e9SPaul Traina 	xmep = &xid_map[xid_map_next];
7194edb46e9SPaul Traina 
7204edb46e9SPaul Traina 	if (++xid_map_next >= XIDMAPSIZE)
7214edb46e9SPaul Traina 		xid_map_next = 0;
7224edb46e9SPaul Traina 
7234edb46e9SPaul Traina 	xmep->xid = rp->rm_xid;
7244edb46e9SPaul Traina 	xmep->client = ip->ip_src;
7254edb46e9SPaul Traina 	xmep->server = ip->ip_dst;
7264edb46e9SPaul Traina 	xmep->proc = ntohl(rp->rm_call.cb_proc);
727647f50c3SDoug Rabson 	xmep->vers = ntohl(rp->rm_call.cb_vers);
7284edb46e9SPaul Traina }
7294edb46e9SPaul Traina 
7302ebf6c05SBill Fenner /*
7312ebf6c05SBill Fenner  * Returns 0 and puts NFSPROC_xxx in proc return and
7322ebf6c05SBill Fenner  * version in vers return, or returns -1 on failure
7332ebf6c05SBill Fenner  */
734647f50c3SDoug Rabson static int
735647f50c3SDoug Rabson xid_map_find(const struct rpc_msg *rp, const struct ip *ip, u_int32_t *proc,
736647f50c3SDoug Rabson 	     u_int32_t *vers)
7374edb46e9SPaul Traina {
7384edb46e9SPaul Traina 	int i;
7394edb46e9SPaul Traina 	struct xid_map_entry *xmep;
7404edb46e9SPaul Traina 	u_int32_t xid = rp->rm_xid;
7414edb46e9SPaul Traina 	u_int32_t clip = ip->ip_dst.s_addr;
7424edb46e9SPaul Traina 	u_int32_t sip = ip->ip_src.s_addr;
7434edb46e9SPaul Traina 
7444edb46e9SPaul Traina 	/* Start searching from where we last left off */
7454edb46e9SPaul Traina 	i = xid_map_hint;
7464edb46e9SPaul Traina 	do {
7474edb46e9SPaul Traina 		xmep = &xid_map[i];
7484edb46e9SPaul Traina 		if (xmep->xid == xid && xmep->client.s_addr == clip &&
7494edb46e9SPaul Traina 		    xmep->server.s_addr == sip) {
7504edb46e9SPaul Traina 			/* match */
7514edb46e9SPaul Traina 			xid_map_hint = i;
752647f50c3SDoug Rabson 			*proc = xmep->proc;
753647f50c3SDoug Rabson 			*vers = xmep->vers;
754647f50c3SDoug Rabson 			return 0;
7554edb46e9SPaul Traina 		}
7564edb46e9SPaul Traina 		if (++i >= XIDMAPSIZE)
7574edb46e9SPaul Traina 			i = 0;
7584edb46e9SPaul Traina 	} while (i != xid_map_hint);
7594edb46e9SPaul Traina 
7604edb46e9SPaul Traina 	/* search failed */
7614edb46e9SPaul Traina 	return (-1);
7624edb46e9SPaul Traina }
7634edb46e9SPaul Traina 
7644edb46e9SPaul Traina /*
7654edb46e9SPaul Traina  * Routines for parsing reply packets
7664edb46e9SPaul Traina  */
7674edb46e9SPaul Traina 
7684edb46e9SPaul Traina /*
7694edb46e9SPaul Traina  * Return a pointer to the beginning of the actual results.
7702ebf6c05SBill Fenner  * If the packet was truncated, return NULL.
7714edb46e9SPaul Traina  */
7724edb46e9SPaul Traina static const u_int32_t *
773647f50c3SDoug Rabson parserep(register const struct rpc_msg *rp, register int length)
7744edb46e9SPaul Traina {
7754edb46e9SPaul Traina 	register const u_int32_t *dp;
776647f50c3SDoug Rabson 	int len;
7774edb46e9SPaul Traina 	enum accept_stat astat;
7784edb46e9SPaul Traina 
7794edb46e9SPaul Traina 	/*
7804edb46e9SPaul Traina 	 * Portability note:
7814edb46e9SPaul Traina 	 * Here we find the address of the ar_verf credentials.
7824edb46e9SPaul Traina 	 * Originally, this calculation was
7834edb46e9SPaul Traina 	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
7844edb46e9SPaul Traina 	 * On the wire, the rp_acpt field starts immediately after
7854edb46e9SPaul Traina 	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
7864edb46e9SPaul Traina 	 * "struct accepted_reply") contains a "struct opaque_auth",
7874edb46e9SPaul Traina 	 * whose internal representation contains a pointer, so on a
7884edb46e9SPaul Traina 	 * 64-bit machine the compiler inserts 32 bits of padding
7894edb46e9SPaul Traina 	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
7904edb46e9SPaul Traina 	 * the internal representation to parse the on-the-wire
7914edb46e9SPaul Traina 	 * representation.  Instead, we skip past the rp_stat field,
7924edb46e9SPaul Traina 	 * which is an "enum" and so occupies one 32-bit word.
7934edb46e9SPaul Traina 	 */
7944edb46e9SPaul Traina 	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
7952ebf6c05SBill Fenner 	TCHECK2(dp[0], 1);
7964edb46e9SPaul Traina 	len = ntohl(dp[1]);
7974edb46e9SPaul Traina 	if (len >= length)
7982ebf6c05SBill Fenner 		return (NULL);
7994edb46e9SPaul Traina 	/*
8004edb46e9SPaul Traina 	 * skip past the ar_verf credentials.
8014edb46e9SPaul Traina 	 */
8024edb46e9SPaul Traina 	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
8032ebf6c05SBill Fenner 	TCHECK2(dp[0], 0);
8044edb46e9SPaul Traina 
8054edb46e9SPaul Traina 	/*
8064edb46e9SPaul Traina 	 * now we can check the ar_stat field
8074edb46e9SPaul Traina 	 */
8084edb46e9SPaul Traina 	astat = ntohl(*(enum accept_stat *)dp);
8094edb46e9SPaul Traina 	switch (astat) {
8104edb46e9SPaul Traina 
8114edb46e9SPaul Traina 	case SUCCESS:
8124edb46e9SPaul Traina 		break;
8134edb46e9SPaul Traina 
8144edb46e9SPaul Traina 	case PROG_UNAVAIL:
8154edb46e9SPaul Traina 		printf(" PROG_UNAVAIL");
8162ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
8172ebf6c05SBill Fenner 		return (NULL);
8184edb46e9SPaul Traina 
8194edb46e9SPaul Traina 	case PROG_MISMATCH:
8204edb46e9SPaul Traina 		printf(" PROG_MISMATCH");
8212ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
8222ebf6c05SBill Fenner 		return (NULL);
8234edb46e9SPaul Traina 
8244edb46e9SPaul Traina 	case PROC_UNAVAIL:
8254edb46e9SPaul Traina 		printf(" PROC_UNAVAIL");
8262ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
8272ebf6c05SBill Fenner 		return (NULL);
8284edb46e9SPaul Traina 
8294edb46e9SPaul Traina 	case GARBAGE_ARGS:
8304edb46e9SPaul Traina 		printf(" GARBAGE_ARGS");
8312ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
8322ebf6c05SBill Fenner 		return (NULL);
8334edb46e9SPaul Traina 
8344edb46e9SPaul Traina 	case SYSTEM_ERR:
8354edb46e9SPaul Traina 		printf(" SYSTEM_ERR");
8362ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
8372ebf6c05SBill Fenner 		return (NULL);
8384edb46e9SPaul Traina 
8394edb46e9SPaul Traina 	default:
8404edb46e9SPaul Traina 		printf(" ar_stat %d", astat);
8412ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
8422ebf6c05SBill Fenner 		return (NULL);
8434edb46e9SPaul Traina 	}
8444edb46e9SPaul Traina 	/* successful return */
8452ebf6c05SBill Fenner 	if ((sizeof(astat) + ((u_char *)dp)) < snapend)
8464edb46e9SPaul Traina 		return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
8474edb46e9SPaul Traina 
8482ebf6c05SBill Fenner trunc:
8492ebf6c05SBill Fenner 	return (NULL);
8504edb46e9SPaul Traina }
8514edb46e9SPaul Traina 
8524edb46e9SPaul Traina 
8532ebf6c05SBill Fenner #define T2CHECK(p, l) if ((u_char *)(p) > ((u_char *)snapend) - l) return(NULL)
854647f50c3SDoug Rabson 
855647f50c3SDoug Rabson static const u_int32_t *
856647f50c3SDoug Rabson parsestatus(const u_int32_t *dp, int *er)
857647f50c3SDoug Rabson {
8582ebf6c05SBill Fenner 	register int errnum;
859647f50c3SDoug Rabson 
8602ebf6c05SBill Fenner 	TCHECK(dp[0]);
8612ebf6c05SBill Fenner 	errnum = ntohl(dp[0]);
862647f50c3SDoug Rabson 	if (er)
8632ebf6c05SBill Fenner 		*er = errnum;
8642ebf6c05SBill Fenner 	if (errnum != 0) {
8652ebf6c05SBill Fenner 		if (!qflag)
8662ebf6c05SBill Fenner 			printf(" ERROR: %s", pcap_strerror(errnum));
8672ebf6c05SBill Fenner 		nfserr = 1;
8682ebf6c05SBill Fenner 		return (NULL);
8694edb46e9SPaul Traina 	}
8704edb46e9SPaul Traina 	return (dp + 1);
8712ebf6c05SBill Fenner trunc:
8722ebf6c05SBill Fenner 	return (NULL);
8734edb46e9SPaul Traina }
8744edb46e9SPaul Traina 
8754edb46e9SPaul Traina static const u_int32_t *
876647f50c3SDoug Rabson parsefattr(const u_int32_t *dp, int verbose, int v3)
8774edb46e9SPaul Traina {
878647f50c3SDoug Rabson 	const struct nfs_fattr *fap;
8794edb46e9SPaul Traina 
880647f50c3SDoug Rabson 	T2CHECK(dp,  5 * sizeof(*dp));
881647f50c3SDoug Rabson 
882647f50c3SDoug Rabson 	fap = (const struct nfs_fattr *)dp;
8834edb46e9SPaul Traina 	if (verbose) {
8842ebf6c05SBill Fenner 		printf(" %s %lo ids %ld/%ld",
885647f50c3SDoug Rabson 		    tok2str(type2str, "unk-ft %d ", ntohl(fap->fa_type)),
886647f50c3SDoug Rabson 		       ntohl(fap->fa_mode), ntohl(fap->fa_uid),
887647f50c3SDoug Rabson 		       ntohl(fap->fa_gid));
888647f50c3SDoug Rabson 		if (v3) {
889647f50c3SDoug Rabson 			T2CHECK(dp,  7 * sizeof(*dp));
890647f50c3SDoug Rabson 			printf(" sz ");
891647f50c3SDoug Rabson 			print_int64((u_int32_t *)&fap->fa3_size, UNSIGNED);
892647f50c3SDoug Rabson 			putchar(' ');
893647f50c3SDoug Rabson 		}
894647f50c3SDoug Rabson 		else {
895647f50c3SDoug Rabson 			T2CHECK(dp,  6 * sizeof(*dp));
8962ebf6c05SBill Fenner 			printf(" sz %ld ", ntohl(fap->fa2_size));
897647f50c3SDoug Rabson 		}
8984edb46e9SPaul Traina 	}
8994edb46e9SPaul Traina 	/* print lots more stuff */
9004edb46e9SPaul Traina 	if (verbose > 1) {
901647f50c3SDoug Rabson 		if (v3) {
902647f50c3SDoug Rabson 			T2CHECK(dp, 64);
9032ebf6c05SBill Fenner 			printf("nlink %ld rdev %ld/%ld ",
904647f50c3SDoug Rabson 			       ntohl(fap->fa_nlink),
905647f50c3SDoug Rabson 			       ntohl(fap->fa3_rdev.specdata1),
906647f50c3SDoug Rabson 			       ntohl(fap->fa3_rdev.specdata2));
907647f50c3SDoug Rabson 			printf("fsid ");
908647f50c3SDoug Rabson 			print_int64((u_int32_t *)&fap->fa2_fsid, HEX);
909647f50c3SDoug Rabson 			printf(" nodeid ");
910647f50c3SDoug Rabson 			print_int64((u_int32_t *)&fap->fa2_fileid, HEX);
9112ebf6c05SBill Fenner 			printf(" a/m/ctime %lu.%06lu ",
912647f50c3SDoug Rabson 			       ntohl(fap->fa3_atime.nfsv3_sec),
913647f50c3SDoug Rabson 			       ntohl(fap->fa3_atime.nfsv3_nsec));
9142ebf6c05SBill Fenner 			printf("%lu.%06lu ",
915647f50c3SDoug Rabson 			       ntohl(fap->fa3_mtime.nfsv3_sec),
916647f50c3SDoug Rabson 			       ntohl(fap->fa3_mtime.nfsv3_nsec));
9172ebf6c05SBill Fenner 			printf("%lu.%06lu ",
918647f50c3SDoug Rabson 			       ntohl(fap->fa3_ctime.nfsv3_sec),
919647f50c3SDoug Rabson 			       ntohl(fap->fa3_ctime.nfsv3_nsec));
920647f50c3SDoug Rabson 		} else {
921647f50c3SDoug Rabson 			T2CHECK(dp, 48);
9222ebf6c05SBill Fenner 			printf("nlink %ld rdev %lx fsid %lx nodeid %lx a/m/ctime ",
923647f50c3SDoug Rabson 			       ntohl(fap->fa_nlink), ntohl(fap->fa2_rdev),
924647f50c3SDoug Rabson 			       ntohl(fap->fa2_fsid), ntohl(fap->fa2_fileid));
9252ebf6c05SBill Fenner 			printf("%lu.%06lu ",
926647f50c3SDoug Rabson 			       ntohl(fap->fa2_atime.nfsv2_sec),
927647f50c3SDoug Rabson 			       ntohl(fap->fa2_atime.nfsv2_usec));
9282ebf6c05SBill Fenner 			printf("%lu.%06lu ",
929647f50c3SDoug Rabson 			       ntohl(fap->fa2_mtime.nfsv2_sec),
930647f50c3SDoug Rabson 			       ntohl(fap->fa2_mtime.nfsv2_usec));
9312ebf6c05SBill Fenner 			printf("%lu.%06lu ",
932647f50c3SDoug Rabson 			       ntohl(fap->fa2_ctime.nfsv2_sec),
933647f50c3SDoug Rabson 			       ntohl(fap->fa2_ctime.nfsv2_usec));
9344edb46e9SPaul Traina 		}
935647f50c3SDoug Rabson 	}
936647f50c3SDoug Rabson 	return ((const u_int32_t *)((unsigned char *)dp +
937647f50c3SDoug Rabson 		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
9384edb46e9SPaul Traina }
9394edb46e9SPaul Traina 
9404edb46e9SPaul Traina static int
941647f50c3SDoug Rabson parseattrstat(const u_int32_t *dp, int verbose, int v3)
9424edb46e9SPaul Traina {
943647f50c3SDoug Rabson 	int er;
944647f50c3SDoug Rabson 
945647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
946647f50c3SDoug Rabson 	if (dp == NULL || er)
9474edb46e9SPaul Traina 		return (0);
9484edb46e9SPaul Traina 
9492ebf6c05SBill Fenner 	return (parsefattr(dp, verbose, v3) != NULL);
9504edb46e9SPaul Traina }
9514edb46e9SPaul Traina 
9524edb46e9SPaul Traina static int
9534edb46e9SPaul Traina parsediropres(const u_int32_t *dp)
9544edb46e9SPaul Traina {
955647f50c3SDoug Rabson 	int er;
956647f50c3SDoug Rabson 
9572ebf6c05SBill Fenner 	dp = parsestatus(dp, &er);
9582ebf6c05SBill Fenner 	if (dp == NULL || er)
959647f50c3SDoug Rabson 		return (0);
960647f50c3SDoug Rabson 
961647f50c3SDoug Rabson 	dp = parsefh(dp, 0);
9624edb46e9SPaul Traina 	if (dp == NULL)
9634edb46e9SPaul Traina 		return (0);
9644edb46e9SPaul Traina 
965647f50c3SDoug Rabson 	return (parsefattr(dp, vflag, 0) != NULL);
9664edb46e9SPaul Traina }
9674edb46e9SPaul Traina 
9684edb46e9SPaul Traina static int
969647f50c3SDoug Rabson parselinkres(const u_int32_t *dp, int v3)
9704edb46e9SPaul Traina {
971647f50c3SDoug Rabson 	int er;
9724edb46e9SPaul Traina 
973647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
974647f50c3SDoug Rabson 	if (dp == NULL || er)
975647f50c3SDoug Rabson 		return(0);
9762ebf6c05SBill Fenner 
9772ebf6c05SBill Fenner 	if (v3 && ((dp = parse_post_op_attr(dp, vflag)) != NULL))
978647f50c3SDoug Rabson 		return (0);
9792ebf6c05SBill Fenner 
9804edb46e9SPaul Traina 	putchar(' ');
9814edb46e9SPaul Traina 	return (parsefn(dp) != NULL);
9824edb46e9SPaul Traina }
9834edb46e9SPaul Traina 
9844edb46e9SPaul Traina static int
985647f50c3SDoug Rabson parsestatfs(const u_int32_t *dp, int v3)
9864edb46e9SPaul Traina {
987647f50c3SDoug Rabson 	const struct nfs_statfs *sfsp;
988647f50c3SDoug Rabson 	int er;
9894edb46e9SPaul Traina 
990647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
991647f50c3SDoug Rabson 	if (dp == NULL || (!v3 && er))
9924edb46e9SPaul Traina 		return(0);
9934edb46e9SPaul Traina 
994647f50c3SDoug Rabson 	if (qflag)
995647f50c3SDoug Rabson 		return(1);
996647f50c3SDoug Rabson 
997647f50c3SDoug Rabson 	if (v3) {
998647f50c3SDoug Rabson 		if (vflag)
999647f50c3SDoug Rabson 			printf(" POST:");
10002ebf6c05SBill Fenner 		if ((dp = parse_post_op_attr(dp, vflag)) == NULL)
1001647f50c3SDoug Rabson 			return (0);
1002647f50c3SDoug Rabson 	}
1003647f50c3SDoug Rabson 
1004647f50c3SDoug Rabson 	T2CHECK(dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
1005647f50c3SDoug Rabson 
1006647f50c3SDoug Rabson 	sfsp = (const struct nfs_statfs *)dp;
1007647f50c3SDoug Rabson 
1008647f50c3SDoug Rabson 	if (v3) {
1009647f50c3SDoug Rabson 		printf(" tbytes ");
1010647f50c3SDoug Rabson 		print_int64((u_int32_t *)&sfsp->sf_tbytes, UNSIGNED);
1011647f50c3SDoug Rabson 		printf(" fbytes ");
1012647f50c3SDoug Rabson 		print_int64((u_int32_t *)&sfsp->sf_fbytes, UNSIGNED);
1013647f50c3SDoug Rabson 		printf(" abytes ");
1014647f50c3SDoug Rabson 		print_int64((u_int32_t *)&sfsp->sf_abytes, UNSIGNED);
1015647f50c3SDoug Rabson 		if (vflag) {
1016647f50c3SDoug Rabson 			printf(" tfiles ");
1017647f50c3SDoug Rabson 			print_int64((u_int32_t *)&sfsp->sf_tfiles, UNSIGNED);
1018647f50c3SDoug Rabson 			printf(" ffiles ");
1019647f50c3SDoug Rabson 			print_int64((u_int32_t *)&sfsp->sf_ffiles, UNSIGNED);
1020647f50c3SDoug Rabson 			printf(" afiles ");
1021647f50c3SDoug Rabson 			print_int64((u_int32_t *)&sfsp->sf_afiles, UNSIGNED);
1022647f50c3SDoug Rabson 			printf(" invar %lu", ntohl(sfsp->sf_invarsec));
1023647f50c3SDoug Rabson 		}
1024647f50c3SDoug Rabson 	} else {
10252ebf6c05SBill Fenner 		printf(" tsize %ld bsize %ld blocks %ld bfree %ld bavail %ld",
1026647f50c3SDoug Rabson 		       ntohl(sfsp->sf_tsize), ntohl(sfsp->sf_bsize),
1027647f50c3SDoug Rabson 		       ntohl(sfsp->sf_blocks), ntohl(sfsp->sf_bfree),
1028647f50c3SDoug Rabson 		       ntohl(sfsp->sf_bavail));
10294edb46e9SPaul Traina 	}
10304edb46e9SPaul Traina 
10314edb46e9SPaul Traina 	return (1);
10324edb46e9SPaul Traina }
10334edb46e9SPaul Traina 
10344edb46e9SPaul Traina static int
10354edb46e9SPaul Traina parserddires(const u_int32_t *dp)
10364edb46e9SPaul Traina {
1037647f50c3SDoug Rabson 	int er;
1038647f50c3SDoug Rabson 
1039647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
10402ebf6c05SBill Fenner 	if (dp == NULL || er)
10414edb46e9SPaul Traina 		return (0);
1042647f50c3SDoug Rabson 	if (qflag)
1043647f50c3SDoug Rabson 		return (1);
1044647f50c3SDoug Rabson 
1045647f50c3SDoug Rabson 	T2CHECK(dp, 12);
10462ebf6c05SBill Fenner 	printf(" offset %lx size %ld ", ntohl(dp[0]), ntohl(dp[1]));
10474edb46e9SPaul Traina 	if (dp[2] != 0)
10484edb46e9SPaul Traina 		printf("eof");
10494edb46e9SPaul Traina 
10504edb46e9SPaul Traina 	return (1);
1051647f50c3SDoug Rabson }
1052647f50c3SDoug Rabson 
1053647f50c3SDoug Rabson static const u_int32_t *
1054647f50c3SDoug Rabson parse_wcc_attr(const u_int32_t *dp)
1055647f50c3SDoug Rabson {
1056647f50c3SDoug Rabson 	printf(" sz ");
1057647f50c3SDoug Rabson 	print_int64(dp, UNSIGNED);
10582ebf6c05SBill Fenner 	printf(" mtime %lu.%06lu ctime %lu.%06lu", ntohl(dp[2]), ntohl(dp[3]),
1059647f50c3SDoug Rabson 	       ntohl(dp[4]), ntohl(dp[5]));
1060647f50c3SDoug Rabson 	return (dp + 6);
1061647f50c3SDoug Rabson }
1062647f50c3SDoug Rabson 
1063647f50c3SDoug Rabson /*
1064647f50c3SDoug Rabson  * Pre operation attributes. Print only if vflag > 1.
1065647f50c3SDoug Rabson  */
1066647f50c3SDoug Rabson static const u_int32_t *
1067647f50c3SDoug Rabson parse_pre_op_attr(const u_int32_t *dp, int verbose)
1068647f50c3SDoug Rabson {
1069647f50c3SDoug Rabson 	T2CHECK(dp, 4);
1070647f50c3SDoug Rabson 	if (!ntohl(dp[0]))
1071647f50c3SDoug Rabson 		return (dp + 1);
1072647f50c3SDoug Rabson 	dp++;
1073647f50c3SDoug Rabson 	T2CHECK(dp, 24);
1074647f50c3SDoug Rabson 	if (verbose > 1) {
1075647f50c3SDoug Rabson 		return parse_wcc_attr(dp);
1076647f50c3SDoug Rabson 	} else {
1077647f50c3SDoug Rabson 		/* If not verbose enough, just skip over wcc_attr */
1078647f50c3SDoug Rabson 		return (dp + 6);
1079647f50c3SDoug Rabson 	}
1080647f50c3SDoug Rabson }
1081647f50c3SDoug Rabson 
1082647f50c3SDoug Rabson /*
1083647f50c3SDoug Rabson  * Post operation attributes are printed if vflag >= 1
1084647f50c3SDoug Rabson  */
1085647f50c3SDoug Rabson static const u_int32_t *
1086647f50c3SDoug Rabson parse_post_op_attr(const u_int32_t *dp, int verbose)
1087647f50c3SDoug Rabson {
1088647f50c3SDoug Rabson 	T2CHECK(dp, 4);
1089647f50c3SDoug Rabson 	if (!ntohl(dp[0]))
1090647f50c3SDoug Rabson 		return (dp + 1);
1091647f50c3SDoug Rabson 	dp++;
1092647f50c3SDoug Rabson 	if (verbose) {
1093647f50c3SDoug Rabson 		return parsefattr(dp, verbose, 1);
1094647f50c3SDoug Rabson 	} else
1095647f50c3SDoug Rabson 		return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
1096647f50c3SDoug Rabson }
1097647f50c3SDoug Rabson 
1098647f50c3SDoug Rabson static const u_int32_t *
1099647f50c3SDoug Rabson parse_wcc_data(const u_int32_t *dp, int verbose)
1100647f50c3SDoug Rabson {
1101647f50c3SDoug Rabson 	if (verbose > 1)
1102647f50c3SDoug Rabson 		printf(" PRE:");
11032ebf6c05SBill Fenner 	if ((dp = parse_pre_op_attr(dp, verbose)) == NULL)
11042ebf6c05SBill Fenner 		return (NULL);
1105647f50c3SDoug Rabson 
1106647f50c3SDoug Rabson 	if (verbose)
1107647f50c3SDoug Rabson 		printf(" POST:");
1108647f50c3SDoug Rabson 	return parse_post_op_attr(dp, verbose);
1109647f50c3SDoug Rabson }
1110647f50c3SDoug Rabson 
1111647f50c3SDoug Rabson static const u_int32_t *
1112647f50c3SDoug Rabson parsecreateopres(const u_int32_t *dp, int verbose)
1113647f50c3SDoug Rabson {
1114647f50c3SDoug Rabson 	int er;
1115647f50c3SDoug Rabson 
11162ebf6c05SBill Fenner 	if ((dp = parsestatus(dp, &er)) == NULL)
11172ebf6c05SBill Fenner 		return (NULL);
1118647f50c3SDoug Rabson 	if (er)
1119647f50c3SDoug Rabson 		dp = parse_wcc_data(dp, verbose);
1120647f50c3SDoug Rabson 	else {
1121647f50c3SDoug Rabson 		T2CHECK(dp, 4);
1122647f50c3SDoug Rabson 		if (!ntohl(dp[0]))
1123647f50c3SDoug Rabson 			return (dp + 1);
1124647f50c3SDoug Rabson 		dp++;
11252ebf6c05SBill Fenner 		if ((dp = parsefh(dp, 1)) == NULL)
11262ebf6c05SBill Fenner 			return (NULL);
1127647f50c3SDoug Rabson 		if (verbose) {
11282ebf6c05SBill Fenner 			if ((dp = parse_post_op_attr(dp, verbose)) == NULL)
11292ebf6c05SBill Fenner 				return (NULL);
1130647f50c3SDoug Rabson 			if (vflag > 1) {
1131647f50c3SDoug Rabson 				printf("dir attr:");
1132647f50c3SDoug Rabson 				dp = parse_wcc_data(dp, verbose);
1133647f50c3SDoug Rabson 			}
1134647f50c3SDoug Rabson 		}
1135647f50c3SDoug Rabson 	}
1136647f50c3SDoug Rabson 	return (dp);
1137647f50c3SDoug Rabson }
1138647f50c3SDoug Rabson 
1139647f50c3SDoug Rabson static int
1140647f50c3SDoug Rabson parsewccres(const u_int32_t *dp, int verbose)
1141647f50c3SDoug Rabson {
1142647f50c3SDoug Rabson 	int er;
1143647f50c3SDoug Rabson 
11442ebf6c05SBill Fenner 	if ((dp = parsestatus(dp, &er)) == NULL)
1145647f50c3SDoug Rabson 		return (0);
11462ebf6c05SBill Fenner 	return parse_wcc_data(dp, verbose) != NULL;
1147647f50c3SDoug Rabson }
1148647f50c3SDoug Rabson 
1149647f50c3SDoug Rabson static const u_int32_t *
1150647f50c3SDoug Rabson parsev3rddirres(const u_int32_t *dp, int verbose)
1151647f50c3SDoug Rabson {
1152647f50c3SDoug Rabson 	int er;
1153647f50c3SDoug Rabson 
11542ebf6c05SBill Fenner 	if ((dp = parsestatus(dp, &er)) == NULL)
11552ebf6c05SBill Fenner 		return (NULL);
1156647f50c3SDoug Rabson 	if (vflag)
1157647f50c3SDoug Rabson 		printf(" POST:");
11582ebf6c05SBill Fenner 	if ((dp = parse_post_op_attr(dp, verbose)) == NULL)
11592ebf6c05SBill Fenner 		return (NULL);
1160647f50c3SDoug Rabson 	if (er)
1161647f50c3SDoug Rabson 		return dp;
1162647f50c3SDoug Rabson 	if (vflag) {
1163647f50c3SDoug Rabson 		T2CHECK(dp, 8);
11642ebf6c05SBill Fenner 		printf(" verf %08x%08x", dp[0], dp[1]);
1165647f50c3SDoug Rabson 		dp += 2;
1166647f50c3SDoug Rabson 	}
1167647f50c3SDoug Rabson 	return dp;
1168647f50c3SDoug Rabson }
1169647f50c3SDoug Rabson 
1170647f50c3SDoug Rabson static int
1171647f50c3SDoug Rabson parsefsinfo(const u_int32_t *dp)
1172647f50c3SDoug Rabson {
1173647f50c3SDoug Rabson 	struct nfsv3_fsinfo *sfp;
1174647f50c3SDoug Rabson 	int er;
1175647f50c3SDoug Rabson 
11762ebf6c05SBill Fenner 	if ((dp = parsestatus(dp, &er)) == NULL)
1177647f50c3SDoug Rabson 		return (0);
1178647f50c3SDoug Rabson 	if (vflag)
1179647f50c3SDoug Rabson 		printf(" POST:");
11802ebf6c05SBill Fenner 	if ((dp = parse_post_op_attr(dp, vflag)) == NULL)
1181647f50c3SDoug Rabson 		return (0);
1182647f50c3SDoug Rabson 	if (er)
1183647f50c3SDoug Rabson 		return (1);
1184647f50c3SDoug Rabson 
1185647f50c3SDoug Rabson 	T2CHECK(dp, sizeof (struct nfsv3_fsinfo));
1186647f50c3SDoug Rabson 
1187647f50c3SDoug Rabson 	sfp = (struct nfsv3_fsinfo *)dp;
1188647f50c3SDoug Rabson 	printf(" rtmax %lu rtpref %lu wtmax %lu wtpref %lu dtpref %lu",
1189647f50c3SDoug Rabson 	       ntohl(sfp->fs_rtmax), ntohl(sfp->fs_rtpref),
1190647f50c3SDoug Rabson 	       ntohl(sfp->fs_wtmax), ntohl(sfp->fs_wtpref),
1191647f50c3SDoug Rabson 	       ntohl(sfp->fs_dtpref));
1192647f50c3SDoug Rabson 	if (vflag) {
1193647f50c3SDoug Rabson 		printf(" rtmult %lu wtmult %lu maxfsz ",
1194647f50c3SDoug Rabson 		       ntohl(sfp->fs_rtmult), ntohl(sfp->fs_wtmult));
1195647f50c3SDoug Rabson 		print_int64((u_int32_t *)&sfp->fs_maxfilesize, UNSIGNED);
11962ebf6c05SBill Fenner 		printf(" delta %lu.%06lu ", ntohl(sfp->fs_timedelta.nfsv3_sec),
1197647f50c3SDoug Rabson 		       ntohl(sfp->fs_timedelta.nfsv3_nsec));
1198647f50c3SDoug Rabson 	}
1199647f50c3SDoug Rabson 	return (1);
1200647f50c3SDoug Rabson }
1201647f50c3SDoug Rabson 
1202647f50c3SDoug Rabson static int
1203647f50c3SDoug Rabson parsepathconf(const u_int32_t *dp)
1204647f50c3SDoug Rabson {
1205647f50c3SDoug Rabson 	int er;
1206647f50c3SDoug Rabson 	struct nfsv3_pathconf *spp;
1207647f50c3SDoug Rabson 
12082ebf6c05SBill Fenner 	if ((dp = parsestatus(dp, &er)) == NULL)
1209647f50c3SDoug Rabson 		return (0);
1210647f50c3SDoug Rabson 	if (vflag)
1211647f50c3SDoug Rabson 		printf(" POST:");
12122ebf6c05SBill Fenner 	if ((dp = parse_post_op_attr(dp, vflag)) == NULL)
1213647f50c3SDoug Rabson 		return (0);
1214647f50c3SDoug Rabson 	if (er)
1215647f50c3SDoug Rabson 		return (1);
1216647f50c3SDoug Rabson 
1217647f50c3SDoug Rabson 	T2CHECK(dp, sizeof (struct nfsv3_pathconf));
1218647f50c3SDoug Rabson 
1219647f50c3SDoug Rabson 	spp = (struct nfsv3_pathconf *)dp;
1220647f50c3SDoug Rabson 
1221647f50c3SDoug Rabson 	printf(" linkmax %lu namemax %lu %s %s %s %s",
1222647f50c3SDoug Rabson 	       ntohl(spp->pc_linkmax),
1223647f50c3SDoug Rabson 	       ntohl(spp->pc_namemax),
1224647f50c3SDoug Rabson 	       ntohl(spp->pc_notrunc) ? "notrunc" : "",
1225647f50c3SDoug Rabson 	       ntohl(spp->pc_chownrestricted) ? "chownres" : "",
1226647f50c3SDoug Rabson 	       ntohl(spp->pc_caseinsensitive) ? "igncase" : "",
1227647f50c3SDoug Rabson 	       ntohl(spp->pc_casepreserving) ? "keepcase" : "");
12284edb46e9SPaul Traina 	return (0);
12294edb46e9SPaul Traina }
12304edb46e9SPaul Traina 
12314edb46e9SPaul Traina static void
1232647f50c3SDoug Rabson interp_reply(const struct rpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
12334edb46e9SPaul Traina {
12344edb46e9SPaul Traina 	register const u_int32_t *dp;
1235647f50c3SDoug Rabson 	register int v3;
12362ebf6c05SBill Fenner 
1237647f50c3SDoug Rabson 	int er;
1238647f50c3SDoug Rabson 
1239647f50c3SDoug Rabson 	v3 = (vers == NFS_VER3);
1240647f50c3SDoug Rabson 
1241647f50c3SDoug Rabson 	if (!v3 && proc < NFS_NPROCS)
1242647f50c3SDoug Rabson 		proc = nfsv3_procid[proc];
12434edb46e9SPaul Traina 
12444edb46e9SPaul Traina 	switch (proc) {
12454edb46e9SPaul Traina 
12464edb46e9SPaul Traina 	case NFSPROC_NOOP:
12474edb46e9SPaul Traina 		printf(" nop");
12484edb46e9SPaul Traina 		return;
1249647f50c3SDoug Rabson 
12504edb46e9SPaul Traina 	case NFSPROC_NULL:
12514edb46e9SPaul Traina 		printf(" null");
12524edb46e9SPaul Traina 		return;
12534edb46e9SPaul Traina 
12544edb46e9SPaul Traina 	case NFSPROC_GETATTR:
12554edb46e9SPaul Traina 		printf(" getattr");
12564edb46e9SPaul Traina 		dp = parserep(rp, length);
12572ebf6c05SBill Fenner 		if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
12584edb46e9SPaul Traina 			return;
12594edb46e9SPaul Traina 		break;
12604edb46e9SPaul Traina 
12614edb46e9SPaul Traina 	case NFSPROC_SETATTR:
12624edb46e9SPaul Traina 		printf(" setattr");
12632ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
12644edb46e9SPaul Traina 			return;
1265647f50c3SDoug Rabson 		if (v3) {
12662ebf6c05SBill Fenner 			if (parsewccres(dp, vflag) != 0)
1267647f50c3SDoug Rabson 				return;
1268647f50c3SDoug Rabson 		} else {
1269647f50c3SDoug Rabson 			if (parseattrstat(dp, !qflag, 0) != 0)
1270647f50c3SDoug Rabson 				return;
1271647f50c3SDoug Rabson 		}
12724edb46e9SPaul Traina 		break;
12734edb46e9SPaul Traina 
12744edb46e9SPaul Traina 	case NFSPROC_LOOKUP:
12754edb46e9SPaul Traina 		printf(" lookup");
12762ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
12774edb46e9SPaul Traina 			break;
1278647f50c3SDoug Rabson 		if (v3) {
12792ebf6c05SBill Fenner 			if ((dp = parsestatus(dp, &er)) == NULL)
1280647f50c3SDoug Rabson 				break;
1281647f50c3SDoug Rabson 			if (er) {
1282647f50c3SDoug Rabson 				if (vflag > 1) {
1283647f50c3SDoug Rabson 					printf(" post dattr:");
1284647f50c3SDoug Rabson 					dp = parse_post_op_attr(dp, vflag);
1285647f50c3SDoug Rabson 				}
1286647f50c3SDoug Rabson 			} else {
12872ebf6c05SBill Fenner 				if ((dp = parsefh(dp, v3)) == NULL)
1288647f50c3SDoug Rabson 					break;
12892ebf6c05SBill Fenner 				if (((dp = parse_post_op_attr(dp, vflag)) != NULL) &&
12902ebf6c05SBill Fenner 				    (vflag > 1)) {
1291647f50c3SDoug Rabson 					printf(" post dattr:");
1292647f50c3SDoug Rabson 					dp = parse_post_op_attr(dp, vflag);
1293647f50c3SDoug Rabson 				}
1294647f50c3SDoug Rabson 			}
12952ebf6c05SBill Fenner 			if (dp != NULL)
1296647f50c3SDoug Rabson 				return;
1297647f50c3SDoug Rabson 		} else {
1298647f50c3SDoug Rabson 			if (parsediropres(dp) != 0)
1299647f50c3SDoug Rabson 				return;
1300647f50c3SDoug Rabson 		}
1301647f50c3SDoug Rabson 		break;
1302647f50c3SDoug Rabson 
1303647f50c3SDoug Rabson 	case NFSPROC_ACCESS:
1304647f50c3SDoug Rabson 		printf(" access");
1305647f50c3SDoug Rabson 		dp = parserep(rp, length);
13062ebf6c05SBill Fenner 		if ((dp = parsestatus(dp, &er)) == NULL)
1307647f50c3SDoug Rabson 			break;
1308647f50c3SDoug Rabson 		if (vflag)
1309647f50c3SDoug Rabson 			printf(" attr:");
13102ebf6c05SBill Fenner 		if ((dp = parse_post_op_attr(dp, vflag)) == NULL)
1311647f50c3SDoug Rabson 			break;
1312647f50c3SDoug Rabson 		if (!er)
13132ebf6c05SBill Fenner 			printf(" c %04lx", ntohl(dp[0]));
1314647f50c3SDoug Rabson 		return;
13154edb46e9SPaul Traina 
13164edb46e9SPaul Traina 	case NFSPROC_READLINK:
13174edb46e9SPaul Traina 		printf(" readlink");
13184edb46e9SPaul Traina 		dp = parserep(rp, length);
13192ebf6c05SBill Fenner 		if (dp != NULL && parselinkres(dp, v3) != 0)
13204edb46e9SPaul Traina 			return;
13214edb46e9SPaul Traina 		break;
13224edb46e9SPaul Traina 
13234edb46e9SPaul Traina 	case NFSPROC_READ:
13244edb46e9SPaul Traina 		printf(" read");
13252ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1326647f50c3SDoug Rabson 			break;
1327647f50c3SDoug Rabson 		if (v3) {
13282ebf6c05SBill Fenner 			if ((dp = parsestatus(dp, &er)) == NULL)
1329647f50c3SDoug Rabson 				break;
13302ebf6c05SBill Fenner 			if ((dp = parse_post_op_attr(dp, vflag)) == NULL)
1331647f50c3SDoug Rabson 				break;
1332647f50c3SDoug Rabson 			if (er)
13334edb46e9SPaul Traina 				return;
1334647f50c3SDoug Rabson 			if (vflag) {
1335647f50c3SDoug Rabson 				TCHECK2(*dp, 8);
1336647f50c3SDoug Rabson 				printf("%lu bytes", ntohl(dp[0]));
1337647f50c3SDoug Rabson 				if (ntohl(dp[1]))
1338647f50c3SDoug Rabson 					printf(" EOF");
1339647f50c3SDoug Rabson 			}
1340647f50c3SDoug Rabson 			return;
1341647f50c3SDoug Rabson 		} else {
1342647f50c3SDoug Rabson 			if (parseattrstat(dp, vflag, 0) != 0)
1343647f50c3SDoug Rabson 				return;
1344647f50c3SDoug Rabson 		}
13454edb46e9SPaul Traina 		break;
13464edb46e9SPaul Traina 
13474edb46e9SPaul Traina 	case NFSPROC_WRITE:
13484edb46e9SPaul Traina 		printf(" write");
13492ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1350647f50c3SDoug Rabson 			break;
1351647f50c3SDoug Rabson 		if (v3) {
13522ebf6c05SBill Fenner 			if ((dp = parsestatus(dp, &er)) == NULL)
1353647f50c3SDoug Rabson 				break;
13542ebf6c05SBill Fenner 			if ((dp = parse_wcc_data(dp, vflag)) == NULL)
1355647f50c3SDoug Rabson 				break;
1356647f50c3SDoug Rabson 			if (er)
13574edb46e9SPaul Traina 				return;
1358647f50c3SDoug Rabson 			if (vflag) {
1359647f50c3SDoug Rabson 				TCHECK2(*dp, 4);
1360647f50c3SDoug Rabson 				printf("%lu bytes", ntohl(dp[0]));
1361647f50c3SDoug Rabson 				if (vflag > 1) {
1362647f50c3SDoug Rabson 					TCHECK2(*dp, 4);
1363647f50c3SDoug Rabson 					printf(" <%s>",
1364647f50c3SDoug Rabson 					       nfsv3_writemodes[ntohl(dp[1])]);
1365647f50c3SDoug Rabson 				}
1366647f50c3SDoug Rabson 				return;
1367647f50c3SDoug Rabson 			}
1368647f50c3SDoug Rabson 		} else {
1369647f50c3SDoug Rabson 			if (parseattrstat(dp, vflag, v3) != 0)
1370647f50c3SDoug Rabson 				return;
1371647f50c3SDoug Rabson 		}
13724edb46e9SPaul Traina 		break;
13734edb46e9SPaul Traina 
13744edb46e9SPaul Traina 	case NFSPROC_CREATE:
13754edb46e9SPaul Traina 		printf(" create");
13762ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1377647f50c3SDoug Rabson 			break;
1378647f50c3SDoug Rabson 		if (v3) {
13792ebf6c05SBill Fenner 			if (parsecreateopres(dp, vflag) != NULL)
1380647f50c3SDoug Rabson 				return;
1381647f50c3SDoug Rabson 		} else {
1382647f50c3SDoug Rabson 			if (parsediropres(dp) != 0)
1383647f50c3SDoug Rabson 				return;
1384647f50c3SDoug Rabson 		}
1385647f50c3SDoug Rabson 		break;
1386647f50c3SDoug Rabson 
1387647f50c3SDoug Rabson 	case NFSPROC_MKDIR:
1388647f50c3SDoug Rabson 		printf(" mkdir");
13892ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1390647f50c3SDoug Rabson 			break;
1391647f50c3SDoug Rabson 		if (v3) {
13922ebf6c05SBill Fenner 			if (parsecreateopres(dp, vflag) != NULL)
1393647f50c3SDoug Rabson 				return;
1394647f50c3SDoug Rabson 		} else {
1395647f50c3SDoug Rabson 			if (parsediropres(dp) != 0)
1396647f50c3SDoug Rabson 				return;
1397647f50c3SDoug Rabson 		}
1398647f50c3SDoug Rabson 		break;
1399647f50c3SDoug Rabson 
1400647f50c3SDoug Rabson 	case NFSPROC_SYMLINK:
1401647f50c3SDoug Rabson 		printf(" symlink");
14022ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1403647f50c3SDoug Rabson 			break;
1404647f50c3SDoug Rabson 		if (v3) {
14052ebf6c05SBill Fenner 			if (parsecreateopres(dp, vflag) != NULL)
1406647f50c3SDoug Rabson 				return;
1407647f50c3SDoug Rabson 		} else {
14082ebf6c05SBill Fenner 			if (parsestatus(dp, &er) != NULL)
1409647f50c3SDoug Rabson 				return;
1410647f50c3SDoug Rabson 		}
1411647f50c3SDoug Rabson 		break;
1412647f50c3SDoug Rabson 
1413647f50c3SDoug Rabson 	case NFSPROC_MKNOD:
1414647f50c3SDoug Rabson 		printf(" mknod");
14152ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1416647f50c3SDoug Rabson 			break;
14172ebf6c05SBill Fenner 		if (parsecreateopres(dp, vflag) != NULL)
14184edb46e9SPaul Traina 			return;
14194edb46e9SPaul Traina 		break;
14204edb46e9SPaul Traina 
14214edb46e9SPaul Traina 	case NFSPROC_REMOVE:
14224edb46e9SPaul Traina 		printf(" remove");
14232ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
14244edb46e9SPaul Traina 			break;
1425647f50c3SDoug Rabson 		if (v3) {
14262ebf6c05SBill Fenner 			if (parsewccres(dp, vflag) != 0)
14274edb46e9SPaul Traina 				return;
1428647f50c3SDoug Rabson 		} else {
14292ebf6c05SBill Fenner 			if (parsestatus(dp, &er) != NULL)
14304edb46e9SPaul Traina 				return;
1431647f50c3SDoug Rabson 		}
14324edb46e9SPaul Traina 		break;
14334edb46e9SPaul Traina 
14344edb46e9SPaul Traina 	case NFSPROC_RMDIR:
14354edb46e9SPaul Traina 		printf(" rmdir");
14362ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1437647f50c3SDoug Rabson 			break;
1438647f50c3SDoug Rabson 		if (v3) {
14392ebf6c05SBill Fenner 			if (parsewccres(dp, vflag) != 0)
14404edb46e9SPaul Traina 				return;
1441647f50c3SDoug Rabson 		} else {
14422ebf6c05SBill Fenner 			if (parsestatus(dp, &er) != NULL)
1443647f50c3SDoug Rabson 				return;
1444647f50c3SDoug Rabson 		}
1445647f50c3SDoug Rabson 		break;
1446647f50c3SDoug Rabson 
1447647f50c3SDoug Rabson 	case NFSPROC_RENAME:
1448647f50c3SDoug Rabson 		printf(" rename");
14492ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1450647f50c3SDoug Rabson 			break;
1451647f50c3SDoug Rabson 		if (v3) {
14522ebf6c05SBill Fenner 			if ((dp = parsestatus(dp, &er)) == NULL)
1453647f50c3SDoug Rabson 				break;
1454647f50c3SDoug Rabson 			if (vflag) {
1455647f50c3SDoug Rabson 				printf(" from:");
14562ebf6c05SBill Fenner 				if ((dp = parse_wcc_data(dp, vflag)) == NULL)
1457647f50c3SDoug Rabson 					break;
1458647f50c3SDoug Rabson 				printf(" to:");
14592ebf6c05SBill Fenner 				if ((dp = parse_wcc_data(dp, vflag)) == NULL)
1460647f50c3SDoug Rabson 					break;
1461647f50c3SDoug Rabson 			}
1462647f50c3SDoug Rabson 			return;
1463647f50c3SDoug Rabson 		} else {
14642ebf6c05SBill Fenner 			if (parsestatus(dp, &er) != NULL)
1465647f50c3SDoug Rabson 				return;
1466647f50c3SDoug Rabson 		}
1467647f50c3SDoug Rabson 		break;
1468647f50c3SDoug Rabson 
1469647f50c3SDoug Rabson 	case NFSPROC_LINK:
1470647f50c3SDoug Rabson 		printf(" link");
14712ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1472647f50c3SDoug Rabson 			break;
1473647f50c3SDoug Rabson 		if (v3) {
14742ebf6c05SBill Fenner 			if ((dp = parsestatus(dp, &er)) == NULL)
1475647f50c3SDoug Rabson 				break;
1476647f50c3SDoug Rabson 			if (vflag) {
1477647f50c3SDoug Rabson 				printf(" file POST:");
14782ebf6c05SBill Fenner 				if ((dp = parse_post_op_attr(dp, vflag)) == NULL)
1479647f50c3SDoug Rabson 					break;
1480647f50c3SDoug Rabson 				printf(" dir:");
14812ebf6c05SBill Fenner 				if ((dp = parse_wcc_data(dp, vflag)) == NULL)
1482647f50c3SDoug Rabson 					break;
1483647f50c3SDoug Rabson 				return;
1484647f50c3SDoug Rabson 			}
1485647f50c3SDoug Rabson 		} else {
14862ebf6c05SBill Fenner 			if (parsestatus(dp, &er) != NULL)
1487647f50c3SDoug Rabson 				return;
1488647f50c3SDoug Rabson 		}
14894edb46e9SPaul Traina 		break;
14904edb46e9SPaul Traina 
14914edb46e9SPaul Traina 	case NFSPROC_READDIR:
14924edb46e9SPaul Traina 		printf(" readdir");
14932ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1494647f50c3SDoug Rabson 			break;
1495647f50c3SDoug Rabson 		if (v3) {
14962ebf6c05SBill Fenner 			if (parsev3rddirres(dp, vflag) != NULL)
1497647f50c3SDoug Rabson 				return;
1498647f50c3SDoug Rabson 		} else {
1499647f50c3SDoug Rabson 			if (parserddires(dp) != 0)
1500647f50c3SDoug Rabson 				return;
1501647f50c3SDoug Rabson 		}
1502647f50c3SDoug Rabson 		break;
1503647f50c3SDoug Rabson 
1504647f50c3SDoug Rabson 	case NFSPROC_READDIRPLUS:
1505647f50c3SDoug Rabson 		printf(" readdirplus");
15062ebf6c05SBill Fenner 		if ((dp = parserep(rp, length)) == NULL)
1507647f50c3SDoug Rabson 			break;
15082ebf6c05SBill Fenner 		if (parsev3rddirres(dp, vflag) != NULL)
15094edb46e9SPaul Traina 			return;
15104edb46e9SPaul Traina 		break;
15114edb46e9SPaul Traina 
1512647f50c3SDoug Rabson 	case NFSPROC_FSSTAT:
1513647f50c3SDoug Rabson 		printf(" fsstat");
15144edb46e9SPaul Traina 		dp = parserep(rp, length);
15152ebf6c05SBill Fenner 		if (dp != NULL && parsestatfs(dp, v3) != NULL)
1516647f50c3SDoug Rabson 			return;
1517647f50c3SDoug Rabson 		break;
1518647f50c3SDoug Rabson 
1519647f50c3SDoug Rabson 	case NFSPROC_FSINFO:
1520647f50c3SDoug Rabson 		printf(" fsinfo");
1521647f50c3SDoug Rabson 		dp = parserep(rp, length);
15222ebf6c05SBill Fenner 		if (dp != NULL && parsefsinfo(dp) != NULL)
1523647f50c3SDoug Rabson 			return;
1524647f50c3SDoug Rabson 		break;
1525647f50c3SDoug Rabson 
1526647f50c3SDoug Rabson 	case NFSPROC_PATHCONF:
1527647f50c3SDoug Rabson 		printf(" pathconf");
1528647f50c3SDoug Rabson 		dp = parserep(rp, length);
15292ebf6c05SBill Fenner 		if (dp != NULL && parsepathconf(dp) != 0)
1530647f50c3SDoug Rabson 			return;
1531647f50c3SDoug Rabson 		break;
1532647f50c3SDoug Rabson 
1533647f50c3SDoug Rabson 	case NFSPROC_COMMIT:
1534647f50c3SDoug Rabson 		printf(" commit");
1535647f50c3SDoug Rabson 		dp = parserep(rp, length);
15362ebf6c05SBill Fenner 		if (dp != NULL && parsewccres(dp, vflag) != 0)
15374edb46e9SPaul Traina 			return;
15384edb46e9SPaul Traina 		break;
15394edb46e9SPaul Traina 
15404edb46e9SPaul Traina 	default:
15412ebf6c05SBill Fenner 		printf(" proc-%u", proc);
15424edb46e9SPaul Traina 		return;
15434edb46e9SPaul Traina 	}
1544647f50c3SDoug Rabson 
1545647f50c3SDoug Rabson trunc:
15462ebf6c05SBill Fenner 	if (!nfserr)
15474edb46e9SPaul Traina 		fputs(" [|nfs]", stdout);
15484edb46e9SPaul Traina }
1549