print-nfs.c revision 190207
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 190207 2009-03-21 18:30:25Z rpaulo $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.110.2.1 2007-12-22 03:08:45 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);
54190207Srpaulostatic int 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
302190207Srpaulo	TCHECK(rp->rm_xid);
30375118Sfenner	if (!nflag) {
30475118Sfenner		strlcpy(srcid, "nfs", sizeof(srcid));
30575118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
306127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
30775118Sfenner	} else {
30875118Sfenner		snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
30975118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
310127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
31175118Sfenner	}
31275118Sfenner	print_nfsaddr(bp2, srcid, dstid);
313190207Srpaulo	TCHECK(rp->rm_reply.rp_stat);
314172686Smlaier	reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat);
315172686Smlaier	switch (reply_stat) {
31617680Spst
317172686Smlaier	case SUNRPC_MSG_ACCEPTED:
318172686Smlaier		(void)printf("reply ok %u", length);
319172686Smlaier		if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
320172686Smlaier			interp_reply(rp, proc, vers, length);
321172686Smlaier		break;
322172686Smlaier
323172686Smlaier	case SUNRPC_MSG_DENIED:
324172686Smlaier		(void)printf("reply ERR %u: ", length);
325190207Srpaulo		TCHECK(rp->rm_reply.rp_reject.rj_stat);
326172686Smlaier		rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat);
327172686Smlaier		switch (rstat) {
328172686Smlaier
329172686Smlaier		case SUNRPC_RPC_MISMATCH:
330190207Srpaulo			TCHECK(rp->rm_reply.rp_reject.rj_vers.high);
331172686Smlaier			rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low);
332172686Smlaier			rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high);
333172686Smlaier			(void)printf("RPC Version mismatch (%u-%u)",
334172686Smlaier			    rlow, rhigh);
335172686Smlaier			break;
336172686Smlaier
337172686Smlaier		case SUNRPC_AUTH_ERROR:
338190207Srpaulo			TCHECK(rp->rm_reply.rp_reject.rj_why);
339172686Smlaier			rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why);
340172686Smlaier			(void)printf("Auth ");
341172686Smlaier			switch (rwhy) {
342172686Smlaier
343172686Smlaier			case SUNRPC_AUTH_OK:
344172686Smlaier				(void)printf("OK");
345172686Smlaier				break;
346172686Smlaier
347172686Smlaier			case SUNRPC_AUTH_BADCRED:
348172686Smlaier				(void)printf("Bogus Credentials (seal broken)");
349172686Smlaier				break;
350172686Smlaier
351172686Smlaier			case SUNRPC_AUTH_REJECTEDCRED:
352172686Smlaier				(void)printf("Rejected Credentials (client should begin new session)");
353172686Smlaier				break;
354172686Smlaier
355172686Smlaier			case SUNRPC_AUTH_BADVERF:
356172686Smlaier				(void)printf("Bogus Verifier (seal broken)");
357172686Smlaier				break;
358172686Smlaier
359172686Smlaier			case SUNRPC_AUTH_REJECTEDVERF:
360172686Smlaier				(void)printf("Verifier expired or was replayed");
361172686Smlaier				break;
362172686Smlaier
363172686Smlaier			case SUNRPC_AUTH_TOOWEAK:
364172686Smlaier				(void)printf("Credentials are too weak");
365172686Smlaier				break;
366172686Smlaier
367172686Smlaier			case SUNRPC_AUTH_INVALIDRESP:
368172686Smlaier				(void)printf("Bogus response verifier");
369172686Smlaier				break;
370172686Smlaier
371172686Smlaier			case SUNRPC_AUTH_FAILED:
372172686Smlaier				(void)printf("Unknown failure");
373172686Smlaier				break;
374172686Smlaier
375172686Smlaier			default:
376172686Smlaier				(void)printf("Invalid failure code %u",
377172686Smlaier				    (unsigned int)rwhy);
378172686Smlaier				break;
379172686Smlaier			}
380172686Smlaier			break;
381172686Smlaier
382172686Smlaier		default:
383172686Smlaier			(void)printf("Unknown reason for rejecting rpc message %u",
384172686Smlaier			    (unsigned int)rstat);
385172686Smlaier			break;
386172686Smlaier		}
387172686Smlaier		break;
388172686Smlaier
389172686Smlaier	default:
390172686Smlaier		(void)printf("reply Unknown rpc response code=%u %u",
391172686Smlaier		    reply_stat, length);
392172686Smlaier		break;
393172686Smlaier	}
394190207Srpaulo	return;
395190207Srpaulo
396190207Srpaulotrunc:
397190207Srpaulo	if (!nfserr)
398190207Srpaulo		fputs(" [|nfs]", stdout);
39917680Spst}
40017680Spst
40117680Spst/*
40217680Spst * Return a pointer to the first file handle in the packet.
40375118Sfenner * If the packet was truncated, return 0.
40417680Spst */
40517680Spststatic const u_int32_t *
406146778Ssamparsereq(register const struct sunrpc_msg *rp, register u_int length)
40717680Spst{
40826183Sfenner	register const u_int32_t *dp;
40917680Spst	register u_int len;
41017680Spst
41117680Spst	/*
41217680Spst	 * find the start of the req data (if we captured it)
41317680Spst	 */
41426183Sfenner	dp = (u_int32_t *)&rp->rm_call.cb_cred;
41526183Sfenner	TCHECK(dp[1]);
416127675Sbms	len = EXTRACT_32BITS(&dp[1]);
41726183Sfenner	if (len < length) {
41826183Sfenner		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
41926183Sfenner		TCHECK(dp[1]);
420127675Sbms		len = EXTRACT_32BITS(&dp[1]);
42126183Sfenner		if (len < length) {
42226183Sfenner			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
42326183Sfenner			TCHECK2(dp[0], 0);
42426183Sfenner			return (dp);
42517680Spst		}
42617680Spst	}
42726183Sfennertrunc:
42826183Sfenner	return (NULL);
42917680Spst}
43017680Spst
43117680Spst/*
43217680Spst * Print out an NFS file handle and return a pointer to following word.
43375118Sfenner * If packet was truncated, return 0.
43417680Spst */
43517680Spststatic const u_int32_t *
43618976Sdfrparsefh(register const u_int32_t *dp, int v3)
43717680Spst{
438127675Sbms	u_int len;
43918976Sdfr
44018976Sdfr	if (v3) {
44126183Sfenner		TCHECK(dp[0]);
442127675Sbms		len = EXTRACT_32BITS(dp) / 4;
44318976Sdfr		dp++;
44418976Sdfr	} else
44518976Sdfr		len = NFSX_V2FH / 4;
44618976Sdfr
44726183Sfenner	if (TTEST2(*dp, len * sizeof(*dp))) {
44818976Sdfr		nfs_printfh(dp, len);
44918976Sdfr		return (dp + len);
45017680Spst	}
45126183Sfennertrunc:
45226183Sfenner	return (NULL);
45317680Spst}
45417680Spst
45517680Spst/*
45617680Spst * Print out a file name and return pointer to 32-bit word past it.
45775118Sfenner * If packet was truncated, return 0.
45817680Spst */
45917680Spststatic const u_int32_t *
46017680Spstparsefn(register const u_int32_t *dp)
46117680Spst{
46217680Spst	register u_int32_t len;
46317680Spst	register const u_char *cp;
46417680Spst
46517680Spst	/* Bail if we don't have the string length */
46675118Sfenner	TCHECK(*dp);
46717680Spst
46817680Spst	/* Fetch string length; convert to host order */
46917680Spst	len = *dp++;
47017680Spst	NTOHL(len);
47117680Spst
47275118Sfenner	TCHECK2(*dp, ((len + 3) & ~3));
47375118Sfenner
47417680Spst	cp = (u_char *)dp;
47517680Spst	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
47617680Spst	dp += ((len + 3) & ~3) / sizeof(*dp);
47726183Sfenner	putchar('"');
478147904Ssam	if (fn_printn(cp, len, snapend)) {
479147904Ssam		putchar('"');
480147904Ssam		goto trunc;
481147904Ssam	}
48226183Sfenner	putchar('"');
48317680Spst
48417680Spst	return (dp);
48575118Sfennertrunc:
48675118Sfenner	return NULL;
48717680Spst}
48817680Spst
48917680Spst/*
49017680Spst * Print out file handle and file name.
49117680Spst * Return pointer to 32-bit word past file name.
49275118Sfenner * If packet was truncated (or there was some other error), return 0.
49317680Spst */
49417680Spststatic const u_int32_t *
49518976Sdfrparsefhn(register const u_int32_t *dp, int v3)
49617680Spst{
49718976Sdfr	dp = parsefh(dp, v3);
49826183Sfenner	if (dp == NULL)
49926183Sfenner		return (NULL);
50017680Spst	putchar(' ');
50117680Spst	return (parsefn(dp));
50217680Spst}
50317680Spst
50417680Spstvoid
50517680Spstnfsreq_print(register const u_char *bp, u_int length,
50617680Spst    register const u_char *bp2)
50717680Spst{
508146778Ssam	register const struct sunrpc_msg *rp;
50917680Spst	register const u_int32_t *dp;
51075118Sfenner	nfs_type type;
51175118Sfenner	int v3;
51275118Sfenner	u_int32_t proc;
51318976Sdfr	struct nfsv3_sattr sa3;
51475118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
51517680Spst
51626183Sfenner	nfserr = 0;		/* assume no error */
517146778Ssam	rp = (const struct sunrpc_msg *)bp;
518190207Srpaulo
519190207Srpaulo	TCHECK(rp->rm_xid);
52075118Sfenner	if (!nflag) {
52175118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
522127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
52375118Sfenner		strlcpy(dstid, "nfs", sizeof(dstid));
52475118Sfenner	} else {
52575118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
526127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
52775118Sfenner		snprintf(dstid, sizeof(dstid), "%u", NFS_PORT);
52875118Sfenner	}
52975118Sfenner	print_nfsaddr(bp2, srcid, dstid);
53075118Sfenner	(void)printf("%d", length);
53117680Spst
532190207Srpaulo	if (!xid_map_enter(rp, bp2))	/* record proc number for later on */
533190207Srpaulo		goto trunc;
53417680Spst
535127675Sbms	v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
536127675Sbms	proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
53718976Sdfr
53818976Sdfr	if (!v3 && proc < NFS_NPROCS)
53918976Sdfr		proc =  nfsv3_procid[proc];
54018976Sdfr
54118976Sdfr	switch (proc) {
54217680Spst	case NFSPROC_NOOP:
54317680Spst		printf(" nop");
54417680Spst		return;
54517680Spst	case NFSPROC_NULL:
54617680Spst		printf(" null");
54717680Spst		return;
54817680Spst
54917680Spst	case NFSPROC_GETATTR:
55017680Spst		printf(" getattr");
55175118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
55275118Sfenner		    parsefh(dp, v3) != NULL)
55317680Spst			return;
55417680Spst		break;
55517680Spst
55617680Spst	case NFSPROC_SETATTR:
55717680Spst		printf(" setattr");
55875118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
55975118Sfenner		    parsefh(dp, v3) != NULL)
56017680Spst			return;
56117680Spst		break;
56217680Spst
56317680Spst	case NFSPROC_LOOKUP:
56417680Spst		printf(" lookup");
56575118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
56675118Sfenner		    parsefhn(dp, v3) != NULL)
56717680Spst			return;
56817680Spst		break;
56917680Spst
57018976Sdfr	case NFSPROC_ACCESS:
57118976Sdfr		printf(" access");
57226183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
57326183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
57475118Sfenner			TCHECK(dp[0]);
575127675Sbms			printf(" %04x", EXTRACT_32BITS(&dp[0]));
57618976Sdfr			return;
57718976Sdfr		}
57818976Sdfr		break;
57918976Sdfr
58017680Spst	case NFSPROC_READLINK:
58117680Spst		printf(" readlink");
58275118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
58375118Sfenner		    parsefh(dp, v3) != NULL)
58417680Spst			return;
58517680Spst		break;
58617680Spst
58717680Spst	case NFSPROC_READ:
58817680Spst		printf(" read");
58926183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
59026183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
59118976Sdfr			if (v3) {
59275118Sfenner				TCHECK(dp[2]);
593146778Ssam				printf(" %u bytes @ %" PRIu64,
594146778Ssam				       EXTRACT_32BITS(&dp[2]),
595146778Ssam				       EXTRACT_64BITS(&dp[0]));
59618976Sdfr			} else {
59775118Sfenner				TCHECK(dp[1]);
59875118Sfenner				printf(" %u bytes @ %u",
599127675Sbms				    EXTRACT_32BITS(&dp[1]),
600127675Sbms				    EXTRACT_32BITS(&dp[0]));
60118976Sdfr			}
60217680Spst			return;
60317680Spst		}
60417680Spst		break;
60517680Spst
60617680Spst	case NFSPROC_WRITE:
60717680Spst		printf(" write");
60826183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
60926183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
61018976Sdfr			if (v3) {
611146778Ssam				TCHECK(dp[2]);
612146778Ssam				printf(" %u (%u) bytes @ %" PRIu64,
613146778Ssam						EXTRACT_32BITS(&dp[4]),
614146778Ssam						EXTRACT_32BITS(&dp[2]),
615146778Ssam						EXTRACT_64BITS(&dp[0]));
61618976Sdfr				if (vflag) {
61718976Sdfr					dp += 3;
61875118Sfenner					TCHECK(dp[0]);
61918976Sdfr					printf(" <%s>",
62075118Sfenner						tok2str(nfsv3_writemodes,
621127675Sbms							NULL, EXTRACT_32BITS(dp)));
62218976Sdfr				}
62318976Sdfr			} else {
62475118Sfenner				TCHECK(dp[3]);
62575118Sfenner				printf(" %u (%u) bytes @ %u (%u)",
626127675Sbms						EXTRACT_32BITS(&dp[3]),
627127675Sbms						EXTRACT_32BITS(&dp[2]),
628127675Sbms						EXTRACT_32BITS(&dp[1]),
629127675Sbms						EXTRACT_32BITS(&dp[0]));
63018976Sdfr			}
63117680Spst			return;
63217680Spst		}
63317680Spst		break;
63417680Spst
63517680Spst	case NFSPROC_CREATE:
63617680Spst		printf(" create");
63775118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
63875118Sfenner		    parsefhn(dp, v3) != NULL)
63917680Spst			return;
64017680Spst		break;
64117680Spst
64218976Sdfr	case NFSPROC_MKDIR:
64318976Sdfr		printf(" mkdir");
64475118Sfenner		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
64518976Sdfr			return;
64618976Sdfr		break;
64718976Sdfr
64818976Sdfr	case NFSPROC_SYMLINK:
64918976Sdfr		printf(" symlink");
65075118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
65175118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
65275118Sfenner			fputs(" ->", stdout);
65375118Sfenner			if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
65418976Sdfr				break;
65575118Sfenner			if (parsefn(dp) == 0)
65618976Sdfr				break;
65718976Sdfr			if (v3 && vflag)
65818976Sdfr				print_sattr3(&sa3, vflag);
65918976Sdfr			return;
66018976Sdfr		}
66118976Sdfr		break;
66218976Sdfr
66318976Sdfr	case NFSPROC_MKNOD:
66418976Sdfr		printf(" mknod");
66575118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
66675118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
66775118Sfenner			TCHECK(*dp);
668127675Sbms			type = (nfs_type)EXTRACT_32BITS(dp);
669127675Sbms			dp++;
67075118Sfenner			if ((dp = parse_sattr3(dp, &sa3)) == 0)
67118976Sdfr				break;
67218976Sdfr			printf(" %s", tok2str(type2str, "unk-ft %d", type));
67318976Sdfr			if (vflag && (type == NFCHR || type == NFBLK)) {
67475118Sfenner				TCHECK(dp[1]);
67575118Sfenner				printf(" %u/%u",
676127675Sbms				       EXTRACT_32BITS(&dp[0]),
677127675Sbms				       EXTRACT_32BITS(&dp[1]));
67818976Sdfr				dp += 2;
67918976Sdfr			}
68018976Sdfr			if (vflag)
68118976Sdfr				print_sattr3(&sa3, vflag);
68218976Sdfr			return;
68318976Sdfr		}
68418976Sdfr		break;
68518976Sdfr
68617680Spst	case NFSPROC_REMOVE:
68717680Spst		printf(" remove");
68875118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
68975118Sfenner		    parsefhn(dp, v3) != NULL)
69017680Spst			return;
69117680Spst		break;
69217680Spst
69318976Sdfr	case NFSPROC_RMDIR:
69418976Sdfr		printf(" rmdir");
69575118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
69675118Sfenner		    parsefhn(dp, v3) != NULL)
69718976Sdfr			return;
69818976Sdfr		break;
69918976Sdfr
70017680Spst	case NFSPROC_RENAME:
70117680Spst		printf(" rename");
70226183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
70326183Sfenner		    (dp = parsefhn(dp, v3)) != NULL) {
70417680Spst			fputs(" ->", stdout);
70526183Sfenner			if (parsefhn(dp, v3) != NULL)
70617680Spst				return;
70717680Spst		}
70817680Spst		break;
70917680Spst
71017680Spst	case NFSPROC_LINK:
71117680Spst		printf(" link");
71226183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
71326183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
71417680Spst			fputs(" ->", stdout);
71526183Sfenner			if (parsefhn(dp, v3) != NULL)
71617680Spst				return;
71717680Spst		}
71817680Spst		break;
71917680Spst
72018976Sdfr	case NFSPROC_READDIR:
72118976Sdfr		printf(" readdir");
72226183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
72326183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
72418976Sdfr			if (v3) {
72575118Sfenner				TCHECK(dp[4]);
72618976Sdfr				/*
72718976Sdfr				 * We shouldn't really try to interpret the
72818976Sdfr				 * offset cookie here.
72918976Sdfr				 */
730146778Ssam				printf(" %u bytes @ %" PRId64,
731146778Ssam				    EXTRACT_32BITS(&dp[4]),
732146778Ssam				    EXTRACT_64BITS(&dp[0]));
73318976Sdfr				if (vflag)
73426183Sfenner					printf(" verf %08x%08x", dp[2],
73518976Sdfr					       dp[3]);
73618976Sdfr			} else {
73775118Sfenner				TCHECK(dp[1]);
73818976Sdfr				/*
73918976Sdfr				 * Print the offset as signed, since -1 is
74018976Sdfr				 * common, but offsets > 2^31 aren't.
74118976Sdfr				 */
74275118Sfenner				printf(" %u bytes @ %d",
743127675Sbms				    EXTRACT_32BITS(&dp[1]),
744127675Sbms				    EXTRACT_32BITS(&dp[0]));
74518976Sdfr			}
74618976Sdfr			return;
74717680Spst		}
74817680Spst		break;
74917680Spst
75018976Sdfr	case NFSPROC_READDIRPLUS:
75118976Sdfr		printf(" readdirplus");
75226183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
75326183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
75475118Sfenner			TCHECK(dp[4]);
75518976Sdfr			/*
75618976Sdfr			 * We don't try to interpret the offset
75718976Sdfr			 * cookie here.
75818976Sdfr			 */
759146778Ssam			printf(" %u bytes @ %" PRId64,
760146778Ssam				EXTRACT_32BITS(&dp[4]),
761146778Ssam				EXTRACT_64BITS(&dp[0]));
762146778Ssam			if (vflag) {
763146778Ssam				TCHECK(dp[5]);
76475118Sfenner				printf(" max %u verf %08x%08x",
765127675Sbms				       EXTRACT_32BITS(&dp[5]), dp[2], dp[3]);
766146778Ssam			}
76717680Spst			return;
76818976Sdfr		}
76917680Spst		break;
77017680Spst
77118976Sdfr	case NFSPROC_FSSTAT:
77218976Sdfr		printf(" fsstat");
77375118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
77475118Sfenner		    parsefh(dp, v3) != NULL)
77517680Spst			return;
77617680Spst		break;
77717680Spst
77818976Sdfr	case NFSPROC_FSINFO:
77918976Sdfr		printf(" fsinfo");
780111729Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
781111729Sfenner		    parsefh(dp, v3) != NULL)
782111729Sfenner			return;
78318976Sdfr		break;
78418976Sdfr
78518976Sdfr	case NFSPROC_PATHCONF:
78618976Sdfr		printf(" pathconf");
787111729Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
788111729Sfenner		    parsefh(dp, v3) != NULL)
789111729Sfenner			return;
79018976Sdfr		break;
79118976Sdfr
79218976Sdfr	case NFSPROC_COMMIT:
79318976Sdfr		printf(" commit");
79426183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
79526183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
796146778Ssam			TCHECK(dp[2]);
797146778Ssam			printf(" %u bytes @ %" PRIu64,
798146778Ssam				EXTRACT_32BITS(&dp[2]),
799146778Ssam				EXTRACT_64BITS(&dp[0]));
80017680Spst			return;
80117680Spst		}
80217680Spst		break;
80317680Spst
80417680Spst	default:
805127675Sbms		printf(" proc-%u", EXTRACT_32BITS(&rp->rm_call.cb_proc));
80617680Spst		return;
80717680Spst	}
80875118Sfenner
80917680Spsttrunc:
81026183Sfenner	if (!nfserr)
81126183Sfenner		fputs(" [|nfs]", stdout);
81217680Spst}
81317680Spst
81417680Spst/*
81517680Spst * Print out an NFS file handle.
81617680Spst * We assume packet was not truncated before the end of the
81717680Spst * file handle pointed to by dp.
81817680Spst *
81917680Spst * Note: new version (using portable file-handle parser) doesn't produce
82017680Spst * generation number.  It probably could be made to do that, with some
82117680Spst * additional hacking on the parser code.
82217680Spst */
82317680Spststatic void
82475118Sfennernfs_printfh(register const u_int32_t *dp, const u_int len)
82517680Spst{
82617680Spst	my_fsid fsid;
82717680Spst	ino_t ino;
828127675Sbms	const char *sfsname = NULL;
829127675Sbms	char *spacep;
83017680Spst
831127675Sbms	if (uflag) {
832127675Sbms		u_int i;
833127675Sbms		char const *sep = "";
83417680Spst
835127675Sbms		printf(" fh[");
836127675Sbms		for (i=0; i<len; i++) {
837127675Sbms			(void)printf("%s%x", sep, dp[i]);
838127675Sbms			sep = ":";
839127675Sbms		}
840127675Sbms		printf("]");
841127675Sbms		return;
842127675Sbms	}
843127675Sbms
844127675Sbms	Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
845127675Sbms
84617680Spst	if (sfsname) {
84726183Sfenner		/* file system ID is ASCII, not numeric, for this server OS */
84826183Sfenner		static char temp[NFSX_V3FHMAX+1];
84917680Spst
85026183Sfenner		/* Make sure string is null-terminated */
85126183Sfenner		strncpy(temp, sfsname, NFSX_V3FHMAX);
85275118Sfenner		temp[sizeof(temp) - 1] = '\0';
85326183Sfenner		/* Remove trailing spaces */
854127675Sbms		spacep = strchr(temp, ' ');
855127675Sbms		if (spacep)
856127675Sbms			*spacep = '\0';
85717680Spst
85875118Sfenner		(void)printf(" fh %s/", temp);
85926183Sfenner	} else {
86075118Sfenner		(void)printf(" fh %d,%d/",
86175118Sfenner			     fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor);
86217680Spst	}
86375118Sfenner
864127675Sbms	if(fsid.Fsid_dev.Minor == 257)
865127675Sbms		/* Print the undecoded handle */
86675118Sfenner		(void)printf("%s", fsid.Opaque_Handle);
86775118Sfenner	else
86875118Sfenner		(void)printf("%ld", (long) ino);
86917680Spst}
87017680Spst
87117680Spst/*
87217680Spst * Maintain a small cache of recent client.XID.server/proc pairs, to allow
87317680Spst * us to match up replies with requests and thus to know how to parse
87417680Spst * the reply.
87517680Spst */
87617680Spst
87717680Spststruct xid_map_entry {
87875118Sfenner	u_int32_t	xid;		/* transaction ID (net order) */
87975118Sfenner	int ipver;			/* IP version (4 or 6) */
88075118Sfenner#ifdef INET6
88175118Sfenner	struct in6_addr	client;		/* client IP address (net order) */
88275118Sfenner	struct in6_addr	server;		/* server IP address (net order) */
88375118Sfenner#else
88417680Spst	struct in_addr	client;		/* client IP address (net order) */
88517680Spst	struct in_addr	server;		/* server IP address (net order) */
88675118Sfenner#endif
88775118Sfenner	u_int32_t	proc;		/* call proc number (host order) */
88875118Sfenner	u_int32_t	vers;		/* program version (host order) */
88917680Spst};
89017680Spst
89117680Spst/*
89217680Spst * Map entries are kept in an array that we manage as a ring;
89317680Spst * new entries are always added at the tail of the ring.  Initially,
89417680Spst * all the entries are zero and hence don't match anything.
89517680Spst */
89617680Spst
89717680Spst#define	XIDMAPSIZE	64
89817680Spst
89917680Spststruct xid_map_entry xid_map[XIDMAPSIZE];
90017680Spst
90117680Spstint	xid_map_next = 0;
90217680Spstint	xid_map_hint = 0;
90317680Spst
904190207Srpaulostatic int
905146778Ssamxid_map_enter(const struct sunrpc_msg *rp, const u_char *bp)
90617680Spst{
90775118Sfenner	struct ip *ip = NULL;
90875118Sfenner#ifdef INET6
90975118Sfenner	struct ip6_hdr *ip6 = NULL;
91075118Sfenner#endif
91117680Spst	struct xid_map_entry *xmep;
91217680Spst
913190207Srpaulo	if (!TTEST(rp->rm_call.cb_vers))
914190207Srpaulo		return (0);
91575118Sfenner	switch (IP_V((struct ip *)bp)) {
91675118Sfenner	case 4:
91775118Sfenner		ip = (struct ip *)bp;
91875118Sfenner		break;
91975118Sfenner#ifdef INET6
92075118Sfenner	case 6:
92175118Sfenner		ip6 = (struct ip6_hdr *)bp;
92275118Sfenner		break;
92375118Sfenner#endif
92475118Sfenner	default:
925190207Srpaulo		return (1);
92675118Sfenner	}
92775118Sfenner
92817680Spst	xmep = &xid_map[xid_map_next];
92917680Spst
93017680Spst	if (++xid_map_next >= XIDMAPSIZE)
93117680Spst		xid_map_next = 0;
93217680Spst
93317680Spst	xmep->xid = rp->rm_xid;
93475118Sfenner	if (ip) {
93575118Sfenner		xmep->ipver = 4;
93675118Sfenner		memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
93775118Sfenner		memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
93875118Sfenner	}
93975118Sfenner#ifdef INET6
94075118Sfenner	else if (ip6) {
94175118Sfenner		xmep->ipver = 6;
94275118Sfenner		memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
94375118Sfenner		memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
94475118Sfenner	}
94575118Sfenner#endif
946127675Sbms	xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
947127675Sbms	xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
948190207Srpaulo	return (1);
94917680Spst}
95017680Spst
95126183Sfenner/*
95226183Sfenner * Returns 0 and puts NFSPROC_xxx in proc return and
95326183Sfenner * version in vers return, or returns -1 on failure
95426183Sfenner */
95518976Sdfrstatic int
956146778Ssamxid_map_find(const struct sunrpc_msg *rp, const u_char *bp, u_int32_t *proc,
95718976Sdfr	     u_int32_t *vers)
95817680Spst{
95917680Spst	int i;
96017680Spst	struct xid_map_entry *xmep;
96117680Spst	u_int32_t xid = rp->rm_xid;
96275118Sfenner	struct ip *ip = (struct ip *)bp;
96375118Sfenner#ifdef INET6
96475118Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
96575118Sfenner#endif
96675118Sfenner	int cmp;
96717680Spst
96817680Spst	/* Start searching from where we last left off */
969127675Sbms	i = xid_map_hint;
97017680Spst	do {
97117680Spst		xmep = &xid_map[i];
97275118Sfenner		cmp = 1;
97375118Sfenner		if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
97475118Sfenner			goto nextitem;
97575118Sfenner		switch (xmep->ipver) {
97675118Sfenner		case 4:
97775118Sfenner			if (memcmp(&ip->ip_src, &xmep->server,
97875118Sfenner				   sizeof(ip->ip_src)) != 0 ||
97975118Sfenner			    memcmp(&ip->ip_dst, &xmep->client,
98075118Sfenner				   sizeof(ip->ip_dst)) != 0) {
98175118Sfenner				cmp = 0;
98275118Sfenner			}
98375118Sfenner			break;
98475118Sfenner#ifdef INET6
98575118Sfenner		case 6:
98675118Sfenner			if (memcmp(&ip6->ip6_src, &xmep->server,
98775118Sfenner				   sizeof(ip6->ip6_src)) != 0 ||
98875118Sfenner			    memcmp(&ip6->ip6_dst, &xmep->client,
98975118Sfenner				   sizeof(ip6->ip6_dst)) != 0) {
99075118Sfenner				cmp = 0;
99175118Sfenner			}
99275118Sfenner			break;
99375118Sfenner#endif
99475118Sfenner		default:
99575118Sfenner			cmp = 0;
99675118Sfenner			break;
99775118Sfenner		}
99875118Sfenner		if (cmp) {
99917680Spst			/* match */
100017680Spst			xid_map_hint = i;
100118976Sdfr			*proc = xmep->proc;
100218976Sdfr			*vers = xmep->vers;
100318976Sdfr			return 0;
100417680Spst		}
100575118Sfenner	nextitem:
100617680Spst		if (++i >= XIDMAPSIZE)
100717680Spst			i = 0;
100817680Spst	} while (i != xid_map_hint);
100917680Spst
101017680Spst	/* search failed */
101175118Sfenner	return (-1);
101217680Spst}
101317680Spst
101417680Spst/*
101517680Spst * Routines for parsing reply packets
101617680Spst */
101717680Spst
101817680Spst/*
101917680Spst * Return a pointer to the beginning of the actual results.
102075118Sfenner * If the packet was truncated, return 0.
102117680Spst */
102217680Spststatic const u_int32_t *
1023146778Ssamparserep(register const struct sunrpc_msg *rp, register u_int length)
102417680Spst{
102517680Spst	register const u_int32_t *dp;
102675118Sfenner	u_int len;
1027146778Ssam	enum sunrpc_accept_stat astat;
102817680Spst
102917680Spst	/*
103017680Spst	 * Portability note:
103117680Spst	 * Here we find the address of the ar_verf credentials.
103217680Spst	 * Originally, this calculation was
103317680Spst	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
103417680Spst	 * On the wire, the rp_acpt field starts immediately after
103517680Spst	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
103617680Spst	 * "struct accepted_reply") contains a "struct opaque_auth",
103717680Spst	 * whose internal representation contains a pointer, so on a
103817680Spst	 * 64-bit machine the compiler inserts 32 bits of padding
103917680Spst	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
104017680Spst	 * the internal representation to parse the on-the-wire
104117680Spst	 * representation.  Instead, we skip past the rp_stat field,
104217680Spst	 * which is an "enum" and so occupies one 32-bit word.
104317680Spst	 */
104417680Spst	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
104575118Sfenner	TCHECK(dp[1]);
1046127675Sbms	len = EXTRACT_32BITS(&dp[1]);
104717680Spst	if (len >= length)
104826183Sfenner		return (NULL);
104917680Spst	/*
105017680Spst	 * skip past the ar_verf credentials.
105117680Spst	 */
105217680Spst	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
105326183Sfenner	TCHECK2(dp[0], 0);
105417680Spst
105517680Spst	/*
105617680Spst	 * now we can check the ar_stat field
105717680Spst	 */
1058147904Ssam	astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
105917680Spst	switch (astat) {
106017680Spst
1061146778Ssam	case SUNRPC_SUCCESS:
106217680Spst		break;
106317680Spst
1064146778Ssam	case SUNRPC_PROG_UNAVAIL:
106517680Spst		printf(" PROG_UNAVAIL");
106626183Sfenner		nfserr = 1;		/* suppress trunc string */
106726183Sfenner		return (NULL);
106817680Spst
1069146778Ssam	case SUNRPC_PROG_MISMATCH:
107017680Spst		printf(" PROG_MISMATCH");
107126183Sfenner		nfserr = 1;		/* suppress trunc string */
107226183Sfenner		return (NULL);
107317680Spst
1074146778Ssam	case SUNRPC_PROC_UNAVAIL:
107517680Spst		printf(" PROC_UNAVAIL");
107626183Sfenner		nfserr = 1;		/* suppress trunc string */
107726183Sfenner		return (NULL);
107817680Spst
1079146778Ssam	case SUNRPC_GARBAGE_ARGS:
108017680Spst		printf(" GARBAGE_ARGS");
108126183Sfenner		nfserr = 1;		/* suppress trunc string */
108226183Sfenner		return (NULL);
108317680Spst
1084146778Ssam	case SUNRPC_SYSTEM_ERR:
108517680Spst		printf(" SYSTEM_ERR");
108626183Sfenner		nfserr = 1;		/* suppress trunc string */
108726183Sfenner		return (NULL);
108817680Spst
108917680Spst	default:
109017680Spst		printf(" ar_stat %d", astat);
109126183Sfenner		nfserr = 1;		/* suppress trunc string */
109226183Sfenner		return (NULL);
109317680Spst	}
109417680Spst	/* successful return */
109575118Sfenner	TCHECK2(*dp, sizeof(astat));
109675118Sfenner	return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
109726183Sfennertrunc:
109875118Sfenner	return (0);
109917680Spst}
110017680Spst
110117680Spststatic const u_int32_t *
110218976Sdfrparsestatus(const u_int32_t *dp, int *er)
110317680Spst{
110475118Sfenner	int errnum;
110517680Spst
110626183Sfenner	TCHECK(dp[0]);
110775118Sfenner
1108127675Sbms	errnum = EXTRACT_32BITS(&dp[0]);
110918976Sdfr	if (er)
111026183Sfenner		*er = errnum;
111126183Sfenner	if (errnum != 0) {
111226183Sfenner		if (!qflag)
111375118Sfenner			printf(" ERROR: %s",
111475118Sfenner			    tok2str(status2str, "unk %d", errnum));
111526183Sfenner		nfserr = 1;
111617680Spst	}
111717680Spst	return (dp + 1);
111826183Sfennertrunc:
111975118Sfenner	return NULL;
112017680Spst}
112117680Spst
112217680Spststatic const u_int32_t *
112318976Sdfrparsefattr(const u_int32_t *dp, int verbose, int v3)
112417680Spst{
112518976Sdfr	const struct nfs_fattr *fap;
112617680Spst
112718976Sdfr	fap = (const struct nfs_fattr *)dp;
112826184Sfenner	TCHECK(fap->fa_gid);
112917680Spst	if (verbose) {
113075118Sfenner		printf(" %s %o ids %d/%d",
113175118Sfenner		    tok2str(type2str, "unk-ft %d ",
1132127675Sbms		    EXTRACT_32BITS(&fap->fa_type)),
1133127675Sbms		    EXTRACT_32BITS(&fap->fa_mode),
1134127675Sbms		    EXTRACT_32BITS(&fap->fa_uid),
1135127675Sbms		    EXTRACT_32BITS(&fap->fa_gid));
113618976Sdfr		if (v3) {
113726184Sfenner			TCHECK(fap->fa3_size);
1138146778Ssam			printf(" sz %" PRIu64,
1139146778Ssam				EXTRACT_64BITS((u_int32_t *)&fap->fa3_size));
114026184Sfenner		} else {
114126184Sfenner			TCHECK(fap->fa2_size);
1142127675Sbms			printf(" sz %d", EXTRACT_32BITS(&fap->fa2_size));
114318976Sdfr		}
114417680Spst	}
114517680Spst	/* print lots more stuff */
114617680Spst	if (verbose > 1) {
114718976Sdfr		if (v3) {
114826184Sfenner			TCHECK(fap->fa3_ctime);
1149127675Sbms			printf(" nlink %d rdev %d/%d",
1150127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1151127675Sbms			       EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
1152127675Sbms			       EXTRACT_32BITS(&fap->fa3_rdev.specdata2));
1153146778Ssam			printf(" fsid %" PRIx64,
1154146778Ssam				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fsid));
1155146778Ssam			printf(" fileid %" PRIx64,
1156146778Ssam				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fileid));
1157127675Sbms			printf(" a/m/ctime %u.%06u",
1158127675Sbms			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
1159127675Sbms			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec));
1160127675Sbms			printf(" %u.%06u",
1161127675Sbms			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
1162127675Sbms			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec));
1163127675Sbms			printf(" %u.%06u",
1164127675Sbms			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
1165127675Sbms			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec));
116618976Sdfr		} else {
116726184Sfenner			TCHECK(fap->fa2_ctime);
1168127675Sbms			printf(" nlink %d rdev %x fsid %x nodeid %x a/m/ctime",
1169127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1170127675Sbms			       EXTRACT_32BITS(&fap->fa2_rdev),
1171127675Sbms			       EXTRACT_32BITS(&fap->fa2_fsid),
1172127675Sbms			       EXTRACT_32BITS(&fap->fa2_fileid));
1173127675Sbms			printf(" %u.%06u",
1174127675Sbms			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
1175127675Sbms			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec));
1176127675Sbms			printf(" %u.%06u",
1177127675Sbms			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
1178127675Sbms			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec));
1179127675Sbms			printf(" %u.%06u",
1180127675Sbms			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
1181127675Sbms			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec));
118218976Sdfr		}
118317680Spst	}
118418976Sdfr	return ((const u_int32_t *)((unsigned char *)dp +
118518976Sdfr		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
118626184Sfennertrunc:
118726184Sfenner	return (NULL);
118817680Spst}
118917680Spst
119017680Spststatic int
119118976Sdfrparseattrstat(const u_int32_t *dp, int verbose, int v3)
119217680Spst{
119318976Sdfr	int er;
119418976Sdfr
119518976Sdfr	dp = parsestatus(dp, &er);
1196111729Sfenner	if (dp == NULL)
119717680Spst		return (0);
1198111729Sfenner	if (er)
1199111729Sfenner		return (1);
120017680Spst
120126183Sfenner	return (parsefattr(dp, verbose, v3) != NULL);
120217680Spst}
120317680Spst
120417680Spststatic int
120517680Spstparsediropres(const u_int32_t *dp)
120617680Spst{
120718976Sdfr	int er;
120818976Sdfr
1209111729Sfenner	if (!(dp = parsestatus(dp, &er)))
121017680Spst		return (0);
1211111729Sfenner	if (er)
1212111729Sfenner		return (1);
121317680Spst
121418976Sdfr	dp = parsefh(dp, 0);
121517680Spst	if (dp == NULL)
121617680Spst		return (0);
121717680Spst
121818976Sdfr	return (parsefattr(dp, vflag, 0) != NULL);
121917680Spst}
122017680Spst
122117680Spststatic int
122218976Sdfrparselinkres(const u_int32_t *dp, int v3)
122317680Spst{
122418976Sdfr	int er;
122518976Sdfr
122618976Sdfr	dp = parsestatus(dp, &er);
1227111729Sfenner	if (dp == NULL)
122817680Spst		return(0);
1229111729Sfenner	if (er)
1230111729Sfenner		return(1);
123175118Sfenner	if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
123218976Sdfr		return (0);
123317680Spst	putchar(' ');
123417680Spst	return (parsefn(dp) != NULL);
123517680Spst}
123617680Spst
123717680Spststatic int
123818976Sdfrparsestatfs(const u_int32_t *dp, int v3)
123917680Spst{
124018976Sdfr	const struct nfs_statfs *sfsp;
124118976Sdfr	int er;
124217680Spst
124318976Sdfr	dp = parsestatus(dp, &er);
1244111729Sfenner	if (dp == NULL)
124575118Sfenner		return (0);
1246111729Sfenner	if (!v3 && er)
1247111729Sfenner		return (1);
124817680Spst
124918976Sdfr	if (qflag)
125018976Sdfr		return(1);
125118976Sdfr
125218976Sdfr	if (v3) {
125318976Sdfr		if (vflag)
125418976Sdfr			printf(" POST:");
125575118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
125618976Sdfr			return (0);
125717680Spst	}
125817680Spst
1259111729Sfenner	TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
126018976Sdfr
126118976Sdfr	sfsp = (const struct nfs_statfs *)dp;
126218976Sdfr
126318976Sdfr	if (v3) {
1264146778Ssam		printf(" tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
1265146778Ssam			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tbytes),
1266146778Ssam			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_fbytes),
1267146778Ssam			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_abytes));
126818976Sdfr		if (vflag) {
1269146778Ssam			printf(" tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
1270146778Ssam			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tfiles),
1271146778Ssam			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_ffiles),
1272146778Ssam			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_afiles),
1273127675Sbms			       EXTRACT_32BITS(&sfsp->sf_invarsec));
127418976Sdfr		}
127518976Sdfr	} else {
127675118Sfenner		printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
1277127675Sbms			EXTRACT_32BITS(&sfsp->sf_tsize),
1278127675Sbms			EXTRACT_32BITS(&sfsp->sf_bsize),
1279127675Sbms			EXTRACT_32BITS(&sfsp->sf_blocks),
1280127675Sbms			EXTRACT_32BITS(&sfsp->sf_bfree),
1281127675Sbms			EXTRACT_32BITS(&sfsp->sf_bavail));
128218976Sdfr	}
128318976Sdfr
128417680Spst	return (1);
128526184Sfennertrunc:
128626184Sfenner	return (0);
128717680Spst}
128817680Spst
128917680Spststatic int
129017680Spstparserddires(const u_int32_t *dp)
129117680Spst{
129218976Sdfr	int er;
129318976Sdfr
129418976Sdfr	dp = parsestatus(dp, &er);
1295111729Sfenner	if (dp == NULL)
129617680Spst		return (0);
1297111729Sfenner	if (er)
1298111729Sfenner		return (1);
129918976Sdfr	if (qflag)
130018976Sdfr		return (1);
130118976Sdfr
130226184Sfenner	TCHECK(dp[2]);
130375118Sfenner	printf(" offset %x size %d ",
1304127675Sbms	       EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1]));
130518976Sdfr	if (dp[2] != 0)
130675118Sfenner		printf(" eof");
130718976Sdfr
130818976Sdfr	return (1);
130926184Sfennertrunc:
131026184Sfenner	return (0);
131118976Sdfr}
131218976Sdfr
131318976Sdfrstatic const u_int32_t *
131418976Sdfrparse_wcc_attr(const u_int32_t *dp)
131518976Sdfr{
1316146778Ssam	printf(" sz %" PRIu64, EXTRACT_64BITS(&dp[0]));
131775118Sfenner	printf(" mtime %u.%06u ctime %u.%06u",
1318127675Sbms	       EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
1319127675Sbms	       EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5]));
132018976Sdfr	return (dp + 6);
132118976Sdfr}
132218976Sdfr
132318976Sdfr/*
132418976Sdfr * Pre operation attributes. Print only if vflag > 1.
132518976Sdfr */
132618976Sdfrstatic const u_int32_t *
132718976Sdfrparse_pre_op_attr(const u_int32_t *dp, int verbose)
132818976Sdfr{
132926184Sfenner	TCHECK(dp[0]);
1330127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
133118976Sdfr		return (dp + 1);
133218976Sdfr	dp++;
1333111729Sfenner	TCHECK2(*dp, 24);
133418976Sdfr	if (verbose > 1) {
133518976Sdfr		return parse_wcc_attr(dp);
133618976Sdfr	} else {
133718976Sdfr		/* If not verbose enough, just skip over wcc_attr */
133818976Sdfr		return (dp + 6);
133917680Spst	}
134026184Sfennertrunc:
134126184Sfenner	return (NULL);
134218976Sdfr}
134317680Spst
134418976Sdfr/*
134518976Sdfr * Post operation attributes are printed if vflag >= 1
134618976Sdfr */
134718976Sdfrstatic const u_int32_t *
134818976Sdfrparse_post_op_attr(const u_int32_t *dp, int verbose)
134918976Sdfr{
135026184Sfenner	TCHECK(dp[0]);
1351127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
135218976Sdfr		return (dp + 1);
135318976Sdfr	dp++;
135418976Sdfr	if (verbose) {
135518976Sdfr		return parsefattr(dp, verbose, 1);
135618976Sdfr	} else
135718976Sdfr		return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
135826184Sfennertrunc:
135926184Sfenner	return (NULL);
136018976Sdfr}
136118976Sdfr
136218976Sdfrstatic const u_int32_t *
136318976Sdfrparse_wcc_data(const u_int32_t *dp, int verbose)
136418976Sdfr{
136518976Sdfr	if (verbose > 1)
136618976Sdfr		printf(" PRE:");
136775118Sfenner	if (!(dp = parse_pre_op_attr(dp, verbose)))
136875118Sfenner		return (0);
136918976Sdfr
137018976Sdfr	if (verbose)
137118976Sdfr		printf(" POST:");
137218976Sdfr	return parse_post_op_attr(dp, verbose);
137318976Sdfr}
137418976Sdfr
137518976Sdfrstatic const u_int32_t *
137618976Sdfrparsecreateopres(const u_int32_t *dp, int verbose)
137718976Sdfr{
137818976Sdfr	int er;
137918976Sdfr
138075118Sfenner	if (!(dp = parsestatus(dp, &er)))
138175118Sfenner		return (0);
138218976Sdfr	if (er)
138318976Sdfr		dp = parse_wcc_data(dp, verbose);
138418976Sdfr	else {
138526184Sfenner		TCHECK(dp[0]);
1386127675Sbms		if (!EXTRACT_32BITS(&dp[0]))
138718976Sdfr			return (dp + 1);
138818976Sdfr		dp++;
138975118Sfenner		if (!(dp = parsefh(dp, 1)))
139075118Sfenner			return (0);
139118976Sdfr		if (verbose) {
139275118Sfenner			if (!(dp = parse_post_op_attr(dp, verbose)))
139375118Sfenner				return (0);
139418976Sdfr			if (vflag > 1) {
1395127675Sbms				printf(" dir attr:");
139618976Sdfr				dp = parse_wcc_data(dp, verbose);
139718976Sdfr			}
139818976Sdfr		}
139918976Sdfr	}
140018976Sdfr	return (dp);
140126184Sfennertrunc:
140226184Sfenner	return (NULL);
140318976Sdfr}
140418976Sdfr
140518976Sdfrstatic int
140618976Sdfrparsewccres(const u_int32_t *dp, int verbose)
140718976Sdfr{
140818976Sdfr	int er;
140918976Sdfr
141075118Sfenner	if (!(dp = parsestatus(dp, &er)))
141118976Sdfr		return (0);
141275118Sfenner	return parse_wcc_data(dp, verbose) != 0;
141318976Sdfr}
141418976Sdfr
141518976Sdfrstatic const u_int32_t *
141618976Sdfrparsev3rddirres(const u_int32_t *dp, int verbose)
141718976Sdfr{
141818976Sdfr	int er;
141918976Sdfr
142075118Sfenner	if (!(dp = parsestatus(dp, &er)))
142175118Sfenner		return (0);
142218976Sdfr	if (vflag)
142318976Sdfr		printf(" POST:");
142475118Sfenner	if (!(dp = parse_post_op_attr(dp, verbose)))
142575118Sfenner		return (0);
142618976Sdfr	if (er)
142718976Sdfr		return dp;
142818976Sdfr	if (vflag) {
142926184Sfenner		TCHECK(dp[1]);
143026183Sfenner		printf(" verf %08x%08x", dp[0], dp[1]);
143118976Sdfr		dp += 2;
143218976Sdfr	}
143318976Sdfr	return dp;
143426184Sfennertrunc:
143526184Sfenner	return (NULL);
143618976Sdfr}
143718976Sdfr
143818976Sdfrstatic int
143918976Sdfrparsefsinfo(const u_int32_t *dp)
144018976Sdfr{
144118976Sdfr	struct nfsv3_fsinfo *sfp;
144218976Sdfr	int er;
144318976Sdfr
144475118Sfenner	if (!(dp = parsestatus(dp, &er)))
144518976Sdfr		return (0);
144618976Sdfr	if (vflag)
144718976Sdfr		printf(" POST:");
144875118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
144918976Sdfr		return (0);
145018976Sdfr	if (er)
145118976Sdfr		return (1);
145218976Sdfr
145318976Sdfr	sfp = (struct nfsv3_fsinfo *)dp;
145426184Sfenner	TCHECK(*sfp);
145575118Sfenner	printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1456127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtmax),
1457127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtpref),
1458127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtmax),
1459127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtpref),
1460127675Sbms	       EXTRACT_32BITS(&sfp->fs_dtpref));
146118976Sdfr	if (vflag) {
1462146778Ssam		printf(" rtmult %u wtmult %u maxfsz %" PRIu64,
1463127675Sbms		       EXTRACT_32BITS(&sfp->fs_rtmult),
1464146778Ssam		       EXTRACT_32BITS(&sfp->fs_wtmult),
1465146778Ssam		       EXTRACT_64BITS((u_int32_t *)&sfp->fs_maxfilesize));
146675118Sfenner		printf(" delta %u.%06u ",
1467127675Sbms		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
1468127675Sbms		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec));
146918976Sdfr	}
1470111729Sfenner	return (1);
1471111729Sfennertrunc:
147275118Sfenner	return (0);
147318976Sdfr}
147418976Sdfr
147518976Sdfrstatic int
147618976Sdfrparsepathconf(const u_int32_t *dp)
147718976Sdfr{
147818976Sdfr	int er;
147918976Sdfr	struct nfsv3_pathconf *spp;
148018976Sdfr
148175118Sfenner	if (!(dp = parsestatus(dp, &er)))
148218976Sdfr		return (0);
148318976Sdfr	if (vflag)
148418976Sdfr		printf(" POST:");
148575118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
148618976Sdfr		return (0);
148718976Sdfr	if (er)
148818976Sdfr		return (1);
148918976Sdfr
149018976Sdfr	spp = (struct nfsv3_pathconf *)dp;
149126184Sfenner	TCHECK(*spp);
149218976Sdfr
149375118Sfenner	printf(" linkmax %u namemax %u %s %s %s %s",
1494127675Sbms	       EXTRACT_32BITS(&spp->pc_linkmax),
1495127675Sbms	       EXTRACT_32BITS(&spp->pc_namemax),
1496127675Sbms	       EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
1497127675Sbms	       EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
1498127675Sbms	       EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
1499127675Sbms	       EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : "");
1500111729Sfenner	return (1);
1501111729Sfennertrunc:
150275118Sfenner	return (0);
150317680Spst}
150475118Sfenner
150517680Spststatic void
1506146778Ssaminterp_reply(const struct sunrpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
150717680Spst{
150817680Spst	register const u_int32_t *dp;
150918976Sdfr	register int v3;
151018976Sdfr	int er;
151117680Spst
151218976Sdfr	v3 = (vers == NFS_VER3);
151318976Sdfr
151418976Sdfr	if (!v3 && proc < NFS_NPROCS)
151518976Sdfr		proc = nfsv3_procid[proc];
151618976Sdfr
151717680Spst	switch (proc) {
151817680Spst
151917680Spst	case NFSPROC_NOOP:
152017680Spst		printf(" nop");
152117680Spst		return;
152218976Sdfr
152317680Spst	case NFSPROC_NULL:
152417680Spst		printf(" null");
152517680Spst		return;
152617680Spst
152717680Spst	case NFSPROC_GETATTR:
152817680Spst		printf(" getattr");
152917680Spst		dp = parserep(rp, length);
153026183Sfenner		if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
153117680Spst			return;
153217680Spst		break;
153317680Spst
153417680Spst	case NFSPROC_SETATTR:
153517680Spst		printf(" setattr");
153675118Sfenner		if (!(dp = parserep(rp, length)))
153717680Spst			return;
153818976Sdfr		if (v3) {
153975118Sfenner			if (parsewccres(dp, vflag))
154018976Sdfr				return;
154118976Sdfr		} else {
154218976Sdfr			if (parseattrstat(dp, !qflag, 0) != 0)
154318976Sdfr				return;
154418976Sdfr		}
154517680Spst		break;
154617680Spst
154717680Spst	case NFSPROC_LOOKUP:
154817680Spst		printf(" lookup");
154975118Sfenner		if (!(dp = parserep(rp, length)))
155018976Sdfr			break;
155118976Sdfr		if (v3) {
155275118Sfenner			if (!(dp = parsestatus(dp, &er)))
155318976Sdfr				break;
155418976Sdfr			if (er) {
155518976Sdfr				if (vflag > 1) {
155618976Sdfr					printf(" post dattr:");
155718976Sdfr					dp = parse_post_op_attr(dp, vflag);
155818976Sdfr				}
155918976Sdfr			} else {
156075118Sfenner				if (!(dp = parsefh(dp, v3)))
156118976Sdfr					break;
156275118Sfenner				if ((dp = parse_post_op_attr(dp, vflag)) &&
156375118Sfenner				    vflag > 1) {
156418976Sdfr					printf(" post dattr:");
156518976Sdfr					dp = parse_post_op_attr(dp, vflag);
156618976Sdfr				}
156718976Sdfr			}
156875118Sfenner			if (dp)
156918976Sdfr				return;
157018976Sdfr		} else {
157118976Sdfr			if (parsediropres(dp) != 0)
157218976Sdfr				return;
157318976Sdfr		}
157417680Spst		break;
157517680Spst
157618976Sdfr	case NFSPROC_ACCESS:
157718976Sdfr		printf(" access");
157898527Sfenner		if (!(dp = parserep(rp, length)))
157998527Sfenner			break;
158075118Sfenner		if (!(dp = parsestatus(dp, &er)))
158118976Sdfr			break;
158218976Sdfr		if (vflag)
158318976Sdfr			printf(" attr:");
158475118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
158518976Sdfr			break;
158618976Sdfr		if (!er)
1587127675Sbms			printf(" c %04x", EXTRACT_32BITS(&dp[0]));
158818976Sdfr		return;
158918976Sdfr
159017680Spst	case NFSPROC_READLINK:
159117680Spst		printf(" readlink");
159217680Spst		dp = parserep(rp, length);
159326183Sfenner		if (dp != NULL && parselinkres(dp, v3) != 0)
159417680Spst			return;
159517680Spst		break;
159617680Spst
159717680Spst	case NFSPROC_READ:
159817680Spst		printf(" read");
159975118Sfenner		if (!(dp = parserep(rp, length)))
160018976Sdfr			break;
160118976Sdfr		if (v3) {
160275118Sfenner			if (!(dp = parsestatus(dp, &er)))
160318976Sdfr				break;
160475118Sfenner			if (!(dp = parse_post_op_attr(dp, vflag)))
160518976Sdfr				break;
160618976Sdfr			if (er)
160718976Sdfr				return;
160818976Sdfr			if (vflag) {
160975118Sfenner				TCHECK(dp[1]);
1610127675Sbms				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1611127675Sbms				if (EXTRACT_32BITS(&dp[1]))
161218976Sdfr					printf(" EOF");
161318976Sdfr			}
161417680Spst			return;
161518976Sdfr		} else {
161618976Sdfr			if (parseattrstat(dp, vflag, 0) != 0)
161718976Sdfr				return;
161818976Sdfr		}
161917680Spst		break;
162017680Spst
162117680Spst	case NFSPROC_WRITE:
162217680Spst		printf(" write");
162375118Sfenner		if (!(dp = parserep(rp, length)))
162418976Sdfr			break;
162518976Sdfr		if (v3) {
162675118Sfenner			if (!(dp = parsestatus(dp, &er)))
162718976Sdfr				break;
162875118Sfenner			if (!(dp = parse_wcc_data(dp, vflag)))
162918976Sdfr				break;
163018976Sdfr			if (er)
163118976Sdfr				return;
163218976Sdfr			if (vflag) {
163375118Sfenner				TCHECK(dp[0]);
1634127675Sbms				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
163518976Sdfr				if (vflag > 1) {
163675118Sfenner					TCHECK(dp[1]);
163718976Sdfr					printf(" <%s>",
163875118Sfenner						tok2str(nfsv3_writemodes,
1639127675Sbms							NULL, EXTRACT_32BITS(&dp[1])));
164018976Sdfr				}
164118976Sdfr				return;
164218976Sdfr			}
164318976Sdfr		} else {
164418976Sdfr			if (parseattrstat(dp, vflag, v3) != 0)
164518976Sdfr				return;
164618976Sdfr		}
164717680Spst		break;
164817680Spst
164917680Spst	case NFSPROC_CREATE:
165017680Spst		printf(" create");
165175118Sfenner		if (!(dp = parserep(rp, length)))
165218976Sdfr			break;
165318976Sdfr		if (v3) {
165475118Sfenner			if (parsecreateopres(dp, vflag) != 0)
165518976Sdfr				return;
165618976Sdfr		} else {
165718976Sdfr			if (parsediropres(dp) != 0)
165818976Sdfr				return;
165918976Sdfr		}
166018976Sdfr		break;
166118976Sdfr
166218976Sdfr	case NFSPROC_MKDIR:
166318976Sdfr		printf(" mkdir");
166475118Sfenner		if (!(dp = parserep(rp, length)))
166518976Sdfr			break;
166618976Sdfr		if (v3) {
166775118Sfenner			if (parsecreateopres(dp, vflag) != 0)
166818976Sdfr				return;
166918976Sdfr		} else {
167018976Sdfr			if (parsediropres(dp) != 0)
167118976Sdfr				return;
167218976Sdfr		}
167318976Sdfr		break;
167418976Sdfr
167518976Sdfr	case NFSPROC_SYMLINK:
167618976Sdfr		printf(" symlink");
167775118Sfenner		if (!(dp = parserep(rp, length)))
167818976Sdfr			break;
167918976Sdfr		if (v3) {
168075118Sfenner			if (parsecreateopres(dp, vflag) != 0)
168118976Sdfr				return;
168218976Sdfr		} else {
168375118Sfenner			if (parsestatus(dp, &er) != 0)
168418976Sdfr				return;
168518976Sdfr		}
168618976Sdfr		break;
168718976Sdfr
168818976Sdfr	case NFSPROC_MKNOD:
168918976Sdfr		printf(" mknod");
169075118Sfenner		if (!(dp = parserep(rp, length)))
169118976Sdfr			break;
169275118Sfenner		if (parsecreateopres(dp, vflag) != 0)
169317680Spst			return;
169417680Spst		break;
169517680Spst
169617680Spst	case NFSPROC_REMOVE:
169717680Spst		printf(" remove");
169875118Sfenner		if (!(dp = parserep(rp, length)))
169918976Sdfr			break;
170018976Sdfr		if (v3) {
170175118Sfenner			if (parsewccres(dp, vflag))
170218976Sdfr				return;
170318976Sdfr		} else {
170475118Sfenner			if (parsestatus(dp, &er) != 0)
170518976Sdfr				return;
170618976Sdfr		}
170717680Spst		break;
170817680Spst
170918976Sdfr	case NFSPROC_RMDIR:
171018976Sdfr		printf(" rmdir");
171175118Sfenner		if (!(dp = parserep(rp, length)))
171218976Sdfr			break;
171318976Sdfr		if (v3) {
171475118Sfenner			if (parsewccres(dp, vflag))
171518976Sdfr				return;
171618976Sdfr		} else {
171775118Sfenner			if (parsestatus(dp, &er) != 0)
171818976Sdfr				return;
171918976Sdfr		}
172018976Sdfr		break;
172118976Sdfr
172217680Spst	case NFSPROC_RENAME:
172317680Spst		printf(" rename");
172475118Sfenner		if (!(dp = parserep(rp, length)))
172518976Sdfr			break;
172618976Sdfr		if (v3) {
172775118Sfenner			if (!(dp = parsestatus(dp, &er)))
172818976Sdfr				break;
172918976Sdfr			if (vflag) {
173018976Sdfr				printf(" from:");
173175118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
173218976Sdfr					break;
173318976Sdfr				printf(" to:");
173475118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
173518976Sdfr					break;
173618976Sdfr			}
173717680Spst			return;
173818976Sdfr		} else {
173975118Sfenner			if (parsestatus(dp, &er) != 0)
174018976Sdfr				return;
174118976Sdfr		}
174217680Spst		break;
174317680Spst
174417680Spst	case NFSPROC_LINK:
174517680Spst		printf(" link");
174675118Sfenner		if (!(dp = parserep(rp, length)))
174718976Sdfr			break;
174818976Sdfr		if (v3) {
174975118Sfenner			if (!(dp = parsestatus(dp, &er)))
175018976Sdfr				break;
175118976Sdfr			if (vflag) {
175218976Sdfr				printf(" file POST:");
175375118Sfenner				if (!(dp = parse_post_op_attr(dp, vflag)))
175418976Sdfr					break;
175518976Sdfr				printf(" dir:");
175675118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
175718976Sdfr					break;
175818976Sdfr				return;
175918976Sdfr			}
176018976Sdfr		} else {
176175118Sfenner			if (parsestatus(dp, &er) != 0)
176218976Sdfr				return;
176318976Sdfr		}
176417680Spst		break;
176517680Spst
176618976Sdfr	case NFSPROC_READDIR:
176718976Sdfr		printf(" readdir");
176875118Sfenner		if (!(dp = parserep(rp, length)))
176918976Sdfr			break;
177018976Sdfr		if (v3) {
177175118Sfenner			if (parsev3rddirres(dp, vflag))
177218976Sdfr				return;
177318976Sdfr		} else {
177418976Sdfr			if (parserddires(dp) != 0)
177518976Sdfr				return;
177618976Sdfr		}
177718976Sdfr		break;
177818976Sdfr
177918976Sdfr	case NFSPROC_READDIRPLUS:
178018976Sdfr		printf(" readdirplus");
178175118Sfenner		if (!(dp = parserep(rp, length)))
178218976Sdfr			break;
178375118Sfenner		if (parsev3rddirres(dp, vflag))
178417680Spst			return;
178517680Spst		break;
178617680Spst
178718976Sdfr	case NFSPROC_FSSTAT:
178818976Sdfr		printf(" fsstat");
178917680Spst		dp = parserep(rp, length);
179075118Sfenner		if (dp != NULL && parsestatfs(dp, v3) != 0)
179117680Spst			return;
179217680Spst		break;
179317680Spst
179418976Sdfr	case NFSPROC_FSINFO:
179518976Sdfr		printf(" fsinfo");
179617680Spst		dp = parserep(rp, length);
179775118Sfenner		if (dp != NULL && parsefsinfo(dp) != 0)
179817680Spst			return;
179917680Spst		break;
180017680Spst
180118976Sdfr	case NFSPROC_PATHCONF:
180218976Sdfr		printf(" pathconf");
180317680Spst		dp = parserep(rp, length);
180426183Sfenner		if (dp != NULL && parsepathconf(dp) != 0)
180517680Spst			return;
180617680Spst		break;
180717680Spst
180818976Sdfr	case NFSPROC_COMMIT:
180918976Sdfr		printf(" commit");
181017680Spst		dp = parserep(rp, length);
181126183Sfenner		if (dp != NULL && parsewccres(dp, vflag) != 0)
181217680Spst			return;
181317680Spst		break;
181417680Spst
181517680Spst	default:
181626183Sfenner		printf(" proc-%u", proc);
181717680Spst		return;
181817680Spst	}
181918976Sdfrtrunc:
182026183Sfenner	if (!nfserr)
182126183Sfenner		fputs(" [|nfs]", stdout);
182217680Spst}
1823