print-nfs.c revision 172686
117680Spst/*
239300Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2075118Sfenner *
2175118Sfenner * $FreeBSD: head/contrib/tcpdump/print-nfs.c 172686 2007-10-16 02:31:48Z mlaier $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26172686Smlaier    "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.106.2.4 2007/06/15 23:17:40 guy Exp $ (LBL)";
2717680Spst#endif
2817680Spst
2975118Sfenner#ifdef HAVE_CONFIG_H
3075118Sfenner#include "config.h"
3175118Sfenner#endif
3275118Sfenner
33127675Sbms#include <tcpdump-stdinc.h>
3417680Spst
3526183Sfenner#include <pcap.h>
3617680Spst#include <stdio.h>
3717680Spst#include <string.h>
3817680Spst
3917680Spst#include "interface.h"
4017680Spst#include "addrtoname.h"
41127675Sbms#include "extract.h"
4217680Spst
4318976Sdfr#include "nfs.h"
4417680Spst#include "nfsfh.h"
4517680Spst
4675118Sfenner#include "ip.h"
4775118Sfenner#ifdef INET6
4875118Sfenner#include "ip6.h"
4975118Sfenner#endif
50146778Ssam#include "rpc_auth.h"
51146778Ssam#include "rpc_msg.h"
5275118Sfenner
5375118Sfennerstatic void nfs_printfh(const u_int32_t *, const u_int);
54146778Ssamstatic void xid_map_enter(const struct sunrpc_msg *, const u_char *);
55146778Ssamstatic int32_t xid_map_find(const struct sunrpc_msg *, const u_char *,
5675118Sfenner			    u_int32_t *, u_int32_t *);
57146778Ssamstatic void interp_reply(const struct sunrpc_msg *, u_int32_t, u_int32_t, int);
5818976Sdfrstatic const u_int32_t *parse_post_op_attr(const u_int32_t *, int);
5975118Sfennerstatic void print_sattr3(const struct nfsv3_sattr *sa3, int verbose);
6075118Sfennerstatic void print_nfsaddr(const u_char *, const char *, const char *);
6117680Spst
6218976Sdfr/*
6318976Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
6418976Sdfr */
6518976Sdfru_int32_t nfsv3_procid[NFS_NPROCS] = {
6618976Sdfr	NFSPROC_NULL,
6718976Sdfr	NFSPROC_GETATTR,
6818976Sdfr	NFSPROC_SETATTR,
6918976Sdfr	NFSPROC_NOOP,
7018976Sdfr	NFSPROC_LOOKUP,
7118976Sdfr	NFSPROC_READLINK,
7218976Sdfr	NFSPROC_READ,
7318976Sdfr	NFSPROC_NOOP,
7418976Sdfr	NFSPROC_WRITE,
7518976Sdfr	NFSPROC_CREATE,
7618976Sdfr	NFSPROC_REMOVE,
7718976Sdfr	NFSPROC_RENAME,
7818976Sdfr	NFSPROC_LINK,
7918976Sdfr	NFSPROC_SYMLINK,
8018976Sdfr	NFSPROC_MKDIR,
8118976Sdfr	NFSPROC_RMDIR,
8218976Sdfr	NFSPROC_READDIR,
8318976Sdfr	NFSPROC_FSSTAT,
8418976Sdfr	NFSPROC_NOOP,
8518976Sdfr	NFSPROC_NOOP,
8618976Sdfr	NFSPROC_NOOP,
8718976Sdfr	NFSPROC_NOOP,
8818976Sdfr	NFSPROC_NOOP,
8918976Sdfr	NFSPROC_NOOP,
9018976Sdfr	NFSPROC_NOOP,
9118976Sdfr	NFSPROC_NOOP
9218976Sdfr};
9318976Sdfr
9475118Sfenner/*
9575118Sfenner * NFS V2 and V3 status values.
9675118Sfenner *
9775118Sfenner * Some of these come from the RFCs for NFS V2 and V3, with the message
9875118Sfenner * strings taken from the FreeBSD C library "errlst.c".
9975118Sfenner *
10075118Sfenner * Others are errors that are not in the RFC but that I suspect some
10175118Sfenner * NFS servers could return; the values are FreeBSD errno values, as
10275118Sfenner * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
10375118Sfenner * was primarily BSD-derived.
10475118Sfenner */
10575118Sfennerstatic struct tok status2str[] = {
10675118Sfenner	{ 1,     "Operation not permitted" },	/* EPERM */
10775118Sfenner	{ 2,     "No such file or directory" },	/* ENOENT */
10875118Sfenner	{ 5,     "Input/output error" },	/* EIO */
10975118Sfenner	{ 6,     "Device not configured" },	/* ENXIO */
11075118Sfenner	{ 11,    "Resource deadlock avoided" },	/* EDEADLK */
11175118Sfenner	{ 12,    "Cannot allocate memory" },	/* ENOMEM */
11275118Sfenner	{ 13,    "Permission denied" },		/* EACCES */
11375118Sfenner	{ 17,    "File exists" },		/* EEXIST */
11475118Sfenner	{ 18,    "Cross-device link" },		/* EXDEV */
11575118Sfenner	{ 19,    "Operation not supported by device" }, /* ENODEV */
11675118Sfenner	{ 20,    "Not a directory" },		/* ENOTDIR */
11775118Sfenner	{ 21,    "Is a directory" },		/* EISDIR */
11875118Sfenner	{ 22,    "Invalid argument" },		/* EINVAL */
11975118Sfenner	{ 26,    "Text file busy" },		/* ETXTBSY */
12075118Sfenner	{ 27,    "File too large" },		/* EFBIG */
12175118Sfenner	{ 28,    "No space left on device" },	/* ENOSPC */
12275118Sfenner	{ 30,    "Read-only file system" },	/* EROFS */
12375118Sfenner	{ 31,    "Too many links" },		/* EMLINK */
12475118Sfenner	{ 45,    "Operation not supported" },	/* EOPNOTSUPP */
12575118Sfenner	{ 62,    "Too many levels of symbolic links" }, /* ELOOP */
12675118Sfenner	{ 63,    "File name too long" },	/* ENAMETOOLONG */
12775118Sfenner	{ 66,    "Directory not empty" },	/* ENOTEMPTY */
12875118Sfenner	{ 69,    "Disc quota exceeded" },	/* EDQUOT */
12975118Sfenner	{ 70,    "Stale NFS file handle" },	/* ESTALE */
13075118Sfenner	{ 71,    "Too many levels of remote in path" }, /* EREMOTE */
13175118Sfenner	{ 99,    "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
13275118Sfenner	{ 10001, "Illegal NFS file handle" },	/* NFS3ERR_BADHANDLE */
13375118Sfenner	{ 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
13475118Sfenner	{ 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
13575118Sfenner	{ 10004, "Operation not supported" },	/* NFS3ERR_NOTSUPP */
13675118Sfenner	{ 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
13775118Sfenner	{ 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
13875118Sfenner	{ 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
13975118Sfenner	{ 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
14075118Sfenner	{ 0,     NULL }
14118976Sdfr};
14218976Sdfr
14375118Sfennerstatic struct tok nfsv3_writemodes[] = {
14475118Sfenner	{ 0,		"unstable" },
14575118Sfenner	{ 1,		"datasync" },
14675118Sfenner	{ 2,		"filesync" },
14775118Sfenner	{ 0,		NULL }
14875118Sfenner};
14975118Sfenner
15018976Sdfrstatic struct tok type2str[] = {
15118976Sdfr	{ NFNON,	"NON" },
15218976Sdfr	{ NFREG,	"REG" },
15318976Sdfr	{ NFDIR,	"DIR" },
15418976Sdfr	{ NFBLK,	"BLK" },
15518976Sdfr	{ NFCHR,	"CHR" },
15618976Sdfr	{ NFLNK,	"LNK" },
15718976Sdfr	{ NFFIFO,	"FIFO" },
15818976Sdfr	{ 0,		NULL }
15918976Sdfr};
16018976Sdfr
16175118Sfennerstatic void
16275118Sfennerprint_nfsaddr(const u_char *bp, const char *s, const char *d)
16375118Sfenner{
16475118Sfenner	struct ip *ip;
16575118Sfenner#ifdef INET6
16675118Sfenner	struct ip6_hdr *ip6;
16775118Sfenner	char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
16875118Sfenner#else
16975118Sfenner#ifndef INET_ADDRSTRLEN
17075118Sfenner#define INET_ADDRSTRLEN	16
17175118Sfenner#endif
17275118Sfenner	char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN];
17375118Sfenner#endif
17475118Sfenner
17575118Sfenner	srcaddr[0] = dstaddr[0] = '\0';
17675118Sfenner	switch (IP_V((struct ip *)bp)) {
17775118Sfenner	case 4:
17875118Sfenner		ip = (struct ip *)bp;
17975118Sfenner		strlcpy(srcaddr, ipaddr_string(&ip->ip_src), sizeof(srcaddr));
18075118Sfenner		strlcpy(dstaddr, ipaddr_string(&ip->ip_dst), sizeof(dstaddr));
18175118Sfenner		break;
18275118Sfenner#ifdef INET6
18375118Sfenner	case 6:
18475118Sfenner		ip6 = (struct ip6_hdr *)bp;
18575118Sfenner		strlcpy(srcaddr, ip6addr_string(&ip6->ip6_src),
18675118Sfenner		    sizeof(srcaddr));
18775118Sfenner		strlcpy(dstaddr, ip6addr_string(&ip6->ip6_dst),
18875118Sfenner		    sizeof(dstaddr));
18975118Sfenner		break;
19075118Sfenner#endif
19175118Sfenner	default:
19275118Sfenner		strlcpy(srcaddr, "?", sizeof(srcaddr));
19375118Sfenner		strlcpy(dstaddr, "?", sizeof(dstaddr));
19475118Sfenner		break;
19575118Sfenner	}
19675118Sfenner
19775118Sfenner	(void)printf("%s.%s > %s.%s: ", srcaddr, s, dstaddr, d);
19875118Sfenner}
19975118Sfenner
20018976Sdfrstatic const u_int32_t *
20118976Sdfrparse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3)
20218976Sdfr{
20375118Sfenner	TCHECK(dp[0]);
204127675Sbms	sa3->sa_modeset = EXTRACT_32BITS(dp);
205127675Sbms	dp++;
206127675Sbms	if (sa3->sa_modeset) {
20775118Sfenner		TCHECK(dp[0]);
208127675Sbms		sa3->sa_mode = EXTRACT_32BITS(dp);
209127675Sbms		dp++;
21018976Sdfr	}
21118976Sdfr
21275118Sfenner	TCHECK(dp[0]);
213127675Sbms	sa3->sa_uidset = EXTRACT_32BITS(dp);
214127675Sbms	dp++;
215127675Sbms	if (sa3->sa_uidset) {
21675118Sfenner		TCHECK(dp[0]);
217127675Sbms		sa3->sa_uid = EXTRACT_32BITS(dp);
218127675Sbms		dp++;
21918976Sdfr	}
22018976Sdfr
22175118Sfenner	TCHECK(dp[0]);
222127675Sbms	sa3->sa_gidset = EXTRACT_32BITS(dp);
223127675Sbms	dp++;
224127675Sbms	if (sa3->sa_gidset) {
22575118Sfenner		TCHECK(dp[0]);
226127675Sbms		sa3->sa_gid = EXTRACT_32BITS(dp);
227127675Sbms		dp++;
22818976Sdfr	}
22918976Sdfr
23075118Sfenner	TCHECK(dp[0]);
231127675Sbms	sa3->sa_sizeset = EXTRACT_32BITS(dp);
232127675Sbms	dp++;
233127675Sbms	if (sa3->sa_sizeset) {
23475118Sfenner		TCHECK(dp[0]);
235127675Sbms		sa3->sa_size = EXTRACT_32BITS(dp);
236127675Sbms		dp++;
23718976Sdfr	}
23818976Sdfr
23975118Sfenner	TCHECK(dp[0]);
240127675Sbms	sa3->sa_atimetype = EXTRACT_32BITS(dp);
241127675Sbms	dp++;
242127675Sbms	if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) {
24375118Sfenner		TCHECK(dp[1]);
244127675Sbms		sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp);
245127675Sbms		dp++;
246127675Sbms		sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp);
247127675Sbms		dp++;
24818976Sdfr	}
24918976Sdfr
25075118Sfenner	TCHECK(dp[0]);
251127675Sbms	sa3->sa_mtimetype = EXTRACT_32BITS(dp);
252127675Sbms	dp++;
253127675Sbms	if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) {
25475118Sfenner		TCHECK(dp[1]);
255127675Sbms		sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp);
256127675Sbms		dp++;
257127675Sbms		sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp);
258127675Sbms		dp++;
25918976Sdfr	}
26018976Sdfr
26118976Sdfr	return dp;
26275118Sfennertrunc:
26375118Sfenner	return NULL;
26418976Sdfr}
26518976Sdfr
26675118Sfennerstatic int nfserr;		/* true if we error rather than trunc */
26775118Sfenner
26875118Sfennerstatic void
26918976Sdfrprint_sattr3(const struct nfsv3_sattr *sa3, int verbose)
27018976Sdfr{
27118976Sdfr	if (sa3->sa_modeset)
27218976Sdfr		printf(" mode %o", sa3->sa_mode);
27318976Sdfr	if (sa3->sa_uidset)
27418976Sdfr		printf(" uid %u", sa3->sa_uid);
27518976Sdfr	if (sa3->sa_gidset)
27618976Sdfr		printf(" gid %u", sa3->sa_gid);
27718976Sdfr	if (verbose > 1) {
27818976Sdfr		if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
27918976Sdfr			printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec,
28018976Sdfr			       sa3->sa_atime.nfsv3_nsec);
28118976Sdfr		if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
28218976Sdfr			printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
28318976Sdfr			       sa3->sa_mtime.nfsv3_nsec);
28418976Sdfr	}
28518976Sdfr}
28618976Sdfr
28718976Sdfrvoid
28817680Spstnfsreply_print(register const u_char *bp, u_int length,
28917680Spst	       register const u_char *bp2)
29017680Spst{
291146778Ssam	register const struct sunrpc_msg *rp;
292172686Smlaier	u_int32_t proc, vers, reply_stat;
29375118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
294172686Smlaier	enum sunrpc_reject_stat rstat;
295172686Smlaier	u_int32_t rlow;
296172686Smlaier	u_int32_t rhigh;
297172686Smlaier	enum sunrpc_auth_stat rwhy;
29817680Spst
29926183Sfenner	nfserr = 0;		/* assume no error */
300146778Ssam	rp = (const struct sunrpc_msg *)bp;
30117680Spst
30275118Sfenner	if (!nflag) {
30375118Sfenner		strlcpy(srcid, "nfs", sizeof(srcid));
30475118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
305127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
30675118Sfenner	} else {
30775118Sfenner		snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
30875118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
309127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
31075118Sfenner	}
31175118Sfenner	print_nfsaddr(bp2, srcid, dstid);
312172686Smlaier	reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat);
313172686Smlaier	switch (reply_stat) {
31417680Spst
315172686Smlaier	case SUNRPC_MSG_ACCEPTED:
316172686Smlaier		(void)printf("reply ok %u", length);
317172686Smlaier		if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
318172686Smlaier			interp_reply(rp, proc, vers, length);
319172686Smlaier		break;
320172686Smlaier
321172686Smlaier	case SUNRPC_MSG_DENIED:
322172686Smlaier		(void)printf("reply ERR %u: ", length);
323172686Smlaier		rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat);
324172686Smlaier		switch (rstat) {
325172686Smlaier
326172686Smlaier		case SUNRPC_RPC_MISMATCH:
327172686Smlaier			rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low);
328172686Smlaier			rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high);
329172686Smlaier			(void)printf("RPC Version mismatch (%u-%u)",
330172686Smlaier			    rlow, rhigh);
331172686Smlaier			break;
332172686Smlaier
333172686Smlaier		case SUNRPC_AUTH_ERROR:
334172686Smlaier			rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why);
335172686Smlaier			(void)printf("Auth ");
336172686Smlaier			switch (rwhy) {
337172686Smlaier
338172686Smlaier			case SUNRPC_AUTH_OK:
339172686Smlaier				(void)printf("OK");
340172686Smlaier				break;
341172686Smlaier
342172686Smlaier			case SUNRPC_AUTH_BADCRED:
343172686Smlaier				(void)printf("Bogus Credentials (seal broken)");
344172686Smlaier				break;
345172686Smlaier
346172686Smlaier			case SUNRPC_AUTH_REJECTEDCRED:
347172686Smlaier				(void)printf("Rejected Credentials (client should begin new session)");
348172686Smlaier				break;
349172686Smlaier
350172686Smlaier			case SUNRPC_AUTH_BADVERF:
351172686Smlaier				(void)printf("Bogus Verifier (seal broken)");
352172686Smlaier				break;
353172686Smlaier
354172686Smlaier			case SUNRPC_AUTH_REJECTEDVERF:
355172686Smlaier				(void)printf("Verifier expired or was replayed");
356172686Smlaier				break;
357172686Smlaier
358172686Smlaier			case SUNRPC_AUTH_TOOWEAK:
359172686Smlaier				(void)printf("Credentials are too weak");
360172686Smlaier				break;
361172686Smlaier
362172686Smlaier			case SUNRPC_AUTH_INVALIDRESP:
363172686Smlaier				(void)printf("Bogus response verifier");
364172686Smlaier				break;
365172686Smlaier
366172686Smlaier			case SUNRPC_AUTH_FAILED:
367172686Smlaier				(void)printf("Unknown failure");
368172686Smlaier				break;
369172686Smlaier
370172686Smlaier			default:
371172686Smlaier				(void)printf("Invalid failure code %u",
372172686Smlaier				    (unsigned int)rwhy);
373172686Smlaier				break;
374172686Smlaier			}
375172686Smlaier			break;
376172686Smlaier
377172686Smlaier		default:
378172686Smlaier			(void)printf("Unknown reason for rejecting rpc message %u",
379172686Smlaier			    (unsigned int)rstat);
380172686Smlaier			break;
381172686Smlaier		}
382172686Smlaier		break;
383172686Smlaier
384172686Smlaier	default:
385172686Smlaier		(void)printf("reply Unknown rpc response code=%u %u",
386172686Smlaier		    reply_stat, length);
387172686Smlaier		break;
388172686Smlaier	}
38917680Spst}
39017680Spst
39117680Spst/*
39217680Spst * Return a pointer to the first file handle in the packet.
39375118Sfenner * If the packet was truncated, return 0.
39417680Spst */
39517680Spststatic const u_int32_t *
396146778Ssamparsereq(register const struct sunrpc_msg *rp, register u_int length)
39717680Spst{
39826183Sfenner	register const u_int32_t *dp;
39917680Spst	register u_int len;
40017680Spst
40117680Spst	/*
40217680Spst	 * find the start of the req data (if we captured it)
40317680Spst	 */
40426183Sfenner	dp = (u_int32_t *)&rp->rm_call.cb_cred;
40526183Sfenner	TCHECK(dp[1]);
406127675Sbms	len = EXTRACT_32BITS(&dp[1]);
40726183Sfenner	if (len < length) {
40826183Sfenner		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
40926183Sfenner		TCHECK(dp[1]);
410127675Sbms		len = EXTRACT_32BITS(&dp[1]);
41126183Sfenner		if (len < length) {
41226183Sfenner			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
41326183Sfenner			TCHECK2(dp[0], 0);
41426183Sfenner			return (dp);
41517680Spst		}
41617680Spst	}
41726183Sfennertrunc:
41826183Sfenner	return (NULL);
41917680Spst}
42017680Spst
42117680Spst/*
42217680Spst * Print out an NFS file handle and return a pointer to following word.
42375118Sfenner * If packet was truncated, return 0.
42417680Spst */
42517680Spststatic const u_int32_t *
42618976Sdfrparsefh(register const u_int32_t *dp, int v3)
42717680Spst{
428127675Sbms	u_int len;
42918976Sdfr
43018976Sdfr	if (v3) {
43126183Sfenner		TCHECK(dp[0]);
432127675Sbms		len = EXTRACT_32BITS(dp) / 4;
43318976Sdfr		dp++;
43418976Sdfr	} else
43518976Sdfr		len = NFSX_V2FH / 4;
43618976Sdfr
43726183Sfenner	if (TTEST2(*dp, len * sizeof(*dp))) {
43818976Sdfr		nfs_printfh(dp, len);
43918976Sdfr		return (dp + len);
44017680Spst	}
44126183Sfennertrunc:
44226183Sfenner	return (NULL);
44317680Spst}
44417680Spst
44517680Spst/*
44617680Spst * Print out a file name and return pointer to 32-bit word past it.
44775118Sfenner * If packet was truncated, return 0.
44817680Spst */
44917680Spststatic const u_int32_t *
45017680Spstparsefn(register const u_int32_t *dp)
45117680Spst{
45217680Spst	register u_int32_t len;
45317680Spst	register const u_char *cp;
45417680Spst
45517680Spst	/* Bail if we don't have the string length */
45675118Sfenner	TCHECK(*dp);
45717680Spst
45817680Spst	/* Fetch string length; convert to host order */
45917680Spst	len = *dp++;
46017680Spst	NTOHL(len);
46117680Spst
46275118Sfenner	TCHECK2(*dp, ((len + 3) & ~3));
46375118Sfenner
46417680Spst	cp = (u_char *)dp;
46517680Spst	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
46617680Spst	dp += ((len + 3) & ~3) / sizeof(*dp);
46726183Sfenner	putchar('"');
468147904Ssam	if (fn_printn(cp, len, snapend)) {
469147904Ssam		putchar('"');
470147904Ssam		goto trunc;
471147904Ssam	}
47226183Sfenner	putchar('"');
47317680Spst
47417680Spst	return (dp);
47575118Sfennertrunc:
47675118Sfenner	return NULL;
47717680Spst}
47817680Spst
47917680Spst/*
48017680Spst * Print out file handle and file name.
48117680Spst * Return pointer to 32-bit word past file name.
48275118Sfenner * If packet was truncated (or there was some other error), return 0.
48317680Spst */
48417680Spststatic const u_int32_t *
48518976Sdfrparsefhn(register const u_int32_t *dp, int v3)
48617680Spst{
48718976Sdfr	dp = parsefh(dp, v3);
48826183Sfenner	if (dp == NULL)
48926183Sfenner		return (NULL);
49017680Spst	putchar(' ');
49117680Spst	return (parsefn(dp));
49217680Spst}
49317680Spst
49417680Spstvoid
49517680Spstnfsreq_print(register const u_char *bp, u_int length,
49617680Spst    register const u_char *bp2)
49717680Spst{
498146778Ssam	register const struct sunrpc_msg *rp;
49917680Spst	register const u_int32_t *dp;
50075118Sfenner	nfs_type type;
50175118Sfenner	int v3;
50275118Sfenner	u_int32_t proc;
50318976Sdfr	struct nfsv3_sattr sa3;
50475118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
50517680Spst
50626183Sfenner	nfserr = 0;		/* assume no error */
507146778Ssam	rp = (const struct sunrpc_msg *)bp;
50875118Sfenner	if (!nflag) {
50975118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
510127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
51175118Sfenner		strlcpy(dstid, "nfs", sizeof(dstid));
51275118Sfenner	} else {
51375118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
514127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
51575118Sfenner		snprintf(dstid, sizeof(dstid), "%u", NFS_PORT);
51675118Sfenner	}
51775118Sfenner	print_nfsaddr(bp2, srcid, dstid);
51875118Sfenner	(void)printf("%d", length);
51917680Spst
52075118Sfenner	xid_map_enter(rp, bp2);	/* record proc number for later on */
52117680Spst
522127675Sbms	v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
523127675Sbms	proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
52418976Sdfr
52518976Sdfr	if (!v3 && proc < NFS_NPROCS)
52618976Sdfr		proc =  nfsv3_procid[proc];
52718976Sdfr
52818976Sdfr	switch (proc) {
52917680Spst	case NFSPROC_NOOP:
53017680Spst		printf(" nop");
53117680Spst		return;
53217680Spst	case NFSPROC_NULL:
53317680Spst		printf(" null");
53417680Spst		return;
53517680Spst
53617680Spst	case NFSPROC_GETATTR:
53717680Spst		printf(" getattr");
53875118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
53975118Sfenner		    parsefh(dp, v3) != NULL)
54017680Spst			return;
54117680Spst		break;
54217680Spst
54317680Spst	case NFSPROC_SETATTR:
54417680Spst		printf(" setattr");
54575118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
54675118Sfenner		    parsefh(dp, v3) != NULL)
54717680Spst			return;
54817680Spst		break;
54917680Spst
55017680Spst	case NFSPROC_LOOKUP:
55117680Spst		printf(" lookup");
55275118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
55375118Sfenner		    parsefhn(dp, v3) != NULL)
55417680Spst			return;
55517680Spst		break;
55617680Spst
55718976Sdfr	case NFSPROC_ACCESS:
55818976Sdfr		printf(" access");
55926183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
56026183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
56175118Sfenner			TCHECK(dp[0]);
562127675Sbms			printf(" %04x", EXTRACT_32BITS(&dp[0]));
56318976Sdfr			return;
56418976Sdfr		}
56518976Sdfr		break;
56618976Sdfr
56717680Spst	case NFSPROC_READLINK:
56817680Spst		printf(" readlink");
56975118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
57075118Sfenner		    parsefh(dp, v3) != NULL)
57117680Spst			return;
57217680Spst		break;
57317680Spst
57417680Spst	case NFSPROC_READ:
57517680Spst		printf(" read");
57626183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
57726183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
57818976Sdfr			if (v3) {
57975118Sfenner				TCHECK(dp[2]);
580146778Ssam				printf(" %u bytes @ %" PRIu64,
581146778Ssam				       EXTRACT_32BITS(&dp[2]),
582146778Ssam				       EXTRACT_64BITS(&dp[0]));
58318976Sdfr			} else {
58475118Sfenner				TCHECK(dp[1]);
58575118Sfenner				printf(" %u bytes @ %u",
586127675Sbms				    EXTRACT_32BITS(&dp[1]),
587127675Sbms				    EXTRACT_32BITS(&dp[0]));
58818976Sdfr			}
58917680Spst			return;
59017680Spst		}
59117680Spst		break;
59217680Spst
59317680Spst	case NFSPROC_WRITE:
59417680Spst		printf(" write");
59526183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
59626183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
59718976Sdfr			if (v3) {
598146778Ssam				TCHECK(dp[2]);
599146778Ssam				printf(" %u (%u) bytes @ %" PRIu64,
600146778Ssam						EXTRACT_32BITS(&dp[4]),
601146778Ssam						EXTRACT_32BITS(&dp[2]),
602146778Ssam						EXTRACT_64BITS(&dp[0]));
60318976Sdfr				if (vflag) {
60418976Sdfr					dp += 3;
60575118Sfenner					TCHECK(dp[0]);
60618976Sdfr					printf(" <%s>",
60775118Sfenner						tok2str(nfsv3_writemodes,
608127675Sbms							NULL, EXTRACT_32BITS(dp)));
60918976Sdfr				}
61018976Sdfr			} else {
61175118Sfenner				TCHECK(dp[3]);
61275118Sfenner				printf(" %u (%u) bytes @ %u (%u)",
613127675Sbms						EXTRACT_32BITS(&dp[3]),
614127675Sbms						EXTRACT_32BITS(&dp[2]),
615127675Sbms						EXTRACT_32BITS(&dp[1]),
616127675Sbms						EXTRACT_32BITS(&dp[0]));
61718976Sdfr			}
61817680Spst			return;
61917680Spst		}
62017680Spst		break;
62117680Spst
62217680Spst	case NFSPROC_CREATE:
62317680Spst		printf(" create");
62475118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
62575118Sfenner		    parsefhn(dp, v3) != NULL)
62617680Spst			return;
62717680Spst		break;
62817680Spst
62918976Sdfr	case NFSPROC_MKDIR:
63018976Sdfr		printf(" mkdir");
63175118Sfenner		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
63218976Sdfr			return;
63318976Sdfr		break;
63418976Sdfr
63518976Sdfr	case NFSPROC_SYMLINK:
63618976Sdfr		printf(" symlink");
63775118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
63875118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
63975118Sfenner			fputs(" ->", stdout);
64075118Sfenner			if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
64118976Sdfr				break;
64275118Sfenner			if (parsefn(dp) == 0)
64318976Sdfr				break;
64418976Sdfr			if (v3 && vflag)
64518976Sdfr				print_sattr3(&sa3, vflag);
64618976Sdfr			return;
64718976Sdfr		}
64818976Sdfr		break;
64918976Sdfr
65018976Sdfr	case NFSPROC_MKNOD:
65118976Sdfr		printf(" mknod");
65275118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
65375118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
65475118Sfenner			TCHECK(*dp);
655127675Sbms			type = (nfs_type)EXTRACT_32BITS(dp);
656127675Sbms			dp++;
65775118Sfenner			if ((dp = parse_sattr3(dp, &sa3)) == 0)
65818976Sdfr				break;
65918976Sdfr			printf(" %s", tok2str(type2str, "unk-ft %d", type));
66018976Sdfr			if (vflag && (type == NFCHR || type == NFBLK)) {
66175118Sfenner				TCHECK(dp[1]);
66275118Sfenner				printf(" %u/%u",
663127675Sbms				       EXTRACT_32BITS(&dp[0]),
664127675Sbms				       EXTRACT_32BITS(&dp[1]));
66518976Sdfr				dp += 2;
66618976Sdfr			}
66718976Sdfr			if (vflag)
66818976Sdfr				print_sattr3(&sa3, vflag);
66918976Sdfr			return;
67018976Sdfr		}
67118976Sdfr		break;
67218976Sdfr
67317680Spst	case NFSPROC_REMOVE:
67417680Spst		printf(" remove");
67575118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
67675118Sfenner		    parsefhn(dp, v3) != NULL)
67717680Spst			return;
67817680Spst		break;
67917680Spst
68018976Sdfr	case NFSPROC_RMDIR:
68118976Sdfr		printf(" rmdir");
68275118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
68375118Sfenner		    parsefhn(dp, v3) != NULL)
68418976Sdfr			return;
68518976Sdfr		break;
68618976Sdfr
68717680Spst	case NFSPROC_RENAME:
68817680Spst		printf(" rename");
68926183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
69026183Sfenner		    (dp = parsefhn(dp, v3)) != NULL) {
69117680Spst			fputs(" ->", stdout);
69226183Sfenner			if (parsefhn(dp, v3) != NULL)
69317680Spst				return;
69417680Spst		}
69517680Spst		break;
69617680Spst
69717680Spst	case NFSPROC_LINK:
69817680Spst		printf(" link");
69926183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
70026183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
70117680Spst			fputs(" ->", stdout);
70226183Sfenner			if (parsefhn(dp, v3) != NULL)
70317680Spst				return;
70417680Spst		}
70517680Spst		break;
70617680Spst
70718976Sdfr	case NFSPROC_READDIR:
70818976Sdfr		printf(" readdir");
70926183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
71026183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
71118976Sdfr			if (v3) {
71275118Sfenner				TCHECK(dp[4]);
71318976Sdfr				/*
71418976Sdfr				 * We shouldn't really try to interpret the
71518976Sdfr				 * offset cookie here.
71618976Sdfr				 */
717146778Ssam				printf(" %u bytes @ %" PRId64,
718146778Ssam				    EXTRACT_32BITS(&dp[4]),
719146778Ssam				    EXTRACT_64BITS(&dp[0]));
72018976Sdfr				if (vflag)
72126183Sfenner					printf(" verf %08x%08x", dp[2],
72218976Sdfr					       dp[3]);
72318976Sdfr			} else {
72475118Sfenner				TCHECK(dp[1]);
72518976Sdfr				/*
72618976Sdfr				 * Print the offset as signed, since -1 is
72718976Sdfr				 * common, but offsets > 2^31 aren't.
72818976Sdfr				 */
72975118Sfenner				printf(" %u bytes @ %d",
730127675Sbms				    EXTRACT_32BITS(&dp[1]),
731127675Sbms				    EXTRACT_32BITS(&dp[0]));
73218976Sdfr			}
73318976Sdfr			return;
73417680Spst		}
73517680Spst		break;
73617680Spst
73718976Sdfr	case NFSPROC_READDIRPLUS:
73818976Sdfr		printf(" readdirplus");
73926183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
74026183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
74175118Sfenner			TCHECK(dp[4]);
74218976Sdfr			/*
74318976Sdfr			 * We don't try to interpret the offset
74418976Sdfr			 * cookie here.
74518976Sdfr			 */
746146778Ssam			printf(" %u bytes @ %" PRId64,
747146778Ssam				EXTRACT_32BITS(&dp[4]),
748146778Ssam				EXTRACT_64BITS(&dp[0]));
749146778Ssam			if (vflag) {
750146778Ssam				TCHECK(dp[5]);
75175118Sfenner				printf(" max %u verf %08x%08x",
752127675Sbms				       EXTRACT_32BITS(&dp[5]), dp[2], dp[3]);
753146778Ssam			}
75417680Spst			return;
75518976Sdfr		}
75617680Spst		break;
75717680Spst
75818976Sdfr	case NFSPROC_FSSTAT:
75918976Sdfr		printf(" fsstat");
76075118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
76175118Sfenner		    parsefh(dp, v3) != NULL)
76217680Spst			return;
76317680Spst		break;
76417680Spst
76518976Sdfr	case NFSPROC_FSINFO:
76618976Sdfr		printf(" fsinfo");
767111729Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
768111729Sfenner		    parsefh(dp, v3) != NULL)
769111729Sfenner			return;
77018976Sdfr		break;
77118976Sdfr
77218976Sdfr	case NFSPROC_PATHCONF:
77318976Sdfr		printf(" pathconf");
774111729Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
775111729Sfenner		    parsefh(dp, v3) != NULL)
776111729Sfenner			return;
77718976Sdfr		break;
77818976Sdfr
77918976Sdfr	case NFSPROC_COMMIT:
78018976Sdfr		printf(" commit");
78126183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
78226183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
783146778Ssam			TCHECK(dp[2]);
784146778Ssam			printf(" %u bytes @ %" PRIu64,
785146778Ssam				EXTRACT_32BITS(&dp[2]),
786146778Ssam				EXTRACT_64BITS(&dp[0]));
78717680Spst			return;
78817680Spst		}
78917680Spst		break;
79017680Spst
79117680Spst	default:
792127675Sbms		printf(" proc-%u", EXTRACT_32BITS(&rp->rm_call.cb_proc));
79317680Spst		return;
79417680Spst	}
79575118Sfenner
79617680Spsttrunc:
79726183Sfenner	if (!nfserr)
79826183Sfenner		fputs(" [|nfs]", stdout);
79917680Spst}
80017680Spst
80117680Spst/*
80217680Spst * Print out an NFS file handle.
80317680Spst * We assume packet was not truncated before the end of the
80417680Spst * file handle pointed to by dp.
80517680Spst *
80617680Spst * Note: new version (using portable file-handle parser) doesn't produce
80717680Spst * generation number.  It probably could be made to do that, with some
80817680Spst * additional hacking on the parser code.
80917680Spst */
81017680Spststatic void
81175118Sfennernfs_printfh(register const u_int32_t *dp, const u_int len)
81217680Spst{
81317680Spst	my_fsid fsid;
81417680Spst	ino_t ino;
815127675Sbms	const char *sfsname = NULL;
816127675Sbms	char *spacep;
81717680Spst
818127675Sbms	if (uflag) {
819127675Sbms		u_int i;
820127675Sbms		char const *sep = "";
82117680Spst
822127675Sbms		printf(" fh[");
823127675Sbms		for (i=0; i<len; i++) {
824127675Sbms			(void)printf("%s%x", sep, dp[i]);
825127675Sbms			sep = ":";
826127675Sbms		}
827127675Sbms		printf("]");
828127675Sbms		return;
829127675Sbms	}
830127675Sbms
831127675Sbms	Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
832127675Sbms
83317680Spst	if (sfsname) {
83426183Sfenner		/* file system ID is ASCII, not numeric, for this server OS */
83526183Sfenner		static char temp[NFSX_V3FHMAX+1];
83617680Spst
83726183Sfenner		/* Make sure string is null-terminated */
83826183Sfenner		strncpy(temp, sfsname, NFSX_V3FHMAX);
83975118Sfenner		temp[sizeof(temp) - 1] = '\0';
84026183Sfenner		/* Remove trailing spaces */
841127675Sbms		spacep = strchr(temp, ' ');
842127675Sbms		if (spacep)
843127675Sbms			*spacep = '\0';
84417680Spst
84575118Sfenner		(void)printf(" fh %s/", temp);
84626183Sfenner	} else {
84775118Sfenner		(void)printf(" fh %d,%d/",
84875118Sfenner			     fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor);
84917680Spst	}
85075118Sfenner
851127675Sbms	if(fsid.Fsid_dev.Minor == 257)
852127675Sbms		/* Print the undecoded handle */
85375118Sfenner		(void)printf("%s", fsid.Opaque_Handle);
85475118Sfenner	else
85575118Sfenner		(void)printf("%ld", (long) ino);
85617680Spst}
85717680Spst
85817680Spst/*
85917680Spst * Maintain a small cache of recent client.XID.server/proc pairs, to allow
86017680Spst * us to match up replies with requests and thus to know how to parse
86117680Spst * the reply.
86217680Spst */
86317680Spst
86417680Spststruct xid_map_entry {
86575118Sfenner	u_int32_t	xid;		/* transaction ID (net order) */
86675118Sfenner	int ipver;			/* IP version (4 or 6) */
86775118Sfenner#ifdef INET6
86875118Sfenner	struct in6_addr	client;		/* client IP address (net order) */
86975118Sfenner	struct in6_addr	server;		/* server IP address (net order) */
87075118Sfenner#else
87117680Spst	struct in_addr	client;		/* client IP address (net order) */
87217680Spst	struct in_addr	server;		/* server IP address (net order) */
87375118Sfenner#endif
87475118Sfenner	u_int32_t	proc;		/* call proc number (host order) */
87575118Sfenner	u_int32_t	vers;		/* program version (host order) */
87617680Spst};
87717680Spst
87817680Spst/*
87917680Spst * Map entries are kept in an array that we manage as a ring;
88017680Spst * new entries are always added at the tail of the ring.  Initially,
88117680Spst * all the entries are zero and hence don't match anything.
88217680Spst */
88317680Spst
88417680Spst#define	XIDMAPSIZE	64
88517680Spst
88617680Spststruct xid_map_entry xid_map[XIDMAPSIZE];
88717680Spst
88817680Spstint	xid_map_next = 0;
88917680Spstint	xid_map_hint = 0;
89017680Spst
89117680Spststatic void
892146778Ssamxid_map_enter(const struct sunrpc_msg *rp, const u_char *bp)
89317680Spst{
89475118Sfenner	struct ip *ip = NULL;
89575118Sfenner#ifdef INET6
89675118Sfenner	struct ip6_hdr *ip6 = NULL;
89775118Sfenner#endif
89817680Spst	struct xid_map_entry *xmep;
89917680Spst
90075118Sfenner	switch (IP_V((struct ip *)bp)) {
90175118Sfenner	case 4:
90275118Sfenner		ip = (struct ip *)bp;
90375118Sfenner		break;
90475118Sfenner#ifdef INET6
90575118Sfenner	case 6:
90675118Sfenner		ip6 = (struct ip6_hdr *)bp;
90775118Sfenner		break;
90875118Sfenner#endif
90975118Sfenner	default:
91075118Sfenner		return;
91175118Sfenner	}
91275118Sfenner
91317680Spst	xmep = &xid_map[xid_map_next];
91417680Spst
91517680Spst	if (++xid_map_next >= XIDMAPSIZE)
91617680Spst		xid_map_next = 0;
91717680Spst
91817680Spst	xmep->xid = rp->rm_xid;
91975118Sfenner	if (ip) {
92075118Sfenner		xmep->ipver = 4;
92175118Sfenner		memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
92275118Sfenner		memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
92375118Sfenner	}
92475118Sfenner#ifdef INET6
92575118Sfenner	else if (ip6) {
92675118Sfenner		xmep->ipver = 6;
92775118Sfenner		memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
92875118Sfenner		memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
92975118Sfenner	}
93075118Sfenner#endif
931127675Sbms	xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
932127675Sbms	xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
93317680Spst}
93417680Spst
93526183Sfenner/*
93626183Sfenner * Returns 0 and puts NFSPROC_xxx in proc return and
93726183Sfenner * version in vers return, or returns -1 on failure
93826183Sfenner */
93918976Sdfrstatic int
940146778Ssamxid_map_find(const struct sunrpc_msg *rp, const u_char *bp, u_int32_t *proc,
94118976Sdfr	     u_int32_t *vers)
94217680Spst{
94317680Spst	int i;
94417680Spst	struct xid_map_entry *xmep;
94517680Spst	u_int32_t xid = rp->rm_xid;
94675118Sfenner	struct ip *ip = (struct ip *)bp;
94775118Sfenner#ifdef INET6
94875118Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
94975118Sfenner#endif
95075118Sfenner	int cmp;
95117680Spst
95217680Spst	/* Start searching from where we last left off */
953127675Sbms	i = xid_map_hint;
95417680Spst	do {
95517680Spst		xmep = &xid_map[i];
95675118Sfenner		cmp = 1;
95775118Sfenner		if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
95875118Sfenner			goto nextitem;
95975118Sfenner		switch (xmep->ipver) {
96075118Sfenner		case 4:
96175118Sfenner			if (memcmp(&ip->ip_src, &xmep->server,
96275118Sfenner				   sizeof(ip->ip_src)) != 0 ||
96375118Sfenner			    memcmp(&ip->ip_dst, &xmep->client,
96475118Sfenner				   sizeof(ip->ip_dst)) != 0) {
96575118Sfenner				cmp = 0;
96675118Sfenner			}
96775118Sfenner			break;
96875118Sfenner#ifdef INET6
96975118Sfenner		case 6:
97075118Sfenner			if (memcmp(&ip6->ip6_src, &xmep->server,
97175118Sfenner				   sizeof(ip6->ip6_src)) != 0 ||
97275118Sfenner			    memcmp(&ip6->ip6_dst, &xmep->client,
97375118Sfenner				   sizeof(ip6->ip6_dst)) != 0) {
97475118Sfenner				cmp = 0;
97575118Sfenner			}
97675118Sfenner			break;
97775118Sfenner#endif
97875118Sfenner		default:
97975118Sfenner			cmp = 0;
98075118Sfenner			break;
98175118Sfenner		}
98275118Sfenner		if (cmp) {
98317680Spst			/* match */
98417680Spst			xid_map_hint = i;
98518976Sdfr			*proc = xmep->proc;
98618976Sdfr			*vers = xmep->vers;
98718976Sdfr			return 0;
98817680Spst		}
98975118Sfenner	nextitem:
99017680Spst		if (++i >= XIDMAPSIZE)
99117680Spst			i = 0;
99217680Spst	} while (i != xid_map_hint);
99317680Spst
99417680Spst	/* search failed */
99575118Sfenner	return (-1);
99617680Spst}
99717680Spst
99817680Spst/*
99917680Spst * Routines for parsing reply packets
100017680Spst */
100117680Spst
100217680Spst/*
100317680Spst * Return a pointer to the beginning of the actual results.
100475118Sfenner * If the packet was truncated, return 0.
100517680Spst */
100617680Spststatic const u_int32_t *
1007146778Ssamparserep(register const struct sunrpc_msg *rp, register u_int length)
100817680Spst{
100917680Spst	register const u_int32_t *dp;
101075118Sfenner	u_int len;
1011146778Ssam	enum sunrpc_accept_stat astat;
101217680Spst
101317680Spst	/*
101417680Spst	 * Portability note:
101517680Spst	 * Here we find the address of the ar_verf credentials.
101617680Spst	 * Originally, this calculation was
101717680Spst	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
101817680Spst	 * On the wire, the rp_acpt field starts immediately after
101917680Spst	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
102017680Spst	 * "struct accepted_reply") contains a "struct opaque_auth",
102117680Spst	 * whose internal representation contains a pointer, so on a
102217680Spst	 * 64-bit machine the compiler inserts 32 bits of padding
102317680Spst	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
102417680Spst	 * the internal representation to parse the on-the-wire
102517680Spst	 * representation.  Instead, we skip past the rp_stat field,
102617680Spst	 * which is an "enum" and so occupies one 32-bit word.
102717680Spst	 */
102817680Spst	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
102975118Sfenner	TCHECK(dp[1]);
1030127675Sbms	len = EXTRACT_32BITS(&dp[1]);
103117680Spst	if (len >= length)
103226183Sfenner		return (NULL);
103317680Spst	/*
103417680Spst	 * skip past the ar_verf credentials.
103517680Spst	 */
103617680Spst	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
103726183Sfenner	TCHECK2(dp[0], 0);
103817680Spst
103917680Spst	/*
104017680Spst	 * now we can check the ar_stat field
104117680Spst	 */
1042147904Ssam	astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
104317680Spst	switch (astat) {
104417680Spst
1045146778Ssam	case SUNRPC_SUCCESS:
104617680Spst		break;
104717680Spst
1048146778Ssam	case SUNRPC_PROG_UNAVAIL:
104917680Spst		printf(" PROG_UNAVAIL");
105026183Sfenner		nfserr = 1;		/* suppress trunc string */
105126183Sfenner		return (NULL);
105217680Spst
1053146778Ssam	case SUNRPC_PROG_MISMATCH:
105417680Spst		printf(" PROG_MISMATCH");
105526183Sfenner		nfserr = 1;		/* suppress trunc string */
105626183Sfenner		return (NULL);
105717680Spst
1058146778Ssam	case SUNRPC_PROC_UNAVAIL:
105917680Spst		printf(" PROC_UNAVAIL");
106026183Sfenner		nfserr = 1;		/* suppress trunc string */
106126183Sfenner		return (NULL);
106217680Spst
1063146778Ssam	case SUNRPC_GARBAGE_ARGS:
106417680Spst		printf(" GARBAGE_ARGS");
106526183Sfenner		nfserr = 1;		/* suppress trunc string */
106626183Sfenner		return (NULL);
106717680Spst
1068146778Ssam	case SUNRPC_SYSTEM_ERR:
106917680Spst		printf(" SYSTEM_ERR");
107026183Sfenner		nfserr = 1;		/* suppress trunc string */
107126183Sfenner		return (NULL);
107217680Spst
107317680Spst	default:
107417680Spst		printf(" ar_stat %d", astat);
107526183Sfenner		nfserr = 1;		/* suppress trunc string */
107626183Sfenner		return (NULL);
107717680Spst	}
107817680Spst	/* successful return */
107975118Sfenner	TCHECK2(*dp, sizeof(astat));
108075118Sfenner	return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
108126183Sfennertrunc:
108275118Sfenner	return (0);
108317680Spst}
108417680Spst
108517680Spststatic const u_int32_t *
108618976Sdfrparsestatus(const u_int32_t *dp, int *er)
108717680Spst{
108875118Sfenner	int errnum;
108917680Spst
109026183Sfenner	TCHECK(dp[0]);
109175118Sfenner
1092127675Sbms	errnum = EXTRACT_32BITS(&dp[0]);
109318976Sdfr	if (er)
109426183Sfenner		*er = errnum;
109526183Sfenner	if (errnum != 0) {
109626183Sfenner		if (!qflag)
109775118Sfenner			printf(" ERROR: %s",
109875118Sfenner			    tok2str(status2str, "unk %d", errnum));
109926183Sfenner		nfserr = 1;
110017680Spst	}
110117680Spst	return (dp + 1);
110226183Sfennertrunc:
110375118Sfenner	return NULL;
110417680Spst}
110517680Spst
110617680Spststatic const u_int32_t *
110718976Sdfrparsefattr(const u_int32_t *dp, int verbose, int v3)
110817680Spst{
110918976Sdfr	const struct nfs_fattr *fap;
111017680Spst
111118976Sdfr	fap = (const struct nfs_fattr *)dp;
111226184Sfenner	TCHECK(fap->fa_gid);
111317680Spst	if (verbose) {
111475118Sfenner		printf(" %s %o ids %d/%d",
111575118Sfenner		    tok2str(type2str, "unk-ft %d ",
1116127675Sbms		    EXTRACT_32BITS(&fap->fa_type)),
1117127675Sbms		    EXTRACT_32BITS(&fap->fa_mode),
1118127675Sbms		    EXTRACT_32BITS(&fap->fa_uid),
1119127675Sbms		    EXTRACT_32BITS(&fap->fa_gid));
112018976Sdfr		if (v3) {
112126184Sfenner			TCHECK(fap->fa3_size);
1122146778Ssam			printf(" sz %" PRIu64,
1123146778Ssam				EXTRACT_64BITS((u_int32_t *)&fap->fa3_size));
112426184Sfenner		} else {
112526184Sfenner			TCHECK(fap->fa2_size);
1126127675Sbms			printf(" sz %d", EXTRACT_32BITS(&fap->fa2_size));
112718976Sdfr		}
112817680Spst	}
112917680Spst	/* print lots more stuff */
113017680Spst	if (verbose > 1) {
113118976Sdfr		if (v3) {
113226184Sfenner			TCHECK(fap->fa3_ctime);
1133127675Sbms			printf(" nlink %d rdev %d/%d",
1134127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1135127675Sbms			       EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
1136127675Sbms			       EXTRACT_32BITS(&fap->fa3_rdev.specdata2));
1137146778Ssam			printf(" fsid %" PRIx64,
1138146778Ssam				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fsid));
1139146778Ssam			printf(" fileid %" PRIx64,
1140146778Ssam				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fileid));
1141127675Sbms			printf(" a/m/ctime %u.%06u",
1142127675Sbms			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
1143127675Sbms			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec));
1144127675Sbms			printf(" %u.%06u",
1145127675Sbms			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
1146127675Sbms			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec));
1147127675Sbms			printf(" %u.%06u",
1148127675Sbms			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
1149127675Sbms			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec));
115018976Sdfr		} else {
115126184Sfenner			TCHECK(fap->fa2_ctime);
1152127675Sbms			printf(" nlink %d rdev %x fsid %x nodeid %x a/m/ctime",
1153127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1154127675Sbms			       EXTRACT_32BITS(&fap->fa2_rdev),
1155127675Sbms			       EXTRACT_32BITS(&fap->fa2_fsid),
1156127675Sbms			       EXTRACT_32BITS(&fap->fa2_fileid));
1157127675Sbms			printf(" %u.%06u",
1158127675Sbms			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
1159127675Sbms			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec));
1160127675Sbms			printf(" %u.%06u",
1161127675Sbms			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
1162127675Sbms			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec));
1163127675Sbms			printf(" %u.%06u",
1164127675Sbms			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
1165127675Sbms			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec));
116618976Sdfr		}
116717680Spst	}
116818976Sdfr	return ((const u_int32_t *)((unsigned char *)dp +
116918976Sdfr		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
117026184Sfennertrunc:
117126184Sfenner	return (NULL);
117217680Spst}
117317680Spst
117417680Spststatic int
117518976Sdfrparseattrstat(const u_int32_t *dp, int verbose, int v3)
117617680Spst{
117718976Sdfr	int er;
117818976Sdfr
117918976Sdfr	dp = parsestatus(dp, &er);
1180111729Sfenner	if (dp == NULL)
118117680Spst		return (0);
1182111729Sfenner	if (er)
1183111729Sfenner		return (1);
118417680Spst
118526183Sfenner	return (parsefattr(dp, verbose, v3) != NULL);
118617680Spst}
118717680Spst
118817680Spststatic int
118917680Spstparsediropres(const u_int32_t *dp)
119017680Spst{
119118976Sdfr	int er;
119218976Sdfr
1193111729Sfenner	if (!(dp = parsestatus(dp, &er)))
119417680Spst		return (0);
1195111729Sfenner	if (er)
1196111729Sfenner		return (1);
119717680Spst
119818976Sdfr	dp = parsefh(dp, 0);
119917680Spst	if (dp == NULL)
120017680Spst		return (0);
120117680Spst
120218976Sdfr	return (parsefattr(dp, vflag, 0) != NULL);
120317680Spst}
120417680Spst
120517680Spststatic int
120618976Sdfrparselinkres(const u_int32_t *dp, int v3)
120717680Spst{
120818976Sdfr	int er;
120918976Sdfr
121018976Sdfr	dp = parsestatus(dp, &er);
1211111729Sfenner	if (dp == NULL)
121217680Spst		return(0);
1213111729Sfenner	if (er)
1214111729Sfenner		return(1);
121575118Sfenner	if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
121618976Sdfr		return (0);
121717680Spst	putchar(' ');
121817680Spst	return (parsefn(dp) != NULL);
121917680Spst}
122017680Spst
122117680Spststatic int
122218976Sdfrparsestatfs(const u_int32_t *dp, int v3)
122317680Spst{
122418976Sdfr	const struct nfs_statfs *sfsp;
122518976Sdfr	int er;
122617680Spst
122718976Sdfr	dp = parsestatus(dp, &er);
1228111729Sfenner	if (dp == NULL)
122975118Sfenner		return (0);
1230111729Sfenner	if (!v3 && er)
1231111729Sfenner		return (1);
123217680Spst
123318976Sdfr	if (qflag)
123418976Sdfr		return(1);
123518976Sdfr
123618976Sdfr	if (v3) {
123718976Sdfr		if (vflag)
123818976Sdfr			printf(" POST:");
123975118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
124018976Sdfr			return (0);
124117680Spst	}
124217680Spst
1243111729Sfenner	TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
124418976Sdfr
124518976Sdfr	sfsp = (const struct nfs_statfs *)dp;
124618976Sdfr
124718976Sdfr	if (v3) {
1248146778Ssam		printf(" tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
1249146778Ssam			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tbytes),
1250146778Ssam			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_fbytes),
1251146778Ssam			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_abytes));
125218976Sdfr		if (vflag) {
1253146778Ssam			printf(" tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
1254146778Ssam			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tfiles),
1255146778Ssam			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_ffiles),
1256146778Ssam			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_afiles),
1257127675Sbms			       EXTRACT_32BITS(&sfsp->sf_invarsec));
125818976Sdfr		}
125918976Sdfr	} else {
126075118Sfenner		printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
1261127675Sbms			EXTRACT_32BITS(&sfsp->sf_tsize),
1262127675Sbms			EXTRACT_32BITS(&sfsp->sf_bsize),
1263127675Sbms			EXTRACT_32BITS(&sfsp->sf_blocks),
1264127675Sbms			EXTRACT_32BITS(&sfsp->sf_bfree),
1265127675Sbms			EXTRACT_32BITS(&sfsp->sf_bavail));
126618976Sdfr	}
126718976Sdfr
126817680Spst	return (1);
126926184Sfennertrunc:
127026184Sfenner	return (0);
127117680Spst}
127217680Spst
127317680Spststatic int
127417680Spstparserddires(const u_int32_t *dp)
127517680Spst{
127618976Sdfr	int er;
127718976Sdfr
127818976Sdfr	dp = parsestatus(dp, &er);
1279111729Sfenner	if (dp == NULL)
128017680Spst		return (0);
1281111729Sfenner	if (er)
1282111729Sfenner		return (1);
128318976Sdfr	if (qflag)
128418976Sdfr		return (1);
128518976Sdfr
128626184Sfenner	TCHECK(dp[2]);
128775118Sfenner	printf(" offset %x size %d ",
1288127675Sbms	       EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1]));
128918976Sdfr	if (dp[2] != 0)
129075118Sfenner		printf(" eof");
129118976Sdfr
129218976Sdfr	return (1);
129326184Sfennertrunc:
129426184Sfenner	return (0);
129518976Sdfr}
129618976Sdfr
129718976Sdfrstatic const u_int32_t *
129818976Sdfrparse_wcc_attr(const u_int32_t *dp)
129918976Sdfr{
1300146778Ssam	printf(" sz %" PRIu64, EXTRACT_64BITS(&dp[0]));
130175118Sfenner	printf(" mtime %u.%06u ctime %u.%06u",
1302127675Sbms	       EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
1303127675Sbms	       EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5]));
130418976Sdfr	return (dp + 6);
130518976Sdfr}
130618976Sdfr
130718976Sdfr/*
130818976Sdfr * Pre operation attributes. Print only if vflag > 1.
130918976Sdfr */
131018976Sdfrstatic const u_int32_t *
131118976Sdfrparse_pre_op_attr(const u_int32_t *dp, int verbose)
131218976Sdfr{
131326184Sfenner	TCHECK(dp[0]);
1314127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
131518976Sdfr		return (dp + 1);
131618976Sdfr	dp++;
1317111729Sfenner	TCHECK2(*dp, 24);
131818976Sdfr	if (verbose > 1) {
131918976Sdfr		return parse_wcc_attr(dp);
132018976Sdfr	} else {
132118976Sdfr		/* If not verbose enough, just skip over wcc_attr */
132218976Sdfr		return (dp + 6);
132317680Spst	}
132426184Sfennertrunc:
132526184Sfenner	return (NULL);
132618976Sdfr}
132717680Spst
132818976Sdfr/*
132918976Sdfr * Post operation attributes are printed if vflag >= 1
133018976Sdfr */
133118976Sdfrstatic const u_int32_t *
133218976Sdfrparse_post_op_attr(const u_int32_t *dp, int verbose)
133318976Sdfr{
133426184Sfenner	TCHECK(dp[0]);
1335127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
133618976Sdfr		return (dp + 1);
133718976Sdfr	dp++;
133818976Sdfr	if (verbose) {
133918976Sdfr		return parsefattr(dp, verbose, 1);
134018976Sdfr	} else
134118976Sdfr		return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
134226184Sfennertrunc:
134326184Sfenner	return (NULL);
134418976Sdfr}
134518976Sdfr
134618976Sdfrstatic const u_int32_t *
134718976Sdfrparse_wcc_data(const u_int32_t *dp, int verbose)
134818976Sdfr{
134918976Sdfr	if (verbose > 1)
135018976Sdfr		printf(" PRE:");
135175118Sfenner	if (!(dp = parse_pre_op_attr(dp, verbose)))
135275118Sfenner		return (0);
135318976Sdfr
135418976Sdfr	if (verbose)
135518976Sdfr		printf(" POST:");
135618976Sdfr	return parse_post_op_attr(dp, verbose);
135718976Sdfr}
135818976Sdfr
135918976Sdfrstatic const u_int32_t *
136018976Sdfrparsecreateopres(const u_int32_t *dp, int verbose)
136118976Sdfr{
136218976Sdfr	int er;
136318976Sdfr
136475118Sfenner	if (!(dp = parsestatus(dp, &er)))
136575118Sfenner		return (0);
136618976Sdfr	if (er)
136718976Sdfr		dp = parse_wcc_data(dp, verbose);
136818976Sdfr	else {
136926184Sfenner		TCHECK(dp[0]);
1370127675Sbms		if (!EXTRACT_32BITS(&dp[0]))
137118976Sdfr			return (dp + 1);
137218976Sdfr		dp++;
137375118Sfenner		if (!(dp = parsefh(dp, 1)))
137475118Sfenner			return (0);
137518976Sdfr		if (verbose) {
137675118Sfenner			if (!(dp = parse_post_op_attr(dp, verbose)))
137775118Sfenner				return (0);
137818976Sdfr			if (vflag > 1) {
1379127675Sbms				printf(" dir attr:");
138018976Sdfr				dp = parse_wcc_data(dp, verbose);
138118976Sdfr			}
138218976Sdfr		}
138318976Sdfr	}
138418976Sdfr	return (dp);
138526184Sfennertrunc:
138626184Sfenner	return (NULL);
138718976Sdfr}
138818976Sdfr
138918976Sdfrstatic int
139018976Sdfrparsewccres(const u_int32_t *dp, int verbose)
139118976Sdfr{
139218976Sdfr	int er;
139318976Sdfr
139475118Sfenner	if (!(dp = parsestatus(dp, &er)))
139518976Sdfr		return (0);
139675118Sfenner	return parse_wcc_data(dp, verbose) != 0;
139718976Sdfr}
139818976Sdfr
139918976Sdfrstatic const u_int32_t *
140018976Sdfrparsev3rddirres(const u_int32_t *dp, int verbose)
140118976Sdfr{
140218976Sdfr	int er;
140318976Sdfr
140475118Sfenner	if (!(dp = parsestatus(dp, &er)))
140575118Sfenner		return (0);
140618976Sdfr	if (vflag)
140718976Sdfr		printf(" POST:");
140875118Sfenner	if (!(dp = parse_post_op_attr(dp, verbose)))
140975118Sfenner		return (0);
141018976Sdfr	if (er)
141118976Sdfr		return dp;
141218976Sdfr	if (vflag) {
141326184Sfenner		TCHECK(dp[1]);
141426183Sfenner		printf(" verf %08x%08x", dp[0], dp[1]);
141518976Sdfr		dp += 2;
141618976Sdfr	}
141718976Sdfr	return dp;
141826184Sfennertrunc:
141926184Sfenner	return (NULL);
142018976Sdfr}
142118976Sdfr
142218976Sdfrstatic int
142318976Sdfrparsefsinfo(const u_int32_t *dp)
142418976Sdfr{
142518976Sdfr	struct nfsv3_fsinfo *sfp;
142618976Sdfr	int er;
142718976Sdfr
142875118Sfenner	if (!(dp = parsestatus(dp, &er)))
142918976Sdfr		return (0);
143018976Sdfr	if (vflag)
143118976Sdfr		printf(" POST:");
143275118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
143318976Sdfr		return (0);
143418976Sdfr	if (er)
143518976Sdfr		return (1);
143618976Sdfr
143718976Sdfr	sfp = (struct nfsv3_fsinfo *)dp;
143826184Sfenner	TCHECK(*sfp);
143975118Sfenner	printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1440127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtmax),
1441127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtpref),
1442127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtmax),
1443127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtpref),
1444127675Sbms	       EXTRACT_32BITS(&sfp->fs_dtpref));
144518976Sdfr	if (vflag) {
1446146778Ssam		printf(" rtmult %u wtmult %u maxfsz %" PRIu64,
1447127675Sbms		       EXTRACT_32BITS(&sfp->fs_rtmult),
1448146778Ssam		       EXTRACT_32BITS(&sfp->fs_wtmult),
1449146778Ssam		       EXTRACT_64BITS((u_int32_t *)&sfp->fs_maxfilesize));
145075118Sfenner		printf(" delta %u.%06u ",
1451127675Sbms		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
1452127675Sbms		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec));
145318976Sdfr	}
1454111729Sfenner	return (1);
1455111729Sfennertrunc:
145675118Sfenner	return (0);
145718976Sdfr}
145818976Sdfr
145918976Sdfrstatic int
146018976Sdfrparsepathconf(const u_int32_t *dp)
146118976Sdfr{
146218976Sdfr	int er;
146318976Sdfr	struct nfsv3_pathconf *spp;
146418976Sdfr
146575118Sfenner	if (!(dp = parsestatus(dp, &er)))
146618976Sdfr		return (0);
146718976Sdfr	if (vflag)
146818976Sdfr		printf(" POST:");
146975118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
147018976Sdfr		return (0);
147118976Sdfr	if (er)
147218976Sdfr		return (1);
147318976Sdfr
147418976Sdfr	spp = (struct nfsv3_pathconf *)dp;
147526184Sfenner	TCHECK(*spp);
147618976Sdfr
147775118Sfenner	printf(" linkmax %u namemax %u %s %s %s %s",
1478127675Sbms	       EXTRACT_32BITS(&spp->pc_linkmax),
1479127675Sbms	       EXTRACT_32BITS(&spp->pc_namemax),
1480127675Sbms	       EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
1481127675Sbms	       EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
1482127675Sbms	       EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
1483127675Sbms	       EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : "");
1484111729Sfenner	return (1);
1485111729Sfennertrunc:
148675118Sfenner	return (0);
148717680Spst}
148875118Sfenner
148917680Spststatic void
1490146778Ssaminterp_reply(const struct sunrpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
149117680Spst{
149217680Spst	register const u_int32_t *dp;
149318976Sdfr	register int v3;
149418976Sdfr	int er;
149517680Spst
149618976Sdfr	v3 = (vers == NFS_VER3);
149718976Sdfr
149818976Sdfr	if (!v3 && proc < NFS_NPROCS)
149918976Sdfr		proc = nfsv3_procid[proc];
150018976Sdfr
150117680Spst	switch (proc) {
150217680Spst
150317680Spst	case NFSPROC_NOOP:
150417680Spst		printf(" nop");
150517680Spst		return;
150618976Sdfr
150717680Spst	case NFSPROC_NULL:
150817680Spst		printf(" null");
150917680Spst		return;
151017680Spst
151117680Spst	case NFSPROC_GETATTR:
151217680Spst		printf(" getattr");
151317680Spst		dp = parserep(rp, length);
151426183Sfenner		if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
151517680Spst			return;
151617680Spst		break;
151717680Spst
151817680Spst	case NFSPROC_SETATTR:
151917680Spst		printf(" setattr");
152075118Sfenner		if (!(dp = parserep(rp, length)))
152117680Spst			return;
152218976Sdfr		if (v3) {
152375118Sfenner			if (parsewccres(dp, vflag))
152418976Sdfr				return;
152518976Sdfr		} else {
152618976Sdfr			if (parseattrstat(dp, !qflag, 0) != 0)
152718976Sdfr				return;
152818976Sdfr		}
152917680Spst		break;
153017680Spst
153117680Spst	case NFSPROC_LOOKUP:
153217680Spst		printf(" lookup");
153375118Sfenner		if (!(dp = parserep(rp, length)))
153418976Sdfr			break;
153518976Sdfr		if (v3) {
153675118Sfenner			if (!(dp = parsestatus(dp, &er)))
153718976Sdfr				break;
153818976Sdfr			if (er) {
153918976Sdfr				if (vflag > 1) {
154018976Sdfr					printf(" post dattr:");
154118976Sdfr					dp = parse_post_op_attr(dp, vflag);
154218976Sdfr				}
154318976Sdfr			} else {
154475118Sfenner				if (!(dp = parsefh(dp, v3)))
154518976Sdfr					break;
154675118Sfenner				if ((dp = parse_post_op_attr(dp, vflag)) &&
154775118Sfenner				    vflag > 1) {
154818976Sdfr					printf(" post dattr:");
154918976Sdfr					dp = parse_post_op_attr(dp, vflag);
155018976Sdfr				}
155118976Sdfr			}
155275118Sfenner			if (dp)
155318976Sdfr				return;
155418976Sdfr		} else {
155518976Sdfr			if (parsediropres(dp) != 0)
155618976Sdfr				return;
155718976Sdfr		}
155817680Spst		break;
155917680Spst
156018976Sdfr	case NFSPROC_ACCESS:
156118976Sdfr		printf(" access");
156298527Sfenner		if (!(dp = parserep(rp, length)))
156398527Sfenner			break;
156475118Sfenner		if (!(dp = parsestatus(dp, &er)))
156518976Sdfr			break;
156618976Sdfr		if (vflag)
156718976Sdfr			printf(" attr:");
156875118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
156918976Sdfr			break;
157018976Sdfr		if (!er)
1571127675Sbms			printf(" c %04x", EXTRACT_32BITS(&dp[0]));
157218976Sdfr		return;
157318976Sdfr
157417680Spst	case NFSPROC_READLINK:
157517680Spst		printf(" readlink");
157617680Spst		dp = parserep(rp, length);
157726183Sfenner		if (dp != NULL && parselinkres(dp, v3) != 0)
157817680Spst			return;
157917680Spst		break;
158017680Spst
158117680Spst	case NFSPROC_READ:
158217680Spst		printf(" read");
158375118Sfenner		if (!(dp = parserep(rp, length)))
158418976Sdfr			break;
158518976Sdfr		if (v3) {
158675118Sfenner			if (!(dp = parsestatus(dp, &er)))
158718976Sdfr				break;
158875118Sfenner			if (!(dp = parse_post_op_attr(dp, vflag)))
158918976Sdfr				break;
159018976Sdfr			if (er)
159118976Sdfr				return;
159218976Sdfr			if (vflag) {
159375118Sfenner				TCHECK(dp[1]);
1594127675Sbms				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1595127675Sbms				if (EXTRACT_32BITS(&dp[1]))
159618976Sdfr					printf(" EOF");
159718976Sdfr			}
159817680Spst			return;
159918976Sdfr		} else {
160018976Sdfr			if (parseattrstat(dp, vflag, 0) != 0)
160118976Sdfr				return;
160218976Sdfr		}
160317680Spst		break;
160417680Spst
160517680Spst	case NFSPROC_WRITE:
160617680Spst		printf(" write");
160775118Sfenner		if (!(dp = parserep(rp, length)))
160818976Sdfr			break;
160918976Sdfr		if (v3) {
161075118Sfenner			if (!(dp = parsestatus(dp, &er)))
161118976Sdfr				break;
161275118Sfenner			if (!(dp = parse_wcc_data(dp, vflag)))
161318976Sdfr				break;
161418976Sdfr			if (er)
161518976Sdfr				return;
161618976Sdfr			if (vflag) {
161775118Sfenner				TCHECK(dp[0]);
1618127675Sbms				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
161918976Sdfr				if (vflag > 1) {
162075118Sfenner					TCHECK(dp[1]);
162118976Sdfr					printf(" <%s>",
162275118Sfenner						tok2str(nfsv3_writemodes,
1623127675Sbms							NULL, EXTRACT_32BITS(&dp[1])));
162418976Sdfr				}
162518976Sdfr				return;
162618976Sdfr			}
162718976Sdfr		} else {
162818976Sdfr			if (parseattrstat(dp, vflag, v3) != 0)
162918976Sdfr				return;
163018976Sdfr		}
163117680Spst		break;
163217680Spst
163317680Spst	case NFSPROC_CREATE:
163417680Spst		printf(" create");
163575118Sfenner		if (!(dp = parserep(rp, length)))
163618976Sdfr			break;
163718976Sdfr		if (v3) {
163875118Sfenner			if (parsecreateopres(dp, vflag) != 0)
163918976Sdfr				return;
164018976Sdfr		} else {
164118976Sdfr			if (parsediropres(dp) != 0)
164218976Sdfr				return;
164318976Sdfr		}
164418976Sdfr		break;
164518976Sdfr
164618976Sdfr	case NFSPROC_MKDIR:
164718976Sdfr		printf(" mkdir");
164875118Sfenner		if (!(dp = parserep(rp, length)))
164918976Sdfr			break;
165018976Sdfr		if (v3) {
165175118Sfenner			if (parsecreateopres(dp, vflag) != 0)
165218976Sdfr				return;
165318976Sdfr		} else {
165418976Sdfr			if (parsediropres(dp) != 0)
165518976Sdfr				return;
165618976Sdfr		}
165718976Sdfr		break;
165818976Sdfr
165918976Sdfr	case NFSPROC_SYMLINK:
166018976Sdfr		printf(" symlink");
166175118Sfenner		if (!(dp = parserep(rp, length)))
166218976Sdfr			break;
166318976Sdfr		if (v3) {
166475118Sfenner			if (parsecreateopres(dp, vflag) != 0)
166518976Sdfr				return;
166618976Sdfr		} else {
166775118Sfenner			if (parsestatus(dp, &er) != 0)
166818976Sdfr				return;
166918976Sdfr		}
167018976Sdfr		break;
167118976Sdfr
167218976Sdfr	case NFSPROC_MKNOD:
167318976Sdfr		printf(" mknod");
167475118Sfenner		if (!(dp = parserep(rp, length)))
167518976Sdfr			break;
167675118Sfenner		if (parsecreateopres(dp, vflag) != 0)
167717680Spst			return;
167817680Spst		break;
167917680Spst
168017680Spst	case NFSPROC_REMOVE:
168117680Spst		printf(" remove");
168275118Sfenner		if (!(dp = parserep(rp, length)))
168318976Sdfr			break;
168418976Sdfr		if (v3) {
168575118Sfenner			if (parsewccres(dp, vflag))
168618976Sdfr				return;
168718976Sdfr		} else {
168875118Sfenner			if (parsestatus(dp, &er) != 0)
168918976Sdfr				return;
169018976Sdfr		}
169117680Spst		break;
169217680Spst
169318976Sdfr	case NFSPROC_RMDIR:
169418976Sdfr		printf(" rmdir");
169575118Sfenner		if (!(dp = parserep(rp, length)))
169618976Sdfr			break;
169718976Sdfr		if (v3) {
169875118Sfenner			if (parsewccres(dp, vflag))
169918976Sdfr				return;
170018976Sdfr		} else {
170175118Sfenner			if (parsestatus(dp, &er) != 0)
170218976Sdfr				return;
170318976Sdfr		}
170418976Sdfr		break;
170518976Sdfr
170617680Spst	case NFSPROC_RENAME:
170717680Spst		printf(" rename");
170875118Sfenner		if (!(dp = parserep(rp, length)))
170918976Sdfr			break;
171018976Sdfr		if (v3) {
171175118Sfenner			if (!(dp = parsestatus(dp, &er)))
171218976Sdfr				break;
171318976Sdfr			if (vflag) {
171418976Sdfr				printf(" from:");
171575118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
171618976Sdfr					break;
171718976Sdfr				printf(" to:");
171875118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
171918976Sdfr					break;
172018976Sdfr			}
172117680Spst			return;
172218976Sdfr		} else {
172375118Sfenner			if (parsestatus(dp, &er) != 0)
172418976Sdfr				return;
172518976Sdfr		}
172617680Spst		break;
172717680Spst
172817680Spst	case NFSPROC_LINK:
172917680Spst		printf(" link");
173075118Sfenner		if (!(dp = parserep(rp, length)))
173118976Sdfr			break;
173218976Sdfr		if (v3) {
173375118Sfenner			if (!(dp = parsestatus(dp, &er)))
173418976Sdfr				break;
173518976Sdfr			if (vflag) {
173618976Sdfr				printf(" file POST:");
173775118Sfenner				if (!(dp = parse_post_op_attr(dp, vflag)))
173818976Sdfr					break;
173918976Sdfr				printf(" dir:");
174075118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
174118976Sdfr					break;
174218976Sdfr				return;
174318976Sdfr			}
174418976Sdfr		} else {
174575118Sfenner			if (parsestatus(dp, &er) != 0)
174618976Sdfr				return;
174718976Sdfr		}
174817680Spst		break;
174917680Spst
175018976Sdfr	case NFSPROC_READDIR:
175118976Sdfr		printf(" readdir");
175275118Sfenner		if (!(dp = parserep(rp, length)))
175318976Sdfr			break;
175418976Sdfr		if (v3) {
175575118Sfenner			if (parsev3rddirres(dp, vflag))
175618976Sdfr				return;
175718976Sdfr		} else {
175818976Sdfr			if (parserddires(dp) != 0)
175918976Sdfr				return;
176018976Sdfr		}
176118976Sdfr		break;
176218976Sdfr
176318976Sdfr	case NFSPROC_READDIRPLUS:
176418976Sdfr		printf(" readdirplus");
176575118Sfenner		if (!(dp = parserep(rp, length)))
176618976Sdfr			break;
176775118Sfenner		if (parsev3rddirres(dp, vflag))
176817680Spst			return;
176917680Spst		break;
177017680Spst
177118976Sdfr	case NFSPROC_FSSTAT:
177218976Sdfr		printf(" fsstat");
177317680Spst		dp = parserep(rp, length);
177475118Sfenner		if (dp != NULL && parsestatfs(dp, v3) != 0)
177517680Spst			return;
177617680Spst		break;
177717680Spst
177818976Sdfr	case NFSPROC_FSINFO:
177918976Sdfr		printf(" fsinfo");
178017680Spst		dp = parserep(rp, length);
178175118Sfenner		if (dp != NULL && parsefsinfo(dp) != 0)
178217680Spst			return;
178317680Spst		break;
178417680Spst
178518976Sdfr	case NFSPROC_PATHCONF:
178618976Sdfr		printf(" pathconf");
178717680Spst		dp = parserep(rp, length);
178826183Sfenner		if (dp != NULL && parsepathconf(dp) != 0)
178917680Spst			return;
179017680Spst		break;
179117680Spst
179218976Sdfr	case NFSPROC_COMMIT:
179318976Sdfr		printf(" commit");
179417680Spst		dp = parserep(rp, length);
179526183Sfenner		if (dp != NULL && parsewccres(dp, vflag) != 0)
179617680Spst			return;
179717680Spst		break;
179817680Spst
179917680Spst	default:
180026183Sfenner		printf(" proc-%u", proc);
180117680Spst		return;
180217680Spst	}
180318976Sdfrtrunc:
180426183Sfenner	if (!nfserr)
180526183Sfenner		fputs(" [|nfs]", stdout);
180617680Spst}
1807