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$
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.111 2007-12-22 03:08:04 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;
513214478Srpaulo	u_int32_t access_flags;
51418976Sdfr	struct nfsv3_sattr sa3;
51575118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
51617680Spst
51726183Sfenner	nfserr = 0;		/* assume no error */
518146778Ssam	rp = (const struct sunrpc_msg *)bp;
519190207Srpaulo
520190207Srpaulo	TCHECK(rp->rm_xid);
52175118Sfenner	if (!nflag) {
52275118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
523127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
52475118Sfenner		strlcpy(dstid, "nfs", sizeof(dstid));
52575118Sfenner	} else {
52675118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
527127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
52875118Sfenner		snprintf(dstid, sizeof(dstid), "%u", NFS_PORT);
52975118Sfenner	}
53075118Sfenner	print_nfsaddr(bp2, srcid, dstid);
53175118Sfenner	(void)printf("%d", length);
53217680Spst
533190207Srpaulo	if (!xid_map_enter(rp, bp2))	/* record proc number for later on */
534190207Srpaulo		goto trunc;
53517680Spst
536127675Sbms	v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
537127675Sbms	proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
53818976Sdfr
53918976Sdfr	if (!v3 && proc < NFS_NPROCS)
54018976Sdfr		proc =  nfsv3_procid[proc];
54118976Sdfr
54218976Sdfr	switch (proc) {
54317680Spst	case NFSPROC_NOOP:
54417680Spst		printf(" nop");
54517680Spst		return;
54617680Spst	case NFSPROC_NULL:
54717680Spst		printf(" null");
54817680Spst		return;
54917680Spst
55017680Spst	case NFSPROC_GETATTR:
55117680Spst		printf(" getattr");
55275118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
55375118Sfenner		    parsefh(dp, v3) != NULL)
55417680Spst			return;
55517680Spst		break;
55617680Spst
55717680Spst	case NFSPROC_SETATTR:
55817680Spst		printf(" setattr");
55975118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
56075118Sfenner		    parsefh(dp, v3) != NULL)
56117680Spst			return;
56217680Spst		break;
56317680Spst
56417680Spst	case NFSPROC_LOOKUP:
56517680Spst		printf(" lookup");
56675118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
56775118Sfenner		    parsefhn(dp, v3) != NULL)
56817680Spst			return;
56917680Spst		break;
57017680Spst
57118976Sdfr	case NFSPROC_ACCESS:
57218976Sdfr		printf(" access");
57326183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
57426183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
57575118Sfenner			TCHECK(dp[0]);
576214478Srpaulo			access_flags = EXTRACT_32BITS(&dp[0]);
577214478Srpaulo			if (access_flags & ~NFSV3ACCESS_FULL) {
578214478Srpaulo				/* NFSV3ACCESS definitions aren't up to date */
579214478Srpaulo				printf(" %04x", access_flags);
580214478Srpaulo			} else if ((access_flags & NFSV3ACCESS_FULL) == NFSV3ACCESS_FULL) {
581214478Srpaulo				printf(" NFS_ACCESS_FULL");
582214478Srpaulo			} else {
583214478Srpaulo				char separator = ' ';
584214478Srpaulo				if (access_flags & NFSV3ACCESS_READ) {
585214478Srpaulo					printf(" NFS_ACCESS_READ");
586214478Srpaulo					separator = '|';
587214478Srpaulo				}
588214478Srpaulo				if (access_flags & NFSV3ACCESS_LOOKUP) {
589214478Srpaulo					printf("%cNFS_ACCESS_LOOKUP", separator);
590214478Srpaulo					separator = '|';
591214478Srpaulo				}
592214478Srpaulo				if (access_flags & NFSV3ACCESS_MODIFY) {
593214478Srpaulo					printf("%cNFS_ACCESS_MODIFY", separator);
594214478Srpaulo					separator = '|';
595214478Srpaulo				}
596214478Srpaulo				if (access_flags & NFSV3ACCESS_EXTEND) {
597214478Srpaulo					printf("%cNFS_ACCESS_EXTEND", separator);
598214478Srpaulo					separator = '|';
599214478Srpaulo				}
600214478Srpaulo				if (access_flags & NFSV3ACCESS_DELETE) {
601214478Srpaulo					printf("%cNFS_ACCESS_DELETE", separator);
602214478Srpaulo					separator = '|';
603214478Srpaulo				}
604214478Srpaulo				if (access_flags & NFSV3ACCESS_EXECUTE)
605214478Srpaulo					printf("%cNFS_ACCESS_EXECUTE", separator);
606214478Srpaulo			}
60718976Sdfr			return;
60818976Sdfr		}
60918976Sdfr		break;
61018976Sdfr
61117680Spst	case NFSPROC_READLINK:
61217680Spst		printf(" readlink");
61375118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
61475118Sfenner		    parsefh(dp, v3) != NULL)
61517680Spst			return;
61617680Spst		break;
61717680Spst
61817680Spst	case NFSPROC_READ:
61917680Spst		printf(" read");
62026183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
62126183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
62218976Sdfr			if (v3) {
62375118Sfenner				TCHECK(dp[2]);
624146778Ssam				printf(" %u bytes @ %" PRIu64,
625146778Ssam				       EXTRACT_32BITS(&dp[2]),
626146778Ssam				       EXTRACT_64BITS(&dp[0]));
62718976Sdfr			} else {
62875118Sfenner				TCHECK(dp[1]);
62975118Sfenner				printf(" %u bytes @ %u",
630127675Sbms				    EXTRACT_32BITS(&dp[1]),
631127675Sbms				    EXTRACT_32BITS(&dp[0]));
63218976Sdfr			}
63317680Spst			return;
63417680Spst		}
63517680Spst		break;
63617680Spst
63717680Spst	case NFSPROC_WRITE:
63817680Spst		printf(" write");
63926183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
64026183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
64118976Sdfr			if (v3) {
642146778Ssam				TCHECK(dp[2]);
643146778Ssam				printf(" %u (%u) bytes @ %" PRIu64,
644146778Ssam						EXTRACT_32BITS(&dp[4]),
645146778Ssam						EXTRACT_32BITS(&dp[2]),
646146778Ssam						EXTRACT_64BITS(&dp[0]));
64718976Sdfr				if (vflag) {
64818976Sdfr					dp += 3;
64975118Sfenner					TCHECK(dp[0]);
65018976Sdfr					printf(" <%s>",
65175118Sfenner						tok2str(nfsv3_writemodes,
652127675Sbms							NULL, EXTRACT_32BITS(dp)));
65318976Sdfr				}
65418976Sdfr			} else {
65575118Sfenner				TCHECK(dp[3]);
65675118Sfenner				printf(" %u (%u) bytes @ %u (%u)",
657127675Sbms						EXTRACT_32BITS(&dp[3]),
658127675Sbms						EXTRACT_32BITS(&dp[2]),
659127675Sbms						EXTRACT_32BITS(&dp[1]),
660127675Sbms						EXTRACT_32BITS(&dp[0]));
66118976Sdfr			}
66217680Spst			return;
66317680Spst		}
66417680Spst		break;
66517680Spst
66617680Spst	case NFSPROC_CREATE:
66717680Spst		printf(" create");
66875118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
66975118Sfenner		    parsefhn(dp, v3) != NULL)
67017680Spst			return;
67117680Spst		break;
67217680Spst
67318976Sdfr	case NFSPROC_MKDIR:
67418976Sdfr		printf(" mkdir");
67575118Sfenner		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
67618976Sdfr			return;
67718976Sdfr		break;
67818976Sdfr
67918976Sdfr	case NFSPROC_SYMLINK:
68018976Sdfr		printf(" symlink");
68175118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
68275118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
68375118Sfenner			fputs(" ->", stdout);
68475118Sfenner			if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
68518976Sdfr				break;
68675118Sfenner			if (parsefn(dp) == 0)
68718976Sdfr				break;
68818976Sdfr			if (v3 && vflag)
68918976Sdfr				print_sattr3(&sa3, vflag);
69018976Sdfr			return;
69118976Sdfr		}
69218976Sdfr		break;
69318976Sdfr
69418976Sdfr	case NFSPROC_MKNOD:
69518976Sdfr		printf(" mknod");
69675118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
69775118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
69875118Sfenner			TCHECK(*dp);
699127675Sbms			type = (nfs_type)EXTRACT_32BITS(dp);
700127675Sbms			dp++;
70175118Sfenner			if ((dp = parse_sattr3(dp, &sa3)) == 0)
70218976Sdfr				break;
70318976Sdfr			printf(" %s", tok2str(type2str, "unk-ft %d", type));
70418976Sdfr			if (vflag && (type == NFCHR || type == NFBLK)) {
70575118Sfenner				TCHECK(dp[1]);
70675118Sfenner				printf(" %u/%u",
707127675Sbms				       EXTRACT_32BITS(&dp[0]),
708127675Sbms				       EXTRACT_32BITS(&dp[1]));
70918976Sdfr				dp += 2;
71018976Sdfr			}
71118976Sdfr			if (vflag)
71218976Sdfr				print_sattr3(&sa3, vflag);
71318976Sdfr			return;
71418976Sdfr		}
71518976Sdfr		break;
71618976Sdfr
71717680Spst	case NFSPROC_REMOVE:
71817680Spst		printf(" remove");
71975118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
72075118Sfenner		    parsefhn(dp, v3) != NULL)
72117680Spst			return;
72217680Spst		break;
72317680Spst
72418976Sdfr	case NFSPROC_RMDIR:
72518976Sdfr		printf(" rmdir");
72675118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
72775118Sfenner		    parsefhn(dp, v3) != NULL)
72818976Sdfr			return;
72918976Sdfr		break;
73018976Sdfr
73117680Spst	case NFSPROC_RENAME:
73217680Spst		printf(" rename");
73326183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
73426183Sfenner		    (dp = parsefhn(dp, v3)) != NULL) {
73517680Spst			fputs(" ->", stdout);
73626183Sfenner			if (parsefhn(dp, v3) != NULL)
73717680Spst				return;
73817680Spst		}
73917680Spst		break;
74017680Spst
74117680Spst	case NFSPROC_LINK:
74217680Spst		printf(" link");
74326183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
74426183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
74517680Spst			fputs(" ->", stdout);
74626183Sfenner			if (parsefhn(dp, v3) != NULL)
74717680Spst				return;
74817680Spst		}
74917680Spst		break;
75017680Spst
75118976Sdfr	case NFSPROC_READDIR:
75218976Sdfr		printf(" readdir");
75326183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
75426183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
75518976Sdfr			if (v3) {
75675118Sfenner				TCHECK(dp[4]);
75718976Sdfr				/*
75818976Sdfr				 * We shouldn't really try to interpret the
75918976Sdfr				 * offset cookie here.
76018976Sdfr				 */
761146778Ssam				printf(" %u bytes @ %" PRId64,
762146778Ssam				    EXTRACT_32BITS(&dp[4]),
763146778Ssam				    EXTRACT_64BITS(&dp[0]));
76418976Sdfr				if (vflag)
76526183Sfenner					printf(" verf %08x%08x", dp[2],
76618976Sdfr					       dp[3]);
76718976Sdfr			} else {
76875118Sfenner				TCHECK(dp[1]);
76918976Sdfr				/*
77018976Sdfr				 * Print the offset as signed, since -1 is
77118976Sdfr				 * common, but offsets > 2^31 aren't.
77218976Sdfr				 */
77375118Sfenner				printf(" %u bytes @ %d",
774127675Sbms				    EXTRACT_32BITS(&dp[1]),
775127675Sbms				    EXTRACT_32BITS(&dp[0]));
77618976Sdfr			}
77718976Sdfr			return;
77817680Spst		}
77917680Spst		break;
78017680Spst
78118976Sdfr	case NFSPROC_READDIRPLUS:
78218976Sdfr		printf(" readdirplus");
78326183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
78426183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
78575118Sfenner			TCHECK(dp[4]);
78618976Sdfr			/*
78718976Sdfr			 * We don't try to interpret the offset
78818976Sdfr			 * cookie here.
78918976Sdfr			 */
790146778Ssam			printf(" %u bytes @ %" PRId64,
791146778Ssam				EXTRACT_32BITS(&dp[4]),
792146778Ssam				EXTRACT_64BITS(&dp[0]));
793146778Ssam			if (vflag) {
794146778Ssam				TCHECK(dp[5]);
79575118Sfenner				printf(" max %u verf %08x%08x",
796127675Sbms				       EXTRACT_32BITS(&dp[5]), dp[2], dp[3]);
797146778Ssam			}
79817680Spst			return;
79918976Sdfr		}
80017680Spst		break;
80117680Spst
80218976Sdfr	case NFSPROC_FSSTAT:
80318976Sdfr		printf(" fsstat");
80475118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
80575118Sfenner		    parsefh(dp, v3) != NULL)
80617680Spst			return;
80717680Spst		break;
80817680Spst
80918976Sdfr	case NFSPROC_FSINFO:
81018976Sdfr		printf(" fsinfo");
811111729Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
812111729Sfenner		    parsefh(dp, v3) != NULL)
813111729Sfenner			return;
81418976Sdfr		break;
81518976Sdfr
81618976Sdfr	case NFSPROC_PATHCONF:
81718976Sdfr		printf(" pathconf");
818111729Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
819111729Sfenner		    parsefh(dp, v3) != NULL)
820111729Sfenner			return;
82118976Sdfr		break;
82218976Sdfr
82318976Sdfr	case NFSPROC_COMMIT:
82418976Sdfr		printf(" commit");
82526183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
82626183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
827146778Ssam			TCHECK(dp[2]);
828146778Ssam			printf(" %u bytes @ %" PRIu64,
829146778Ssam				EXTRACT_32BITS(&dp[2]),
830146778Ssam				EXTRACT_64BITS(&dp[0]));
83117680Spst			return;
83217680Spst		}
83317680Spst		break;
83417680Spst
83517680Spst	default:
836127675Sbms		printf(" proc-%u", EXTRACT_32BITS(&rp->rm_call.cb_proc));
83717680Spst		return;
83817680Spst	}
83975118Sfenner
84017680Spsttrunc:
84126183Sfenner	if (!nfserr)
84226183Sfenner		fputs(" [|nfs]", stdout);
84317680Spst}
84417680Spst
84517680Spst/*
84617680Spst * Print out an NFS file handle.
84717680Spst * We assume packet was not truncated before the end of the
84817680Spst * file handle pointed to by dp.
84917680Spst *
85017680Spst * Note: new version (using portable file-handle parser) doesn't produce
85117680Spst * generation number.  It probably could be made to do that, with some
85217680Spst * additional hacking on the parser code.
85317680Spst */
85417680Spststatic void
85575118Sfennernfs_printfh(register const u_int32_t *dp, const u_int len)
85617680Spst{
85717680Spst	my_fsid fsid;
85817680Spst	ino_t ino;
859127675Sbms	const char *sfsname = NULL;
860127675Sbms	char *spacep;
86117680Spst
862127675Sbms	if (uflag) {
863127675Sbms		u_int i;
864127675Sbms		char const *sep = "";
86517680Spst
866127675Sbms		printf(" fh[");
867127675Sbms		for (i=0; i<len; i++) {
868127675Sbms			(void)printf("%s%x", sep, dp[i]);
869127675Sbms			sep = ":";
870127675Sbms		}
871127675Sbms		printf("]");
872127675Sbms		return;
873127675Sbms	}
874127675Sbms
875127675Sbms	Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
876127675Sbms
87717680Spst	if (sfsname) {
87826183Sfenner		/* file system ID is ASCII, not numeric, for this server OS */
87926183Sfenner		static char temp[NFSX_V3FHMAX+1];
88017680Spst
88126183Sfenner		/* Make sure string is null-terminated */
88226183Sfenner		strncpy(temp, sfsname, NFSX_V3FHMAX);
88375118Sfenner		temp[sizeof(temp) - 1] = '\0';
88426183Sfenner		/* Remove trailing spaces */
885127675Sbms		spacep = strchr(temp, ' ');
886127675Sbms		if (spacep)
887127675Sbms			*spacep = '\0';
88817680Spst
88975118Sfenner		(void)printf(" fh %s/", temp);
89026183Sfenner	} else {
89175118Sfenner		(void)printf(" fh %d,%d/",
89275118Sfenner			     fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor);
89317680Spst	}
89475118Sfenner
895127675Sbms	if(fsid.Fsid_dev.Minor == 257)
896127675Sbms		/* Print the undecoded handle */
89775118Sfenner		(void)printf("%s", fsid.Opaque_Handle);
89875118Sfenner	else
89975118Sfenner		(void)printf("%ld", (long) ino);
90017680Spst}
90117680Spst
90217680Spst/*
90317680Spst * Maintain a small cache of recent client.XID.server/proc pairs, to allow
90417680Spst * us to match up replies with requests and thus to know how to parse
90517680Spst * the reply.
90617680Spst */
90717680Spst
90817680Spststruct xid_map_entry {
90975118Sfenner	u_int32_t	xid;		/* transaction ID (net order) */
91075118Sfenner	int ipver;			/* IP version (4 or 6) */
91175118Sfenner#ifdef INET6
91275118Sfenner	struct in6_addr	client;		/* client IP address (net order) */
91375118Sfenner	struct in6_addr	server;		/* server IP address (net order) */
91475118Sfenner#else
91517680Spst	struct in_addr	client;		/* client IP address (net order) */
91617680Spst	struct in_addr	server;		/* server IP address (net order) */
91775118Sfenner#endif
91875118Sfenner	u_int32_t	proc;		/* call proc number (host order) */
91975118Sfenner	u_int32_t	vers;		/* program version (host order) */
92017680Spst};
92117680Spst
92217680Spst/*
92317680Spst * Map entries are kept in an array that we manage as a ring;
92417680Spst * new entries are always added at the tail of the ring.  Initially,
92517680Spst * all the entries are zero and hence don't match anything.
92617680Spst */
92717680Spst
92817680Spst#define	XIDMAPSIZE	64
92917680Spst
93017680Spststruct xid_map_entry xid_map[XIDMAPSIZE];
93117680Spst
93217680Spstint	xid_map_next = 0;
93317680Spstint	xid_map_hint = 0;
93417680Spst
935190207Srpaulostatic int
936146778Ssamxid_map_enter(const struct sunrpc_msg *rp, const u_char *bp)
93717680Spst{
93875118Sfenner	struct ip *ip = NULL;
93975118Sfenner#ifdef INET6
94075118Sfenner	struct ip6_hdr *ip6 = NULL;
94175118Sfenner#endif
94217680Spst	struct xid_map_entry *xmep;
94317680Spst
944190207Srpaulo	if (!TTEST(rp->rm_call.cb_vers))
945190207Srpaulo		return (0);
94675118Sfenner	switch (IP_V((struct ip *)bp)) {
94775118Sfenner	case 4:
94875118Sfenner		ip = (struct ip *)bp;
94975118Sfenner		break;
95075118Sfenner#ifdef INET6
95175118Sfenner	case 6:
95275118Sfenner		ip6 = (struct ip6_hdr *)bp;
95375118Sfenner		break;
95475118Sfenner#endif
95575118Sfenner	default:
956190207Srpaulo		return (1);
95775118Sfenner	}
95875118Sfenner
95917680Spst	xmep = &xid_map[xid_map_next];
96017680Spst
96117680Spst	if (++xid_map_next >= XIDMAPSIZE)
96217680Spst		xid_map_next = 0;
96317680Spst
96417680Spst	xmep->xid = rp->rm_xid;
96575118Sfenner	if (ip) {
96675118Sfenner		xmep->ipver = 4;
96775118Sfenner		memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
96875118Sfenner		memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
96975118Sfenner	}
97075118Sfenner#ifdef INET6
97175118Sfenner	else if (ip6) {
97275118Sfenner		xmep->ipver = 6;
97375118Sfenner		memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
97475118Sfenner		memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
97575118Sfenner	}
97675118Sfenner#endif
977127675Sbms	xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
978127675Sbms	xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
979190207Srpaulo	return (1);
98017680Spst}
98117680Spst
98226183Sfenner/*
98326183Sfenner * Returns 0 and puts NFSPROC_xxx in proc return and
98426183Sfenner * version in vers return, or returns -1 on failure
98526183Sfenner */
98618976Sdfrstatic int
987146778Ssamxid_map_find(const struct sunrpc_msg *rp, const u_char *bp, u_int32_t *proc,
98818976Sdfr	     u_int32_t *vers)
98917680Spst{
99017680Spst	int i;
99117680Spst	struct xid_map_entry *xmep;
99217680Spst	u_int32_t xid = rp->rm_xid;
99375118Sfenner	struct ip *ip = (struct ip *)bp;
99475118Sfenner#ifdef INET6
99575118Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
99675118Sfenner#endif
99775118Sfenner	int cmp;
99817680Spst
99917680Spst	/* Start searching from where we last left off */
1000127675Sbms	i = xid_map_hint;
100117680Spst	do {
100217680Spst		xmep = &xid_map[i];
100375118Sfenner		cmp = 1;
100475118Sfenner		if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
100575118Sfenner			goto nextitem;
100675118Sfenner		switch (xmep->ipver) {
100775118Sfenner		case 4:
100875118Sfenner			if (memcmp(&ip->ip_src, &xmep->server,
100975118Sfenner				   sizeof(ip->ip_src)) != 0 ||
101075118Sfenner			    memcmp(&ip->ip_dst, &xmep->client,
101175118Sfenner				   sizeof(ip->ip_dst)) != 0) {
101275118Sfenner				cmp = 0;
101375118Sfenner			}
101475118Sfenner			break;
101575118Sfenner#ifdef INET6
101675118Sfenner		case 6:
101775118Sfenner			if (memcmp(&ip6->ip6_src, &xmep->server,
101875118Sfenner				   sizeof(ip6->ip6_src)) != 0 ||
101975118Sfenner			    memcmp(&ip6->ip6_dst, &xmep->client,
102075118Sfenner				   sizeof(ip6->ip6_dst)) != 0) {
102175118Sfenner				cmp = 0;
102275118Sfenner			}
102375118Sfenner			break;
102475118Sfenner#endif
102575118Sfenner		default:
102675118Sfenner			cmp = 0;
102775118Sfenner			break;
102875118Sfenner		}
102975118Sfenner		if (cmp) {
103017680Spst			/* match */
103117680Spst			xid_map_hint = i;
103218976Sdfr			*proc = xmep->proc;
103318976Sdfr			*vers = xmep->vers;
103418976Sdfr			return 0;
103517680Spst		}
103675118Sfenner	nextitem:
103717680Spst		if (++i >= XIDMAPSIZE)
103817680Spst			i = 0;
103917680Spst	} while (i != xid_map_hint);
104017680Spst
104117680Spst	/* search failed */
104275118Sfenner	return (-1);
104317680Spst}
104417680Spst
104517680Spst/*
104617680Spst * Routines for parsing reply packets
104717680Spst */
104817680Spst
104917680Spst/*
105017680Spst * Return a pointer to the beginning of the actual results.
105175118Sfenner * If the packet was truncated, return 0.
105217680Spst */
105317680Spststatic const u_int32_t *
1054146778Ssamparserep(register const struct sunrpc_msg *rp, register u_int length)
105517680Spst{
105617680Spst	register const u_int32_t *dp;
105775118Sfenner	u_int len;
1058146778Ssam	enum sunrpc_accept_stat astat;
105917680Spst
106017680Spst	/*
106117680Spst	 * Portability note:
106217680Spst	 * Here we find the address of the ar_verf credentials.
106317680Spst	 * Originally, this calculation was
106417680Spst	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
106517680Spst	 * On the wire, the rp_acpt field starts immediately after
106617680Spst	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
106717680Spst	 * "struct accepted_reply") contains a "struct opaque_auth",
106817680Spst	 * whose internal representation contains a pointer, so on a
106917680Spst	 * 64-bit machine the compiler inserts 32 bits of padding
107017680Spst	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
107117680Spst	 * the internal representation to parse the on-the-wire
107217680Spst	 * representation.  Instead, we skip past the rp_stat field,
107317680Spst	 * which is an "enum" and so occupies one 32-bit word.
107417680Spst	 */
107517680Spst	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
107675118Sfenner	TCHECK(dp[1]);
1077127675Sbms	len = EXTRACT_32BITS(&dp[1]);
107817680Spst	if (len >= length)
107926183Sfenner		return (NULL);
108017680Spst	/*
108117680Spst	 * skip past the ar_verf credentials.
108217680Spst	 */
108317680Spst	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
108426183Sfenner	TCHECK2(dp[0], 0);
108517680Spst
108617680Spst	/*
108717680Spst	 * now we can check the ar_stat field
108817680Spst	 */
1089147904Ssam	astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
109017680Spst	switch (astat) {
109117680Spst
1092146778Ssam	case SUNRPC_SUCCESS:
109317680Spst		break;
109417680Spst
1095146778Ssam	case SUNRPC_PROG_UNAVAIL:
109617680Spst		printf(" PROG_UNAVAIL");
109726183Sfenner		nfserr = 1;		/* suppress trunc string */
109826183Sfenner		return (NULL);
109917680Spst
1100146778Ssam	case SUNRPC_PROG_MISMATCH:
110117680Spst		printf(" PROG_MISMATCH");
110226183Sfenner		nfserr = 1;		/* suppress trunc string */
110326183Sfenner		return (NULL);
110417680Spst
1105146778Ssam	case SUNRPC_PROC_UNAVAIL:
110617680Spst		printf(" PROC_UNAVAIL");
110726183Sfenner		nfserr = 1;		/* suppress trunc string */
110826183Sfenner		return (NULL);
110917680Spst
1110146778Ssam	case SUNRPC_GARBAGE_ARGS:
111117680Spst		printf(" GARBAGE_ARGS");
111226183Sfenner		nfserr = 1;		/* suppress trunc string */
111326183Sfenner		return (NULL);
111417680Spst
1115146778Ssam	case SUNRPC_SYSTEM_ERR:
111617680Spst		printf(" SYSTEM_ERR");
111726183Sfenner		nfserr = 1;		/* suppress trunc string */
111826183Sfenner		return (NULL);
111917680Spst
112017680Spst	default:
112117680Spst		printf(" ar_stat %d", astat);
112226183Sfenner		nfserr = 1;		/* suppress trunc string */
112326183Sfenner		return (NULL);
112417680Spst	}
112517680Spst	/* successful return */
112675118Sfenner	TCHECK2(*dp, sizeof(astat));
112775118Sfenner	return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
112826183Sfennertrunc:
112975118Sfenner	return (0);
113017680Spst}
113117680Spst
113217680Spststatic const u_int32_t *
113318976Sdfrparsestatus(const u_int32_t *dp, int *er)
113417680Spst{
113575118Sfenner	int errnum;
113617680Spst
113726183Sfenner	TCHECK(dp[0]);
113875118Sfenner
1139127675Sbms	errnum = EXTRACT_32BITS(&dp[0]);
114018976Sdfr	if (er)
114126183Sfenner		*er = errnum;
114226183Sfenner	if (errnum != 0) {
114326183Sfenner		if (!qflag)
114475118Sfenner			printf(" ERROR: %s",
114575118Sfenner			    tok2str(status2str, "unk %d", errnum));
114626183Sfenner		nfserr = 1;
114717680Spst	}
114817680Spst	return (dp + 1);
114926183Sfennertrunc:
115075118Sfenner	return NULL;
115117680Spst}
115217680Spst
115317680Spststatic const u_int32_t *
115418976Sdfrparsefattr(const u_int32_t *dp, int verbose, int v3)
115517680Spst{
115618976Sdfr	const struct nfs_fattr *fap;
115717680Spst
115818976Sdfr	fap = (const struct nfs_fattr *)dp;
115926184Sfenner	TCHECK(fap->fa_gid);
116017680Spst	if (verbose) {
116175118Sfenner		printf(" %s %o ids %d/%d",
116275118Sfenner		    tok2str(type2str, "unk-ft %d ",
1163127675Sbms		    EXTRACT_32BITS(&fap->fa_type)),
1164127675Sbms		    EXTRACT_32BITS(&fap->fa_mode),
1165127675Sbms		    EXTRACT_32BITS(&fap->fa_uid),
1166127675Sbms		    EXTRACT_32BITS(&fap->fa_gid));
116718976Sdfr		if (v3) {
116826184Sfenner			TCHECK(fap->fa3_size);
1169146778Ssam			printf(" sz %" PRIu64,
1170146778Ssam				EXTRACT_64BITS((u_int32_t *)&fap->fa3_size));
117126184Sfenner		} else {
117226184Sfenner			TCHECK(fap->fa2_size);
1173127675Sbms			printf(" sz %d", EXTRACT_32BITS(&fap->fa2_size));
117418976Sdfr		}
117517680Spst	}
117617680Spst	/* print lots more stuff */
117717680Spst	if (verbose > 1) {
117818976Sdfr		if (v3) {
117926184Sfenner			TCHECK(fap->fa3_ctime);
1180127675Sbms			printf(" nlink %d rdev %d/%d",
1181127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1182127675Sbms			       EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
1183127675Sbms			       EXTRACT_32BITS(&fap->fa3_rdev.specdata2));
1184146778Ssam			printf(" fsid %" PRIx64,
1185146778Ssam				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fsid));
1186146778Ssam			printf(" fileid %" PRIx64,
1187146778Ssam				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fileid));
1188127675Sbms			printf(" a/m/ctime %u.%06u",
1189127675Sbms			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
1190127675Sbms			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec));
1191127675Sbms			printf(" %u.%06u",
1192127675Sbms			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
1193127675Sbms			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec));
1194127675Sbms			printf(" %u.%06u",
1195127675Sbms			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
1196127675Sbms			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec));
119718976Sdfr		} else {
119826184Sfenner			TCHECK(fap->fa2_ctime);
1199127675Sbms			printf(" nlink %d rdev %x fsid %x nodeid %x a/m/ctime",
1200127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1201127675Sbms			       EXTRACT_32BITS(&fap->fa2_rdev),
1202127675Sbms			       EXTRACT_32BITS(&fap->fa2_fsid),
1203127675Sbms			       EXTRACT_32BITS(&fap->fa2_fileid));
1204127675Sbms			printf(" %u.%06u",
1205127675Sbms			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
1206127675Sbms			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec));
1207127675Sbms			printf(" %u.%06u",
1208127675Sbms			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
1209127675Sbms			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec));
1210127675Sbms			printf(" %u.%06u",
1211127675Sbms			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
1212127675Sbms			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec));
121318976Sdfr		}
121417680Spst	}
121518976Sdfr	return ((const u_int32_t *)((unsigned char *)dp +
121618976Sdfr		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
121726184Sfennertrunc:
121826184Sfenner	return (NULL);
121917680Spst}
122017680Spst
122117680Spststatic int
122218976Sdfrparseattrstat(const u_int32_t *dp, int verbose, 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);
123117680Spst
123226183Sfenner	return (parsefattr(dp, verbose, v3) != NULL);
123317680Spst}
123417680Spst
123517680Spststatic int
123617680Spstparsediropres(const u_int32_t *dp)
123717680Spst{
123818976Sdfr	int er;
123918976Sdfr
1240111729Sfenner	if (!(dp = parsestatus(dp, &er)))
124117680Spst		return (0);
1242111729Sfenner	if (er)
1243111729Sfenner		return (1);
124417680Spst
124518976Sdfr	dp = parsefh(dp, 0);
124617680Spst	if (dp == NULL)
124717680Spst		return (0);
124817680Spst
124918976Sdfr	return (parsefattr(dp, vflag, 0) != NULL);
125017680Spst}
125117680Spst
125217680Spststatic int
125318976Sdfrparselinkres(const u_int32_t *dp, int v3)
125417680Spst{
125518976Sdfr	int er;
125618976Sdfr
125718976Sdfr	dp = parsestatus(dp, &er);
1258111729Sfenner	if (dp == NULL)
125917680Spst		return(0);
1260111729Sfenner	if (er)
1261111729Sfenner		return(1);
126275118Sfenner	if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
126318976Sdfr		return (0);
126417680Spst	putchar(' ');
126517680Spst	return (parsefn(dp) != NULL);
126617680Spst}
126717680Spst
126817680Spststatic int
126918976Sdfrparsestatfs(const u_int32_t *dp, int v3)
127017680Spst{
127118976Sdfr	const struct nfs_statfs *sfsp;
127218976Sdfr	int er;
127317680Spst
127418976Sdfr	dp = parsestatus(dp, &er);
1275111729Sfenner	if (dp == NULL)
127675118Sfenner		return (0);
1277111729Sfenner	if (!v3 && er)
1278111729Sfenner		return (1);
127917680Spst
128018976Sdfr	if (qflag)
128118976Sdfr		return(1);
128218976Sdfr
128318976Sdfr	if (v3) {
128418976Sdfr		if (vflag)
128518976Sdfr			printf(" POST:");
128675118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
128718976Sdfr			return (0);
128817680Spst	}
128917680Spst
1290111729Sfenner	TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
129118976Sdfr
129218976Sdfr	sfsp = (const struct nfs_statfs *)dp;
129318976Sdfr
129418976Sdfr	if (v3) {
1295146778Ssam		printf(" tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
1296146778Ssam			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tbytes),
1297146778Ssam			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_fbytes),
1298146778Ssam			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_abytes));
129918976Sdfr		if (vflag) {
1300146778Ssam			printf(" tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
1301146778Ssam			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tfiles),
1302146778Ssam			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_ffiles),
1303146778Ssam			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_afiles),
1304127675Sbms			       EXTRACT_32BITS(&sfsp->sf_invarsec));
130518976Sdfr		}
130618976Sdfr	} else {
130775118Sfenner		printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
1308127675Sbms			EXTRACT_32BITS(&sfsp->sf_tsize),
1309127675Sbms			EXTRACT_32BITS(&sfsp->sf_bsize),
1310127675Sbms			EXTRACT_32BITS(&sfsp->sf_blocks),
1311127675Sbms			EXTRACT_32BITS(&sfsp->sf_bfree),
1312127675Sbms			EXTRACT_32BITS(&sfsp->sf_bavail));
131318976Sdfr	}
131418976Sdfr
131517680Spst	return (1);
131626184Sfennertrunc:
131726184Sfenner	return (0);
131817680Spst}
131917680Spst
132017680Spststatic int
132117680Spstparserddires(const u_int32_t *dp)
132217680Spst{
132318976Sdfr	int er;
132418976Sdfr
132518976Sdfr	dp = parsestatus(dp, &er);
1326111729Sfenner	if (dp == NULL)
132717680Spst		return (0);
1328111729Sfenner	if (er)
1329111729Sfenner		return (1);
133018976Sdfr	if (qflag)
133118976Sdfr		return (1);
133218976Sdfr
133326184Sfenner	TCHECK(dp[2]);
133475118Sfenner	printf(" offset %x size %d ",
1335127675Sbms	       EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1]));
133618976Sdfr	if (dp[2] != 0)
133775118Sfenner		printf(" eof");
133818976Sdfr
133918976Sdfr	return (1);
134026184Sfennertrunc:
134126184Sfenner	return (0);
134218976Sdfr}
134318976Sdfr
134418976Sdfrstatic const u_int32_t *
134518976Sdfrparse_wcc_attr(const u_int32_t *dp)
134618976Sdfr{
1347146778Ssam	printf(" sz %" PRIu64, EXTRACT_64BITS(&dp[0]));
134875118Sfenner	printf(" mtime %u.%06u ctime %u.%06u",
1349127675Sbms	       EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
1350127675Sbms	       EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5]));
135118976Sdfr	return (dp + 6);
135218976Sdfr}
135318976Sdfr
135418976Sdfr/*
135518976Sdfr * Pre operation attributes. Print only if vflag > 1.
135618976Sdfr */
135718976Sdfrstatic const u_int32_t *
135818976Sdfrparse_pre_op_attr(const u_int32_t *dp, int verbose)
135918976Sdfr{
136026184Sfenner	TCHECK(dp[0]);
1361127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
136218976Sdfr		return (dp + 1);
136318976Sdfr	dp++;
1364111729Sfenner	TCHECK2(*dp, 24);
136518976Sdfr	if (verbose > 1) {
136618976Sdfr		return parse_wcc_attr(dp);
136718976Sdfr	} else {
136818976Sdfr		/* If not verbose enough, just skip over wcc_attr */
136918976Sdfr		return (dp + 6);
137017680Spst	}
137126184Sfennertrunc:
137226184Sfenner	return (NULL);
137318976Sdfr}
137417680Spst
137518976Sdfr/*
137618976Sdfr * Post operation attributes are printed if vflag >= 1
137718976Sdfr */
137818976Sdfrstatic const u_int32_t *
137918976Sdfrparse_post_op_attr(const u_int32_t *dp, int verbose)
138018976Sdfr{
138126184Sfenner	TCHECK(dp[0]);
1382127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
138318976Sdfr		return (dp + 1);
138418976Sdfr	dp++;
138518976Sdfr	if (verbose) {
138618976Sdfr		return parsefattr(dp, verbose, 1);
138718976Sdfr	} else
138818976Sdfr		return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
138926184Sfennertrunc:
139026184Sfenner	return (NULL);
139118976Sdfr}
139218976Sdfr
139318976Sdfrstatic const u_int32_t *
139418976Sdfrparse_wcc_data(const u_int32_t *dp, int verbose)
139518976Sdfr{
139618976Sdfr	if (verbose > 1)
139718976Sdfr		printf(" PRE:");
139875118Sfenner	if (!(dp = parse_pre_op_attr(dp, verbose)))
139975118Sfenner		return (0);
140018976Sdfr
140118976Sdfr	if (verbose)
140218976Sdfr		printf(" POST:");
140318976Sdfr	return parse_post_op_attr(dp, verbose);
140418976Sdfr}
140518976Sdfr
140618976Sdfrstatic const u_int32_t *
140718976Sdfrparsecreateopres(const u_int32_t *dp, int verbose)
140818976Sdfr{
140918976Sdfr	int er;
141018976Sdfr
141175118Sfenner	if (!(dp = parsestatus(dp, &er)))
141275118Sfenner		return (0);
141318976Sdfr	if (er)
141418976Sdfr		dp = parse_wcc_data(dp, verbose);
141518976Sdfr	else {
141626184Sfenner		TCHECK(dp[0]);
1417127675Sbms		if (!EXTRACT_32BITS(&dp[0]))
141818976Sdfr			return (dp + 1);
141918976Sdfr		dp++;
142075118Sfenner		if (!(dp = parsefh(dp, 1)))
142175118Sfenner			return (0);
142218976Sdfr		if (verbose) {
142375118Sfenner			if (!(dp = parse_post_op_attr(dp, verbose)))
142475118Sfenner				return (0);
142518976Sdfr			if (vflag > 1) {
1426127675Sbms				printf(" dir attr:");
142718976Sdfr				dp = parse_wcc_data(dp, verbose);
142818976Sdfr			}
142918976Sdfr		}
143018976Sdfr	}
143118976Sdfr	return (dp);
143226184Sfennertrunc:
143326184Sfenner	return (NULL);
143418976Sdfr}
143518976Sdfr
143618976Sdfrstatic int
143718976Sdfrparsewccres(const u_int32_t *dp, int verbose)
143818976Sdfr{
143918976Sdfr	int er;
144018976Sdfr
144175118Sfenner	if (!(dp = parsestatus(dp, &er)))
144218976Sdfr		return (0);
144375118Sfenner	return parse_wcc_data(dp, verbose) != 0;
144418976Sdfr}
144518976Sdfr
144618976Sdfrstatic const u_int32_t *
144718976Sdfrparsev3rddirres(const u_int32_t *dp, int verbose)
144818976Sdfr{
144918976Sdfr	int er;
145018976Sdfr
145175118Sfenner	if (!(dp = parsestatus(dp, &er)))
145275118Sfenner		return (0);
145318976Sdfr	if (vflag)
145418976Sdfr		printf(" POST:");
145575118Sfenner	if (!(dp = parse_post_op_attr(dp, verbose)))
145675118Sfenner		return (0);
145718976Sdfr	if (er)
145818976Sdfr		return dp;
145918976Sdfr	if (vflag) {
146026184Sfenner		TCHECK(dp[1]);
146126183Sfenner		printf(" verf %08x%08x", dp[0], dp[1]);
146218976Sdfr		dp += 2;
146318976Sdfr	}
146418976Sdfr	return dp;
146526184Sfennertrunc:
146626184Sfenner	return (NULL);
146718976Sdfr}
146818976Sdfr
146918976Sdfrstatic int
147018976Sdfrparsefsinfo(const u_int32_t *dp)
147118976Sdfr{
147218976Sdfr	struct nfsv3_fsinfo *sfp;
147318976Sdfr	int er;
147418976Sdfr
147575118Sfenner	if (!(dp = parsestatus(dp, &er)))
147618976Sdfr		return (0);
147718976Sdfr	if (vflag)
147818976Sdfr		printf(" POST:");
147975118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
148018976Sdfr		return (0);
148118976Sdfr	if (er)
148218976Sdfr		return (1);
148318976Sdfr
148418976Sdfr	sfp = (struct nfsv3_fsinfo *)dp;
148526184Sfenner	TCHECK(*sfp);
148675118Sfenner	printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1487127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtmax),
1488127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtpref),
1489127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtmax),
1490127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtpref),
1491127675Sbms	       EXTRACT_32BITS(&sfp->fs_dtpref));
149218976Sdfr	if (vflag) {
1493146778Ssam		printf(" rtmult %u wtmult %u maxfsz %" PRIu64,
1494127675Sbms		       EXTRACT_32BITS(&sfp->fs_rtmult),
1495146778Ssam		       EXTRACT_32BITS(&sfp->fs_wtmult),
1496146778Ssam		       EXTRACT_64BITS((u_int32_t *)&sfp->fs_maxfilesize));
149775118Sfenner		printf(" delta %u.%06u ",
1498127675Sbms		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
1499127675Sbms		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec));
150018976Sdfr	}
1501111729Sfenner	return (1);
1502111729Sfennertrunc:
150375118Sfenner	return (0);
150418976Sdfr}
150518976Sdfr
150618976Sdfrstatic int
150718976Sdfrparsepathconf(const u_int32_t *dp)
150818976Sdfr{
150918976Sdfr	int er;
151018976Sdfr	struct nfsv3_pathconf *spp;
151118976Sdfr
151275118Sfenner	if (!(dp = parsestatus(dp, &er)))
151318976Sdfr		return (0);
151418976Sdfr	if (vflag)
151518976Sdfr		printf(" POST:");
151675118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
151718976Sdfr		return (0);
151818976Sdfr	if (er)
151918976Sdfr		return (1);
152018976Sdfr
152118976Sdfr	spp = (struct nfsv3_pathconf *)dp;
152226184Sfenner	TCHECK(*spp);
152318976Sdfr
152475118Sfenner	printf(" linkmax %u namemax %u %s %s %s %s",
1525127675Sbms	       EXTRACT_32BITS(&spp->pc_linkmax),
1526127675Sbms	       EXTRACT_32BITS(&spp->pc_namemax),
1527127675Sbms	       EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
1528127675Sbms	       EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
1529127675Sbms	       EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
1530127675Sbms	       EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : "");
1531111729Sfenner	return (1);
1532111729Sfennertrunc:
153375118Sfenner	return (0);
153417680Spst}
153575118Sfenner
153617680Spststatic void
1537146778Ssaminterp_reply(const struct sunrpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
153817680Spst{
153917680Spst	register const u_int32_t *dp;
154018976Sdfr	register int v3;
154118976Sdfr	int er;
154217680Spst
154318976Sdfr	v3 = (vers == NFS_VER3);
154418976Sdfr
154518976Sdfr	if (!v3 && proc < NFS_NPROCS)
154618976Sdfr		proc = nfsv3_procid[proc];
154718976Sdfr
154817680Spst	switch (proc) {
154917680Spst
155017680Spst	case NFSPROC_NOOP:
155117680Spst		printf(" nop");
155217680Spst		return;
155318976Sdfr
155417680Spst	case NFSPROC_NULL:
155517680Spst		printf(" null");
155617680Spst		return;
155717680Spst
155817680Spst	case NFSPROC_GETATTR:
155917680Spst		printf(" getattr");
156017680Spst		dp = parserep(rp, length);
156126183Sfenner		if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
156217680Spst			return;
156317680Spst		break;
156417680Spst
156517680Spst	case NFSPROC_SETATTR:
156617680Spst		printf(" setattr");
156775118Sfenner		if (!(dp = parserep(rp, length)))
156817680Spst			return;
156918976Sdfr		if (v3) {
157075118Sfenner			if (parsewccres(dp, vflag))
157118976Sdfr				return;
157218976Sdfr		} else {
157318976Sdfr			if (parseattrstat(dp, !qflag, 0) != 0)
157418976Sdfr				return;
157518976Sdfr		}
157617680Spst		break;
157717680Spst
157817680Spst	case NFSPROC_LOOKUP:
157917680Spst		printf(" lookup");
158075118Sfenner		if (!(dp = parserep(rp, length)))
158118976Sdfr			break;
158218976Sdfr		if (v3) {
158375118Sfenner			if (!(dp = parsestatus(dp, &er)))
158418976Sdfr				break;
158518976Sdfr			if (er) {
158618976Sdfr				if (vflag > 1) {
158718976Sdfr					printf(" post dattr:");
158818976Sdfr					dp = parse_post_op_attr(dp, vflag);
158918976Sdfr				}
159018976Sdfr			} else {
159175118Sfenner				if (!(dp = parsefh(dp, v3)))
159218976Sdfr					break;
159375118Sfenner				if ((dp = parse_post_op_attr(dp, vflag)) &&
159475118Sfenner				    vflag > 1) {
159518976Sdfr					printf(" post dattr:");
159618976Sdfr					dp = parse_post_op_attr(dp, vflag);
159718976Sdfr				}
159818976Sdfr			}
159975118Sfenner			if (dp)
160018976Sdfr				return;
160118976Sdfr		} else {
160218976Sdfr			if (parsediropres(dp) != 0)
160318976Sdfr				return;
160418976Sdfr		}
160517680Spst		break;
160617680Spst
160718976Sdfr	case NFSPROC_ACCESS:
160818976Sdfr		printf(" access");
160998527Sfenner		if (!(dp = parserep(rp, length)))
161098527Sfenner			break;
161175118Sfenner		if (!(dp = parsestatus(dp, &er)))
161218976Sdfr			break;
161318976Sdfr		if (vflag)
161418976Sdfr			printf(" attr:");
161575118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
161618976Sdfr			break;
161718976Sdfr		if (!er)
1618127675Sbms			printf(" c %04x", EXTRACT_32BITS(&dp[0]));
161918976Sdfr		return;
162018976Sdfr
162117680Spst	case NFSPROC_READLINK:
162217680Spst		printf(" readlink");
162317680Spst		dp = parserep(rp, length);
162426183Sfenner		if (dp != NULL && parselinkres(dp, v3) != 0)
162517680Spst			return;
162617680Spst		break;
162717680Spst
162817680Spst	case NFSPROC_READ:
162917680Spst		printf(" read");
163075118Sfenner		if (!(dp = parserep(rp, length)))
163118976Sdfr			break;
163218976Sdfr		if (v3) {
163375118Sfenner			if (!(dp = parsestatus(dp, &er)))
163418976Sdfr				break;
163575118Sfenner			if (!(dp = parse_post_op_attr(dp, vflag)))
163618976Sdfr				break;
163718976Sdfr			if (er)
163818976Sdfr				return;
163918976Sdfr			if (vflag) {
164075118Sfenner				TCHECK(dp[1]);
1641127675Sbms				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1642127675Sbms				if (EXTRACT_32BITS(&dp[1]))
164318976Sdfr					printf(" EOF");
164418976Sdfr			}
164517680Spst			return;
164618976Sdfr		} else {
164718976Sdfr			if (parseattrstat(dp, vflag, 0) != 0)
164818976Sdfr				return;
164918976Sdfr		}
165017680Spst		break;
165117680Spst
165217680Spst	case NFSPROC_WRITE:
165317680Spst		printf(" write");
165475118Sfenner		if (!(dp = parserep(rp, length)))
165518976Sdfr			break;
165618976Sdfr		if (v3) {
165775118Sfenner			if (!(dp = parsestatus(dp, &er)))
165818976Sdfr				break;
165975118Sfenner			if (!(dp = parse_wcc_data(dp, vflag)))
166018976Sdfr				break;
166118976Sdfr			if (er)
166218976Sdfr				return;
166318976Sdfr			if (vflag) {
166475118Sfenner				TCHECK(dp[0]);
1665127675Sbms				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
166618976Sdfr				if (vflag > 1) {
166775118Sfenner					TCHECK(dp[1]);
166818976Sdfr					printf(" <%s>",
166975118Sfenner						tok2str(nfsv3_writemodes,
1670127675Sbms							NULL, EXTRACT_32BITS(&dp[1])));
167118976Sdfr				}
167218976Sdfr				return;
167318976Sdfr			}
167418976Sdfr		} else {
167518976Sdfr			if (parseattrstat(dp, vflag, v3) != 0)
167618976Sdfr				return;
167718976Sdfr		}
167817680Spst		break;
167917680Spst
168017680Spst	case NFSPROC_CREATE:
168117680Spst		printf(" create");
168275118Sfenner		if (!(dp = parserep(rp, length)))
168318976Sdfr			break;
168418976Sdfr		if (v3) {
168575118Sfenner			if (parsecreateopres(dp, vflag) != 0)
168618976Sdfr				return;
168718976Sdfr		} else {
168818976Sdfr			if (parsediropres(dp) != 0)
168918976Sdfr				return;
169018976Sdfr		}
169118976Sdfr		break;
169218976Sdfr
169318976Sdfr	case NFSPROC_MKDIR:
169418976Sdfr		printf(" mkdir");
169575118Sfenner		if (!(dp = parserep(rp, length)))
169618976Sdfr			break;
169718976Sdfr		if (v3) {
169875118Sfenner			if (parsecreateopres(dp, vflag) != 0)
169918976Sdfr				return;
170018976Sdfr		} else {
170118976Sdfr			if (parsediropres(dp) != 0)
170218976Sdfr				return;
170318976Sdfr		}
170418976Sdfr		break;
170518976Sdfr
170618976Sdfr	case NFSPROC_SYMLINK:
170718976Sdfr		printf(" symlink");
170875118Sfenner		if (!(dp = parserep(rp, length)))
170918976Sdfr			break;
171018976Sdfr		if (v3) {
171175118Sfenner			if (parsecreateopres(dp, vflag) != 0)
171218976Sdfr				return;
171318976Sdfr		} else {
171475118Sfenner			if (parsestatus(dp, &er) != 0)
171518976Sdfr				return;
171618976Sdfr		}
171718976Sdfr		break;
171818976Sdfr
171918976Sdfr	case NFSPROC_MKNOD:
172018976Sdfr		printf(" mknod");
172175118Sfenner		if (!(dp = parserep(rp, length)))
172218976Sdfr			break;
172375118Sfenner		if (parsecreateopres(dp, vflag) != 0)
172417680Spst			return;
172517680Spst		break;
172617680Spst
172717680Spst	case NFSPROC_REMOVE:
172817680Spst		printf(" remove");
172975118Sfenner		if (!(dp = parserep(rp, length)))
173018976Sdfr			break;
173118976Sdfr		if (v3) {
173275118Sfenner			if (parsewccres(dp, vflag))
173318976Sdfr				return;
173418976Sdfr		} else {
173575118Sfenner			if (parsestatus(dp, &er) != 0)
173618976Sdfr				return;
173718976Sdfr		}
173817680Spst		break;
173917680Spst
174018976Sdfr	case NFSPROC_RMDIR:
174118976Sdfr		printf(" rmdir");
174275118Sfenner		if (!(dp = parserep(rp, length)))
174318976Sdfr			break;
174418976Sdfr		if (v3) {
174575118Sfenner			if (parsewccres(dp, vflag))
174618976Sdfr				return;
174718976Sdfr		} else {
174875118Sfenner			if (parsestatus(dp, &er) != 0)
174918976Sdfr				return;
175018976Sdfr		}
175118976Sdfr		break;
175218976Sdfr
175317680Spst	case NFSPROC_RENAME:
175417680Spst		printf(" rename");
175575118Sfenner		if (!(dp = parserep(rp, length)))
175618976Sdfr			break;
175718976Sdfr		if (v3) {
175875118Sfenner			if (!(dp = parsestatus(dp, &er)))
175918976Sdfr				break;
176018976Sdfr			if (vflag) {
176118976Sdfr				printf(" from:");
176275118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
176318976Sdfr					break;
176418976Sdfr				printf(" to:");
176575118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
176618976Sdfr					break;
176718976Sdfr			}
176817680Spst			return;
176918976Sdfr		} else {
177075118Sfenner			if (parsestatus(dp, &er) != 0)
177118976Sdfr				return;
177218976Sdfr		}
177317680Spst		break;
177417680Spst
177517680Spst	case NFSPROC_LINK:
177617680Spst		printf(" link");
177775118Sfenner		if (!(dp = parserep(rp, length)))
177818976Sdfr			break;
177918976Sdfr		if (v3) {
178075118Sfenner			if (!(dp = parsestatus(dp, &er)))
178118976Sdfr				break;
178218976Sdfr			if (vflag) {
178318976Sdfr				printf(" file POST:");
178475118Sfenner				if (!(dp = parse_post_op_attr(dp, vflag)))
178518976Sdfr					break;
178618976Sdfr				printf(" dir:");
178775118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
178818976Sdfr					break;
178918976Sdfr				return;
179018976Sdfr			}
179118976Sdfr		} else {
179275118Sfenner			if (parsestatus(dp, &er) != 0)
179318976Sdfr				return;
179418976Sdfr		}
179517680Spst		break;
179617680Spst
179718976Sdfr	case NFSPROC_READDIR:
179818976Sdfr		printf(" readdir");
179975118Sfenner		if (!(dp = parserep(rp, length)))
180018976Sdfr			break;
180118976Sdfr		if (v3) {
180275118Sfenner			if (parsev3rddirres(dp, vflag))
180318976Sdfr				return;
180418976Sdfr		} else {
180518976Sdfr			if (parserddires(dp) != 0)
180618976Sdfr				return;
180718976Sdfr		}
180818976Sdfr		break;
180918976Sdfr
181018976Sdfr	case NFSPROC_READDIRPLUS:
181118976Sdfr		printf(" readdirplus");
181275118Sfenner		if (!(dp = parserep(rp, length)))
181318976Sdfr			break;
181475118Sfenner		if (parsev3rddirres(dp, vflag))
181517680Spst			return;
181617680Spst		break;
181717680Spst
181818976Sdfr	case NFSPROC_FSSTAT:
181918976Sdfr		printf(" fsstat");
182017680Spst		dp = parserep(rp, length);
182175118Sfenner		if (dp != NULL && parsestatfs(dp, v3) != 0)
182217680Spst			return;
182317680Spst		break;
182417680Spst
182518976Sdfr	case NFSPROC_FSINFO:
182618976Sdfr		printf(" fsinfo");
182717680Spst		dp = parserep(rp, length);
182875118Sfenner		if (dp != NULL && parsefsinfo(dp) != 0)
182917680Spst			return;
183017680Spst		break;
183117680Spst
183218976Sdfr	case NFSPROC_PATHCONF:
183318976Sdfr		printf(" pathconf");
183417680Spst		dp = parserep(rp, length);
183526183Sfenner		if (dp != NULL && parsepathconf(dp) != 0)
183617680Spst			return;
183717680Spst		break;
183817680Spst
183918976Sdfr	case NFSPROC_COMMIT:
184018976Sdfr		printf(" commit");
184117680Spst		dp = parserep(rp, length);
184226183Sfenner		if (dp != NULL && parsewccres(dp, vflag) != 0)
184317680Spst			return;
184417680Spst		break;
184517680Spst
184617680Spst	default:
184726183Sfenner		printf(" proc-%u", proc);
184817680Spst		return;
184917680Spst	}
185018976Sdfrtrunc:
185126183Sfenner	if (!nfserr)
185226183Sfenner		fputs(" [|nfs]", stdout);
185317680Spst}
1854