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.
2017680Spst */
2117680Spst
22313537Sglebius/* \summary: Network File System (NFS) printer */
23313537Sglebius
2475118Sfenner#ifdef HAVE_CONFIG_H
2575118Sfenner#include "config.h"
2675118Sfenner#endif
2775118Sfenner
28313537Sglebius#include <netdissect-stdinc.h>
2917680Spst
3017680Spst#include <stdio.h>
3117680Spst#include <string.h>
3217680Spst
33313537Sglebius#include "netdissect.h"
3417680Spst#include "addrtoname.h"
35127675Sbms#include "extract.h"
3617680Spst
3718976Sdfr#include "nfs.h"
3817680Spst#include "nfsfh.h"
3917680Spst
4075118Sfenner#include "ip.h"
4175118Sfenner#include "ip6.h"
42146778Ssam#include "rpc_auth.h"
43146778Ssam#include "rpc_msg.h"
4475118Sfenner
45276788Sdelphijstatic const char tstr[] = " [|nfs]";
4617680Spst
47276788Sdelphijstatic void nfs_printfh(netdissect_options *, const uint32_t *, const u_int);
48276788Sdelphijstatic int xid_map_enter(netdissect_options *, const struct sunrpc_msg *, const u_char *);
49276788Sdelphijstatic int xid_map_find(const struct sunrpc_msg *, const u_char *,
50276788Sdelphij			    uint32_t *, uint32_t *);
51276788Sdelphijstatic void interp_reply(netdissect_options *, const struct sunrpc_msg *, uint32_t, uint32_t, int);
52276788Sdelphijstatic const uint32_t *parse_post_op_attr(netdissect_options *, const uint32_t *, int);
53276788Sdelphij
5418976Sdfr/*
5518976Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
5618976Sdfr */
57313537Sglebiusstatic uint32_t nfsv3_procid[NFS_NPROCS] = {
5818976Sdfr	NFSPROC_NULL,
5918976Sdfr	NFSPROC_GETATTR,
6018976Sdfr	NFSPROC_SETATTR,
6118976Sdfr	NFSPROC_NOOP,
6218976Sdfr	NFSPROC_LOOKUP,
6318976Sdfr	NFSPROC_READLINK,
6418976Sdfr	NFSPROC_READ,
6518976Sdfr	NFSPROC_NOOP,
6618976Sdfr	NFSPROC_WRITE,
6718976Sdfr	NFSPROC_CREATE,
6818976Sdfr	NFSPROC_REMOVE,
6918976Sdfr	NFSPROC_RENAME,
7018976Sdfr	NFSPROC_LINK,
7118976Sdfr	NFSPROC_SYMLINK,
7218976Sdfr	NFSPROC_MKDIR,
7318976Sdfr	NFSPROC_RMDIR,
7418976Sdfr	NFSPROC_READDIR,
7518976Sdfr	NFSPROC_FSSTAT,
7618976Sdfr	NFSPROC_NOOP,
7718976Sdfr	NFSPROC_NOOP,
7818976Sdfr	NFSPROC_NOOP,
7918976Sdfr	NFSPROC_NOOP,
8018976Sdfr	NFSPROC_NOOP,
8118976Sdfr	NFSPROC_NOOP,
8218976Sdfr	NFSPROC_NOOP,
8318976Sdfr	NFSPROC_NOOP
8418976Sdfr};
8518976Sdfr
86276788Sdelphijstatic const struct tok nfsproc_str[] = {
87276788Sdelphij	{ NFSPROC_NOOP,        "nop"         },
88276788Sdelphij	{ NFSPROC_NULL,        "null"        },
89276788Sdelphij	{ NFSPROC_GETATTR,     "getattr"     },
90276788Sdelphij	{ NFSPROC_SETATTR,     "setattr"     },
91276788Sdelphij	{ NFSPROC_LOOKUP,      "lookup"      },
92276788Sdelphij	{ NFSPROC_ACCESS,      "access"      },
93276788Sdelphij	{ NFSPROC_READLINK,    "readlink"    },
94276788Sdelphij	{ NFSPROC_READ,        "read"        },
95276788Sdelphij	{ NFSPROC_WRITE,       "write"       },
96276788Sdelphij	{ NFSPROC_CREATE,      "create"      },
97276788Sdelphij	{ NFSPROC_MKDIR,       "mkdir"       },
98276788Sdelphij	{ NFSPROC_SYMLINK,     "symlink"     },
99276788Sdelphij	{ NFSPROC_MKNOD,       "mknod"       },
100276788Sdelphij	{ NFSPROC_REMOVE,      "remove"      },
101276788Sdelphij	{ NFSPROC_RMDIR,       "rmdir"       },
102276788Sdelphij	{ NFSPROC_RENAME,      "rename"      },
103276788Sdelphij	{ NFSPROC_LINK,        "link"        },
104276788Sdelphij	{ NFSPROC_READDIR,     "readdir"     },
105276788Sdelphij	{ NFSPROC_READDIRPLUS, "readdirplus" },
106276788Sdelphij	{ NFSPROC_FSSTAT,      "fsstat"      },
107276788Sdelphij	{ NFSPROC_FSINFO,      "fsinfo"      },
108276788Sdelphij	{ NFSPROC_PATHCONF,    "pathconf"    },
109276788Sdelphij	{ NFSPROC_COMMIT,      "commit"      },
110276788Sdelphij	{ 0, NULL }
111276788Sdelphij};
112276788Sdelphij
11375118Sfenner/*
11475118Sfenner * NFS V2 and V3 status values.
11575118Sfenner *
11675118Sfenner * Some of these come from the RFCs for NFS V2 and V3, with the message
11775118Sfenner * strings taken from the FreeBSD C library "errlst.c".
11875118Sfenner *
11975118Sfenner * Others are errors that are not in the RFC but that I suspect some
12075118Sfenner * NFS servers could return; the values are FreeBSD errno values, as
12175118Sfenner * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
12275118Sfenner * was primarily BSD-derived.
12375118Sfenner */
124276788Sdelphijstatic const struct tok status2str[] = {
12575118Sfenner	{ 1,     "Operation not permitted" },	/* EPERM */
12675118Sfenner	{ 2,     "No such file or directory" },	/* ENOENT */
12775118Sfenner	{ 5,     "Input/output error" },	/* EIO */
12875118Sfenner	{ 6,     "Device not configured" },	/* ENXIO */
12975118Sfenner	{ 11,    "Resource deadlock avoided" },	/* EDEADLK */
13075118Sfenner	{ 12,    "Cannot allocate memory" },	/* ENOMEM */
13175118Sfenner	{ 13,    "Permission denied" },		/* EACCES */
13275118Sfenner	{ 17,    "File exists" },		/* EEXIST */
13375118Sfenner	{ 18,    "Cross-device link" },		/* EXDEV */
13475118Sfenner	{ 19,    "Operation not supported by device" }, /* ENODEV */
13575118Sfenner	{ 20,    "Not a directory" },		/* ENOTDIR */
13675118Sfenner	{ 21,    "Is a directory" },		/* EISDIR */
13775118Sfenner	{ 22,    "Invalid argument" },		/* EINVAL */
13875118Sfenner	{ 26,    "Text file busy" },		/* ETXTBSY */
13975118Sfenner	{ 27,    "File too large" },		/* EFBIG */
14075118Sfenner	{ 28,    "No space left on device" },	/* ENOSPC */
14175118Sfenner	{ 30,    "Read-only file system" },	/* EROFS */
14275118Sfenner	{ 31,    "Too many links" },		/* EMLINK */
14375118Sfenner	{ 45,    "Operation not supported" },	/* EOPNOTSUPP */
14475118Sfenner	{ 62,    "Too many levels of symbolic links" }, /* ELOOP */
14575118Sfenner	{ 63,    "File name too long" },	/* ENAMETOOLONG */
14675118Sfenner	{ 66,    "Directory not empty" },	/* ENOTEMPTY */
14775118Sfenner	{ 69,    "Disc quota exceeded" },	/* EDQUOT */
14875118Sfenner	{ 70,    "Stale NFS file handle" },	/* ESTALE */
14975118Sfenner	{ 71,    "Too many levels of remote in path" }, /* EREMOTE */
15075118Sfenner	{ 99,    "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
15175118Sfenner	{ 10001, "Illegal NFS file handle" },	/* NFS3ERR_BADHANDLE */
15275118Sfenner	{ 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
15375118Sfenner	{ 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
15475118Sfenner	{ 10004, "Operation not supported" },	/* NFS3ERR_NOTSUPP */
15575118Sfenner	{ 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
15675118Sfenner	{ 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
15775118Sfenner	{ 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
15875118Sfenner	{ 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
15975118Sfenner	{ 0,     NULL }
16018976Sdfr};
16118976Sdfr
162276788Sdelphijstatic const struct tok nfsv3_writemodes[] = {
16375118Sfenner	{ 0,		"unstable" },
16475118Sfenner	{ 1,		"datasync" },
16575118Sfenner	{ 2,		"filesync" },
16675118Sfenner	{ 0,		NULL }
16775118Sfenner};
16875118Sfenner
169276788Sdelphijstatic const struct tok type2str[] = {
17018976Sdfr	{ NFNON,	"NON" },
17118976Sdfr	{ NFREG,	"REG" },
17218976Sdfr	{ NFDIR,	"DIR" },
17318976Sdfr	{ NFBLK,	"BLK" },
17418976Sdfr	{ NFCHR,	"CHR" },
17518976Sdfr	{ NFLNK,	"LNK" },
17618976Sdfr	{ NFFIFO,	"FIFO" },
17718976Sdfr	{ 0,		NULL }
17818976Sdfr};
17918976Sdfr
180276788Sdelphijstatic const struct tok sunrpc_auth_str[] = {
181276788Sdelphij	{ SUNRPC_AUTH_OK,           "OK"                                                     },
182276788Sdelphij	{ SUNRPC_AUTH_BADCRED,      "Bogus Credentials (seal broken)"                        },
183276788Sdelphij	{ SUNRPC_AUTH_REJECTEDCRED, "Rejected Credentials (client should begin new session)" },
184276788Sdelphij	{ SUNRPC_AUTH_BADVERF,      "Bogus Verifier (seal broken)"                           },
185276788Sdelphij	{ SUNRPC_AUTH_REJECTEDVERF, "Verifier expired or was replayed"                       },
186276788Sdelphij	{ SUNRPC_AUTH_TOOWEAK,      "Credentials are too weak"                               },
187276788Sdelphij	{ SUNRPC_AUTH_INVALIDRESP,  "Bogus response verifier"                                },
188276788Sdelphij	{ SUNRPC_AUTH_FAILED,       "Unknown failure"                                        },
189276788Sdelphij	{ 0, NULL }
190276788Sdelphij};
191276788Sdelphij
192276788Sdelphijstatic const struct tok sunrpc_str[] = {
193276788Sdelphij	{ SUNRPC_PROG_UNAVAIL,  "PROG_UNAVAIL"  },
194276788Sdelphij	{ SUNRPC_PROG_MISMATCH, "PROG_MISMATCH" },
195276788Sdelphij	{ SUNRPC_PROC_UNAVAIL,  "PROC_UNAVAIL"  },
196276788Sdelphij	{ SUNRPC_GARBAGE_ARGS,  "GARBAGE_ARGS"  },
197276788Sdelphij	{ SUNRPC_SYSTEM_ERR,    "SYSTEM_ERR"    },
198276788Sdelphij	{ 0, NULL }
199276788Sdelphij};
200276788Sdelphij
20175118Sfennerstatic void
202276788Sdelphijprint_nfsaddr(netdissect_options *ndo,
203276788Sdelphij              const u_char *bp, const char *s, const char *d)
20475118Sfenner{
205313537Sglebius	const struct ip *ip;
206313537Sglebius	const struct ip6_hdr *ip6;
20775118Sfenner	char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
20875118Sfenner
20975118Sfenner	srcaddr[0] = dstaddr[0] = '\0';
210313537Sglebius	switch (IP_V((const struct ip *)bp)) {
21175118Sfenner	case 4:
212313537Sglebius		ip = (const struct ip *)bp;
213276788Sdelphij		strlcpy(srcaddr, ipaddr_string(ndo, &ip->ip_src), sizeof(srcaddr));
214276788Sdelphij		strlcpy(dstaddr, ipaddr_string(ndo, &ip->ip_dst), sizeof(dstaddr));
21575118Sfenner		break;
21675118Sfenner	case 6:
217313537Sglebius		ip6 = (const struct ip6_hdr *)bp;
218276788Sdelphij		strlcpy(srcaddr, ip6addr_string(ndo, &ip6->ip6_src),
21975118Sfenner		    sizeof(srcaddr));
220276788Sdelphij		strlcpy(dstaddr, ip6addr_string(ndo, &ip6->ip6_dst),
22175118Sfenner		    sizeof(dstaddr));
22275118Sfenner		break;
22375118Sfenner	default:
22475118Sfenner		strlcpy(srcaddr, "?", sizeof(srcaddr));
22575118Sfenner		strlcpy(dstaddr, "?", sizeof(dstaddr));
22675118Sfenner		break;
22775118Sfenner	}
22875118Sfenner
229276788Sdelphij	ND_PRINT((ndo, "%s.%s > %s.%s: ", srcaddr, s, dstaddr, d));
23075118Sfenner}
23175118Sfenner
232276788Sdelphijstatic const uint32_t *
233276788Sdelphijparse_sattr3(netdissect_options *ndo,
234276788Sdelphij             const uint32_t *dp, struct nfsv3_sattr *sa3)
23518976Sdfr{
236276788Sdelphij	ND_TCHECK(dp[0]);
237127675Sbms	sa3->sa_modeset = EXTRACT_32BITS(dp);
238127675Sbms	dp++;
239127675Sbms	if (sa3->sa_modeset) {
240276788Sdelphij		ND_TCHECK(dp[0]);
241127675Sbms		sa3->sa_mode = EXTRACT_32BITS(dp);
242127675Sbms		dp++;
24318976Sdfr	}
24418976Sdfr
245276788Sdelphij	ND_TCHECK(dp[0]);
246127675Sbms	sa3->sa_uidset = EXTRACT_32BITS(dp);
247127675Sbms	dp++;
248127675Sbms	if (sa3->sa_uidset) {
249276788Sdelphij		ND_TCHECK(dp[0]);
250127675Sbms		sa3->sa_uid = EXTRACT_32BITS(dp);
251127675Sbms		dp++;
25218976Sdfr	}
25318976Sdfr
254276788Sdelphij	ND_TCHECK(dp[0]);
255127675Sbms	sa3->sa_gidset = EXTRACT_32BITS(dp);
256127675Sbms	dp++;
257127675Sbms	if (sa3->sa_gidset) {
258276788Sdelphij		ND_TCHECK(dp[0]);
259127675Sbms		sa3->sa_gid = EXTRACT_32BITS(dp);
260127675Sbms		dp++;
26118976Sdfr	}
26218976Sdfr
263276788Sdelphij	ND_TCHECK(dp[0]);
264127675Sbms	sa3->sa_sizeset = EXTRACT_32BITS(dp);
265127675Sbms	dp++;
266127675Sbms	if (sa3->sa_sizeset) {
267276788Sdelphij		ND_TCHECK(dp[0]);
268127675Sbms		sa3->sa_size = EXTRACT_32BITS(dp);
269127675Sbms		dp++;
27018976Sdfr	}
27118976Sdfr
272276788Sdelphij	ND_TCHECK(dp[0]);
273127675Sbms	sa3->sa_atimetype = EXTRACT_32BITS(dp);
274127675Sbms	dp++;
275127675Sbms	if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) {
276276788Sdelphij		ND_TCHECK(dp[1]);
277127675Sbms		sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp);
278127675Sbms		dp++;
279127675Sbms		sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp);
280127675Sbms		dp++;
28118976Sdfr	}
28218976Sdfr
283276788Sdelphij	ND_TCHECK(dp[0]);
284127675Sbms	sa3->sa_mtimetype = EXTRACT_32BITS(dp);
285127675Sbms	dp++;
286127675Sbms	if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) {
287276788Sdelphij		ND_TCHECK(dp[1]);
288127675Sbms		sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp);
289127675Sbms		dp++;
290127675Sbms		sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp);
291127675Sbms		dp++;
29218976Sdfr	}
29318976Sdfr
29418976Sdfr	return dp;
29575118Sfennertrunc:
29675118Sfenner	return NULL;
29718976Sdfr}
29818976Sdfr
29975118Sfennerstatic int nfserr;		/* true if we error rather than trunc */
30075118Sfenner
30175118Sfennerstatic void
302276788Sdelphijprint_sattr3(netdissect_options *ndo,
303276788Sdelphij             const struct nfsv3_sattr *sa3, int verbose)
30418976Sdfr{
30518976Sdfr	if (sa3->sa_modeset)
306276788Sdelphij		ND_PRINT((ndo, " mode %o", sa3->sa_mode));
30718976Sdfr	if (sa3->sa_uidset)
308276788Sdelphij		ND_PRINT((ndo, " uid %u", sa3->sa_uid));
30918976Sdfr	if (sa3->sa_gidset)
310276788Sdelphij		ND_PRINT((ndo, " gid %u", sa3->sa_gid));
31118976Sdfr	if (verbose > 1) {
31218976Sdfr		if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
313276788Sdelphij			ND_PRINT((ndo, " atime %u.%06u", sa3->sa_atime.nfsv3_sec,
314276788Sdelphij			       sa3->sa_atime.nfsv3_nsec));
31518976Sdfr		if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
316276788Sdelphij			ND_PRINT((ndo, " mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
317276788Sdelphij			       sa3->sa_mtime.nfsv3_nsec));
31818976Sdfr	}
31918976Sdfr}
32018976Sdfr
32118976Sdfrvoid
322276788Sdelphijnfsreply_print(netdissect_options *ndo,
323276788Sdelphij               register const u_char *bp, u_int length,
324276788Sdelphij               register const u_char *bp2)
32517680Spst{
326146778Ssam	register const struct sunrpc_msg *rp;
32775118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
32817680Spst
32926183Sfenner	nfserr = 0;		/* assume no error */
330146778Ssam	rp = (const struct sunrpc_msg *)bp;
33117680Spst
332276788Sdelphij	ND_TCHECK(rp->rm_xid);
333276788Sdelphij	if (!ndo->ndo_nflag) {
33475118Sfenner		strlcpy(srcid, "nfs", sizeof(srcid));
33575118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
336127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
33775118Sfenner	} else {
33875118Sfenner		snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
33975118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
340127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
34175118Sfenner	}
342276788Sdelphij	print_nfsaddr(ndo, bp2, srcid, dstid);
343276788Sdelphij
344276788Sdelphij	nfsreply_print_noaddr(ndo, bp, length, bp2);
345276788Sdelphij	return;
346276788Sdelphij
347276788Sdelphijtrunc:
348276788Sdelphij	if (!nfserr)
349276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
350276788Sdelphij}
351276788Sdelphij
352276788Sdelphijvoid
353276788Sdelphijnfsreply_print_noaddr(netdissect_options *ndo,
354276788Sdelphij                      register const u_char *bp, u_int length,
355276788Sdelphij                      register const u_char *bp2)
356276788Sdelphij{
357276788Sdelphij	register const struct sunrpc_msg *rp;
358276788Sdelphij	uint32_t proc, vers, reply_stat;
359276788Sdelphij	enum sunrpc_reject_stat rstat;
360276788Sdelphij	uint32_t rlow;
361276788Sdelphij	uint32_t rhigh;
362276788Sdelphij	enum sunrpc_auth_stat rwhy;
363276788Sdelphij
364276788Sdelphij	nfserr = 0;		/* assume no error */
365276788Sdelphij	rp = (const struct sunrpc_msg *)bp;
366276788Sdelphij
367276788Sdelphij	ND_TCHECK(rp->rm_reply.rp_stat);
368172686Smlaier	reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat);
369172686Smlaier	switch (reply_stat) {
37017680Spst
371172686Smlaier	case SUNRPC_MSG_ACCEPTED:
372276788Sdelphij		ND_PRINT((ndo, "reply ok %u", length));
373172686Smlaier		if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
374276788Sdelphij			interp_reply(ndo, rp, proc, vers, length);
375172686Smlaier		break;
376172686Smlaier
377172686Smlaier	case SUNRPC_MSG_DENIED:
378276788Sdelphij		ND_PRINT((ndo, "reply ERR %u: ", length));
379276788Sdelphij		ND_TCHECK(rp->rm_reply.rp_reject.rj_stat);
380172686Smlaier		rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat);
381172686Smlaier		switch (rstat) {
382172686Smlaier
383172686Smlaier		case SUNRPC_RPC_MISMATCH:
384276788Sdelphij			ND_TCHECK(rp->rm_reply.rp_reject.rj_vers.high);
385172686Smlaier			rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low);
386172686Smlaier			rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high);
387276788Sdelphij			ND_PRINT((ndo, "RPC Version mismatch (%u-%u)", rlow, rhigh));
388172686Smlaier			break;
389172686Smlaier
390172686Smlaier		case SUNRPC_AUTH_ERROR:
391276788Sdelphij			ND_TCHECK(rp->rm_reply.rp_reject.rj_why);
392172686Smlaier			rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why);
393276788Sdelphij			ND_PRINT((ndo, "Auth %s", tok2str(sunrpc_auth_str, "Invalid failure code %u", rwhy)));
394172686Smlaier			break;
395172686Smlaier
396172686Smlaier		default:
397276788Sdelphij			ND_PRINT((ndo, "Unknown reason for rejecting rpc message %u", (unsigned int)rstat));
398172686Smlaier			break;
399172686Smlaier		}
400172686Smlaier		break;
401172686Smlaier
402172686Smlaier	default:
403276788Sdelphij		ND_PRINT((ndo, "reply Unknown rpc response code=%u %u", reply_stat, length));
404172686Smlaier		break;
405172686Smlaier	}
406190207Srpaulo	return;
407190207Srpaulo
408190207Srpaulotrunc:
409190207Srpaulo	if (!nfserr)
410276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
41117680Spst}
41217680Spst
41317680Spst/*
41417680Spst * Return a pointer to the first file handle in the packet.
41575118Sfenner * If the packet was truncated, return 0.
41617680Spst */
417276788Sdelphijstatic const uint32_t *
418276788Sdelphijparsereq(netdissect_options *ndo,
419276788Sdelphij         register const struct sunrpc_msg *rp, register u_int length)
42017680Spst{
421276788Sdelphij	register const uint32_t *dp;
42217680Spst	register u_int len;
42317680Spst
42417680Spst	/*
42517680Spst	 * find the start of the req data (if we captured it)
42617680Spst	 */
427313537Sglebius	dp = (const uint32_t *)&rp->rm_call.cb_cred;
428276788Sdelphij	ND_TCHECK(dp[1]);
429127675Sbms	len = EXTRACT_32BITS(&dp[1]);
43026183Sfenner	if (len < length) {
43126183Sfenner		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
432276788Sdelphij		ND_TCHECK(dp[1]);
433127675Sbms		len = EXTRACT_32BITS(&dp[1]);
43426183Sfenner		if (len < length) {
43526183Sfenner			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
436276788Sdelphij			ND_TCHECK2(dp[0], 0);
43726183Sfenner			return (dp);
43817680Spst		}
43917680Spst	}
44026183Sfennertrunc:
44126183Sfenner	return (NULL);
44217680Spst}
44317680Spst
44417680Spst/*
44517680Spst * Print out an NFS file handle and return a pointer to following word.
44675118Sfenner * If packet was truncated, return 0.
44717680Spst */
448276788Sdelphijstatic const uint32_t *
449276788Sdelphijparsefh(netdissect_options *ndo,
450276788Sdelphij        register const uint32_t *dp, int v3)
45117680Spst{
452127675Sbms	u_int len;
45318976Sdfr
45418976Sdfr	if (v3) {
455276788Sdelphij		ND_TCHECK(dp[0]);
456127675Sbms		len = EXTRACT_32BITS(dp) / 4;
45718976Sdfr		dp++;
45818976Sdfr	} else
45918976Sdfr		len = NFSX_V2FH / 4;
46018976Sdfr
461276788Sdelphij	if (ND_TTEST2(*dp, len * sizeof(*dp))) {
462276788Sdelphij		nfs_printfh(ndo, dp, len);
46318976Sdfr		return (dp + len);
46417680Spst	}
46526183Sfennertrunc:
46626183Sfenner	return (NULL);
46717680Spst}
46817680Spst
46917680Spst/*
47017680Spst * Print out a file name and return pointer to 32-bit word past it.
47175118Sfenner * If packet was truncated, return 0.
47217680Spst */
473276788Sdelphijstatic const uint32_t *
474276788Sdelphijparsefn(netdissect_options *ndo,
475276788Sdelphij        register const uint32_t *dp)
47617680Spst{
477276788Sdelphij	register uint32_t len;
47817680Spst	register const u_char *cp;
47917680Spst
48017680Spst	/* Bail if we don't have the string length */
481276788Sdelphij	ND_TCHECK(*dp);
48217680Spst
48317680Spst	/* Fetch string length; convert to host order */
48417680Spst	len = *dp++;
48517680Spst	NTOHL(len);
48617680Spst
487276788Sdelphij	ND_TCHECK2(*dp, ((len + 3) & ~3));
48875118Sfenner
489313537Sglebius	cp = (const u_char *)dp;
49017680Spst	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
49117680Spst	dp += ((len + 3) & ~3) / sizeof(*dp);
492276788Sdelphij	ND_PRINT((ndo, "\""));
493276788Sdelphij	if (fn_printn(ndo, cp, len, ndo->ndo_snapend)) {
494276788Sdelphij		ND_PRINT((ndo, "\""));
495147904Ssam		goto trunc;
496147904Ssam	}
497276788Sdelphij	ND_PRINT((ndo, "\""));
49817680Spst
49917680Spst	return (dp);
50075118Sfennertrunc:
50175118Sfenner	return NULL;
50217680Spst}
50317680Spst
50417680Spst/*
50517680Spst * Print out file handle and file name.
50617680Spst * Return pointer to 32-bit word past file name.
50775118Sfenner * If packet was truncated (or there was some other error), return 0.
50817680Spst */
509276788Sdelphijstatic const uint32_t *
510276788Sdelphijparsefhn(netdissect_options *ndo,
511276788Sdelphij         register const uint32_t *dp, int v3)
51217680Spst{
513276788Sdelphij	dp = parsefh(ndo, dp, v3);
51426183Sfenner	if (dp == NULL)
51526183Sfenner		return (NULL);
516276788Sdelphij	ND_PRINT((ndo, " "));
517276788Sdelphij	return (parsefn(ndo, dp));
51817680Spst}
51917680Spst
52017680Spstvoid
521276788Sdelphijnfsreq_print_noaddr(netdissect_options *ndo,
522276788Sdelphij                    register const u_char *bp, u_int length,
523276788Sdelphij                    register const u_char *bp2)
52417680Spst{
525146778Ssam	register const struct sunrpc_msg *rp;
526276788Sdelphij	register const uint32_t *dp;
52775118Sfenner	nfs_type type;
52875118Sfenner	int v3;
529276788Sdelphij	uint32_t proc;
530276788Sdelphij	uint32_t access_flags;
53118976Sdfr	struct nfsv3_sattr sa3;
53217680Spst
533276788Sdelphij	ND_PRINT((ndo, "%d", length));
53426183Sfenner	nfserr = 0;		/* assume no error */
535146778Ssam	rp = (const struct sunrpc_msg *)bp;
536190207Srpaulo
537276788Sdelphij	if (!xid_map_enter(ndo, rp, bp2))	/* record proc number for later on */
538190207Srpaulo		goto trunc;
53917680Spst
540127675Sbms	v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
541127675Sbms	proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
54218976Sdfr
54318976Sdfr	if (!v3 && proc < NFS_NPROCS)
54418976Sdfr		proc =  nfsv3_procid[proc];
54518976Sdfr
546276788Sdelphij	ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc)));
54718976Sdfr	switch (proc) {
54817680Spst
54917680Spst	case NFSPROC_GETATTR:
55017680Spst	case NFSPROC_SETATTR:
551276788Sdelphij	case NFSPROC_READLINK:
552276788Sdelphij	case NFSPROC_FSSTAT:
553276788Sdelphij	case NFSPROC_FSINFO:
554276788Sdelphij	case NFSPROC_PATHCONF:
555276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
556276788Sdelphij		    parsefh(ndo, dp, v3) != NULL)
55717680Spst			return;
55817680Spst		break;
55917680Spst
56017680Spst	case NFSPROC_LOOKUP:
561276788Sdelphij	case NFSPROC_CREATE:
562276788Sdelphij	case NFSPROC_MKDIR:
563276788Sdelphij	case NFSPROC_REMOVE:
564276788Sdelphij	case NFSPROC_RMDIR:
565276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
566276788Sdelphij		    parsefhn(ndo, dp, v3) != NULL)
56717680Spst			return;
56817680Spst		break;
56917680Spst
57018976Sdfr	case NFSPROC_ACCESS:
571276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
572276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
573276788Sdelphij			ND_TCHECK(dp[0]);
574214478Srpaulo			access_flags = EXTRACT_32BITS(&dp[0]);
575214478Srpaulo			if (access_flags & ~NFSV3ACCESS_FULL) {
576214478Srpaulo				/* NFSV3ACCESS definitions aren't up to date */
577276788Sdelphij				ND_PRINT((ndo, " %04x", access_flags));
578214478Srpaulo			} else if ((access_flags & NFSV3ACCESS_FULL) == NFSV3ACCESS_FULL) {
579276788Sdelphij				ND_PRINT((ndo, " NFS_ACCESS_FULL"));
580214478Srpaulo			} else {
581214478Srpaulo				char separator = ' ';
582214478Srpaulo				if (access_flags & NFSV3ACCESS_READ) {
583276788Sdelphij					ND_PRINT((ndo, " NFS_ACCESS_READ"));
584214478Srpaulo					separator = '|';
585214478Srpaulo				}
586214478Srpaulo				if (access_flags & NFSV3ACCESS_LOOKUP) {
587276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_LOOKUP", separator));
588214478Srpaulo					separator = '|';
589214478Srpaulo				}
590214478Srpaulo				if (access_flags & NFSV3ACCESS_MODIFY) {
591276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_MODIFY", separator));
592214478Srpaulo					separator = '|';
593214478Srpaulo				}
594214478Srpaulo				if (access_flags & NFSV3ACCESS_EXTEND) {
595276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_EXTEND", separator));
596214478Srpaulo					separator = '|';
597214478Srpaulo				}
598214478Srpaulo				if (access_flags & NFSV3ACCESS_DELETE) {
599276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_DELETE", separator));
600214478Srpaulo					separator = '|';
601214478Srpaulo				}
602214478Srpaulo				if (access_flags & NFSV3ACCESS_EXECUTE)
603276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_EXECUTE", separator));
604214478Srpaulo			}
60518976Sdfr			return;
60618976Sdfr		}
60718976Sdfr		break;
60818976Sdfr
60917680Spst	case NFSPROC_READ:
610276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
611276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
61218976Sdfr			if (v3) {
613276788Sdelphij				ND_TCHECK(dp[2]);
614276788Sdelphij				ND_PRINT((ndo, " %u bytes @ %" PRIu64,
615146778Ssam				       EXTRACT_32BITS(&dp[2]),
616276788Sdelphij				       EXTRACT_64BITS(&dp[0])));
61718976Sdfr			} else {
618276788Sdelphij				ND_TCHECK(dp[1]);
619276788Sdelphij				ND_PRINT((ndo, " %u bytes @ %u",
620127675Sbms				    EXTRACT_32BITS(&dp[1]),
621276788Sdelphij				    EXTRACT_32BITS(&dp[0])));
62218976Sdfr			}
62317680Spst			return;
62417680Spst		}
62517680Spst		break;
62617680Spst
62717680Spst	case NFSPROC_WRITE:
628276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
629276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
63018976Sdfr			if (v3) {
631327234Semaste				ND_TCHECK(dp[4]);
632276788Sdelphij				ND_PRINT((ndo, " %u (%u) bytes @ %" PRIu64,
633146778Ssam						EXTRACT_32BITS(&dp[4]),
634146778Ssam						EXTRACT_32BITS(&dp[2]),
635276788Sdelphij						EXTRACT_64BITS(&dp[0])));
636276788Sdelphij				if (ndo->ndo_vflag) {
637276788Sdelphij					ND_PRINT((ndo, " <%s>",
63875118Sfenner						tok2str(nfsv3_writemodes,
639327234Semaste							NULL, EXTRACT_32BITS(&dp[3]))));
64018976Sdfr				}
64118976Sdfr			} else {
642276788Sdelphij				ND_TCHECK(dp[3]);
643276788Sdelphij				ND_PRINT((ndo, " %u (%u) bytes @ %u (%u)",
644127675Sbms						EXTRACT_32BITS(&dp[3]),
645127675Sbms						EXTRACT_32BITS(&dp[2]),
646127675Sbms						EXTRACT_32BITS(&dp[1]),
647276788Sdelphij						EXTRACT_32BITS(&dp[0])));
64818976Sdfr			}
64917680Spst			return;
65017680Spst		}
65117680Spst		break;
65217680Spst
65318976Sdfr	case NFSPROC_SYMLINK:
654313537Sglebius		if ((dp = parsereq(ndo, rp, length)) != NULL &&
655313537Sglebius		    (dp = parsefhn(ndo, dp, v3)) != NULL) {
656276788Sdelphij			ND_PRINT((ndo, " ->"));
657313537Sglebius			if (v3 && (dp = parse_sattr3(ndo, dp, &sa3)) == NULL)
65818976Sdfr				break;
659313537Sglebius			if (parsefn(ndo, dp) == NULL)
66018976Sdfr				break;
661276788Sdelphij			if (v3 && ndo->ndo_vflag)
662276788Sdelphij				print_sattr3(ndo, &sa3, ndo->ndo_vflag);
66318976Sdfr			return;
66418976Sdfr		}
66518976Sdfr		break;
66618976Sdfr
66718976Sdfr	case NFSPROC_MKNOD:
668313537Sglebius		if ((dp = parsereq(ndo, rp, length)) != NULL &&
669313537Sglebius		    (dp = parsefhn(ndo, dp, v3)) != NULL) {
670276788Sdelphij			ND_TCHECK(*dp);
671127675Sbms			type = (nfs_type)EXTRACT_32BITS(dp);
672127675Sbms			dp++;
673313537Sglebius			if ((dp = parse_sattr3(ndo, dp, &sa3)) == NULL)
67418976Sdfr				break;
675276788Sdelphij			ND_PRINT((ndo, " %s", tok2str(type2str, "unk-ft %d", type)));
676276788Sdelphij			if (ndo->ndo_vflag && (type == NFCHR || type == NFBLK)) {
677276788Sdelphij				ND_TCHECK(dp[1]);
678276788Sdelphij				ND_PRINT((ndo, " %u/%u",
679127675Sbms				       EXTRACT_32BITS(&dp[0]),
680276788Sdelphij				       EXTRACT_32BITS(&dp[1])));
68118976Sdfr				dp += 2;
68218976Sdfr			}
683276788Sdelphij			if (ndo->ndo_vflag)
684276788Sdelphij				print_sattr3(ndo, &sa3, ndo->ndo_vflag);
68518976Sdfr			return;
68618976Sdfr		}
68718976Sdfr		break;
68818976Sdfr
68917680Spst	case NFSPROC_RENAME:
690276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
691276788Sdelphij		    (dp = parsefhn(ndo, dp, v3)) != NULL) {
692276788Sdelphij			ND_PRINT((ndo, " ->"));
693276788Sdelphij			if (parsefhn(ndo, dp, v3) != NULL)
69417680Spst				return;
69517680Spst		}
69617680Spst		break;
69717680Spst
69817680Spst	case NFSPROC_LINK:
699276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
700276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
701276788Sdelphij			ND_PRINT((ndo, " ->"));
702276788Sdelphij			if (parsefhn(ndo, dp, v3) != NULL)
70317680Spst				return;
70417680Spst		}
70517680Spst		break;
70617680Spst
70718976Sdfr	case NFSPROC_READDIR:
708276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
709276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
71018976Sdfr			if (v3) {
711276788Sdelphij				ND_TCHECK(dp[4]);
71218976Sdfr				/*
71318976Sdfr				 * We shouldn't really try to interpret the
71418976Sdfr				 * offset cookie here.
71518976Sdfr				 */
716276788Sdelphij				ND_PRINT((ndo, " %u bytes @ %" PRId64,
717146778Ssam				    EXTRACT_32BITS(&dp[4]),
718276788Sdelphij				    EXTRACT_64BITS(&dp[0])));
719276788Sdelphij				if (ndo->ndo_vflag)
720276788Sdelphij					ND_PRINT((ndo, " verf %08x%08x", dp[2], dp[3]));
72118976Sdfr			} else {
722276788Sdelphij				ND_TCHECK(dp[1]);
72318976Sdfr				/*
72418976Sdfr				 * Print the offset as signed, since -1 is
72518976Sdfr				 * common, but offsets > 2^31 aren't.
72618976Sdfr				 */
727276788Sdelphij				ND_PRINT((ndo, " %u bytes @ %d",
728127675Sbms				    EXTRACT_32BITS(&dp[1]),
729276788Sdelphij				    EXTRACT_32BITS(&dp[0])));
73018976Sdfr			}
73118976Sdfr			return;
73217680Spst		}
73317680Spst		break;
73417680Spst
73518976Sdfr	case NFSPROC_READDIRPLUS:
736276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
737276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
738276788Sdelphij			ND_TCHECK(dp[4]);
73918976Sdfr			/*
74018976Sdfr			 * We don't try to interpret the offset
74118976Sdfr			 * cookie here.
74218976Sdfr			 */
743276788Sdelphij			ND_PRINT((ndo, " %u bytes @ %" PRId64,
744146778Ssam				EXTRACT_32BITS(&dp[4]),
745276788Sdelphij				EXTRACT_64BITS(&dp[0])));
746276788Sdelphij			if (ndo->ndo_vflag) {
747276788Sdelphij				ND_TCHECK(dp[5]);
748276788Sdelphij				ND_PRINT((ndo, " max %u verf %08x%08x",
749276788Sdelphij				       EXTRACT_32BITS(&dp[5]), dp[2], dp[3]));
750146778Ssam			}
75117680Spst			return;
75218976Sdfr		}
75317680Spst		break;
75417680Spst
75518976Sdfr	case NFSPROC_COMMIT:
756276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
757276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
758276788Sdelphij			ND_TCHECK(dp[2]);
759276788Sdelphij			ND_PRINT((ndo, " %u bytes @ %" PRIu64,
760146778Ssam				EXTRACT_32BITS(&dp[2]),
761276788Sdelphij				EXTRACT_64BITS(&dp[0])));
76217680Spst			return;
76317680Spst		}
76417680Spst		break;
76517680Spst
76617680Spst	default:
76717680Spst		return;
76817680Spst	}
76975118Sfenner
77017680Spsttrunc:
77126183Sfenner	if (!nfserr)
772276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
77317680Spst}
77417680Spst
77517680Spst/*
77617680Spst * Print out an NFS file handle.
77717680Spst * We assume packet was not truncated before the end of the
77817680Spst * file handle pointed to by dp.
77917680Spst *
78017680Spst * Note: new version (using portable file-handle parser) doesn't produce
78117680Spst * generation number.  It probably could be made to do that, with some
78217680Spst * additional hacking on the parser code.
78317680Spst */
78417680Spststatic void
785276788Sdelphijnfs_printfh(netdissect_options *ndo,
786276788Sdelphij            register const uint32_t *dp, const u_int len)
78717680Spst{
78817680Spst	my_fsid fsid;
789276788Sdelphij	uint32_t ino;
790127675Sbms	const char *sfsname = NULL;
791127675Sbms	char *spacep;
79217680Spst
793276788Sdelphij	if (ndo->ndo_uflag) {
794127675Sbms		u_int i;
795127675Sbms		char const *sep = "";
79617680Spst
797276788Sdelphij		ND_PRINT((ndo, " fh["));
798127675Sbms		for (i=0; i<len; i++) {
799276788Sdelphij			ND_PRINT((ndo, "%s%x", sep, dp[i]));
800127675Sbms			sep = ":";
801127675Sbms		}
802276788Sdelphij		ND_PRINT((ndo, "]"));
803127675Sbms		return;
804127675Sbms	}
805127675Sbms
806127675Sbms	Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
807127675Sbms
80817680Spst	if (sfsname) {
80926183Sfenner		/* file system ID is ASCII, not numeric, for this server OS */
810327234Semaste		char temp[NFSX_V3FHMAX+1];
811327234Semaste		u_int stringlen;
81217680Spst
81326183Sfenner		/* Make sure string is null-terminated */
814327234Semaste		stringlen = len;
815327234Semaste		if (stringlen > NFSX_V3FHMAX)
816327234Semaste			stringlen = NFSX_V3FHMAX;
817327234Semaste		strncpy(temp, sfsname, stringlen);
818327234Semaste		temp[stringlen] = '\0';
81926183Sfenner		/* Remove trailing spaces */
820127675Sbms		spacep = strchr(temp, ' ');
821127675Sbms		if (spacep)
822127675Sbms			*spacep = '\0';
82317680Spst
824276788Sdelphij		ND_PRINT((ndo, " fh %s/", temp));
82526183Sfenner	} else {
826276788Sdelphij		ND_PRINT((ndo, " fh %d,%d/",
827276788Sdelphij			     fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor));
82817680Spst	}
82975118Sfenner
830127675Sbms	if(fsid.Fsid_dev.Minor == 257)
831127675Sbms		/* Print the undecoded handle */
832276788Sdelphij		ND_PRINT((ndo, "%s", fsid.Opaque_Handle));
83375118Sfenner	else
834276788Sdelphij		ND_PRINT((ndo, "%ld", (long) ino));
83517680Spst}
83617680Spst
83717680Spst/*
83817680Spst * Maintain a small cache of recent client.XID.server/proc pairs, to allow
83917680Spst * us to match up replies with requests and thus to know how to parse
84017680Spst * the reply.
84117680Spst */
84217680Spst
84317680Spststruct xid_map_entry {
844276788Sdelphij	uint32_t	xid;		/* transaction ID (net order) */
84575118Sfenner	int ipver;			/* IP version (4 or 6) */
84675118Sfenner	struct in6_addr	client;		/* client IP address (net order) */
84775118Sfenner	struct in6_addr	server;		/* server IP address (net order) */
848276788Sdelphij	uint32_t	proc;		/* call proc number (host order) */
849276788Sdelphij	uint32_t	vers;		/* program version (host order) */
85017680Spst};
85117680Spst
85217680Spst/*
85317680Spst * Map entries are kept in an array that we manage as a ring;
85417680Spst * new entries are always added at the tail of the ring.  Initially,
85517680Spst * all the entries are zero and hence don't match anything.
85617680Spst */
85717680Spst
85817680Spst#define	XIDMAPSIZE	64
85917680Spst
860313537Sglebiusstatic struct xid_map_entry xid_map[XIDMAPSIZE];
86117680Spst
862313537Sglebiusstatic int xid_map_next = 0;
863313537Sglebiusstatic int xid_map_hint = 0;
86417680Spst
865190207Srpaulostatic int
866276788Sdelphijxid_map_enter(netdissect_options *ndo,
867276788Sdelphij              const struct sunrpc_msg *rp, const u_char *bp)
86817680Spst{
869313537Sglebius	const struct ip *ip = NULL;
870313537Sglebius	const struct ip6_hdr *ip6 = NULL;
87117680Spst	struct xid_map_entry *xmep;
87217680Spst
873327234Semaste	if (!ND_TTEST(rp->rm_call.cb_proc))
874190207Srpaulo		return (0);
875313537Sglebius	switch (IP_V((const struct ip *)bp)) {
87675118Sfenner	case 4:
877313537Sglebius		ip = (const struct ip *)bp;
87875118Sfenner		break;
87975118Sfenner	case 6:
880313537Sglebius		ip6 = (const struct ip6_hdr *)bp;
88175118Sfenner		break;
88275118Sfenner	default:
883190207Srpaulo		return (1);
88475118Sfenner	}
88575118Sfenner
88617680Spst	xmep = &xid_map[xid_map_next];
88717680Spst
88817680Spst	if (++xid_map_next >= XIDMAPSIZE)
88917680Spst		xid_map_next = 0;
89017680Spst
891276788Sdelphij	UNALIGNED_MEMCPY(&xmep->xid, &rp->rm_xid, sizeof(xmep->xid));
89275118Sfenner	if (ip) {
89375118Sfenner		xmep->ipver = 4;
894276788Sdelphij		UNALIGNED_MEMCPY(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
895276788Sdelphij		UNALIGNED_MEMCPY(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
89675118Sfenner	}
89775118Sfenner	else if (ip6) {
89875118Sfenner		xmep->ipver = 6;
899276788Sdelphij		UNALIGNED_MEMCPY(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
900276788Sdelphij		UNALIGNED_MEMCPY(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
90175118Sfenner	}
902127675Sbms	xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
903127675Sbms	xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
904190207Srpaulo	return (1);
90517680Spst}
90617680Spst
90726183Sfenner/*
90826183Sfenner * Returns 0 and puts NFSPROC_xxx in proc return and
90926183Sfenner * version in vers return, or returns -1 on failure
91026183Sfenner */
91118976Sdfrstatic int
912276788Sdelphijxid_map_find(const struct sunrpc_msg *rp, const u_char *bp, uint32_t *proc,
913276788Sdelphij	     uint32_t *vers)
91417680Spst{
91517680Spst	int i;
91617680Spst	struct xid_map_entry *xmep;
917313537Sglebius	uint32_t xid;
918313537Sglebius	const struct ip *ip = (const struct ip *)bp;
919313537Sglebius	const struct ip6_hdr *ip6 = (const struct ip6_hdr *)bp;
92075118Sfenner	int cmp;
92117680Spst
922313537Sglebius	UNALIGNED_MEMCPY(&xid, &rp->rm_xid, sizeof(xmep->xid));
92317680Spst	/* Start searching from where we last left off */
924127675Sbms	i = xid_map_hint;
92517680Spst	do {
92617680Spst		xmep = &xid_map[i];
92775118Sfenner		cmp = 1;
92875118Sfenner		if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
92975118Sfenner			goto nextitem;
93075118Sfenner		switch (xmep->ipver) {
93175118Sfenner		case 4:
932276788Sdelphij			if (UNALIGNED_MEMCMP(&ip->ip_src, &xmep->server,
93375118Sfenner				   sizeof(ip->ip_src)) != 0 ||
934276788Sdelphij			    UNALIGNED_MEMCMP(&ip->ip_dst, &xmep->client,
93575118Sfenner				   sizeof(ip->ip_dst)) != 0) {
93675118Sfenner				cmp = 0;
93775118Sfenner			}
93875118Sfenner			break;
93975118Sfenner		case 6:
940276788Sdelphij			if (UNALIGNED_MEMCMP(&ip6->ip6_src, &xmep->server,
94175118Sfenner				   sizeof(ip6->ip6_src)) != 0 ||
942276788Sdelphij			    UNALIGNED_MEMCMP(&ip6->ip6_dst, &xmep->client,
94375118Sfenner				   sizeof(ip6->ip6_dst)) != 0) {
94475118Sfenner				cmp = 0;
94575118Sfenner			}
94675118Sfenner			break;
94775118Sfenner		default:
94875118Sfenner			cmp = 0;
94975118Sfenner			break;
95075118Sfenner		}
95175118Sfenner		if (cmp) {
95217680Spst			/* match */
95317680Spst			xid_map_hint = i;
95418976Sdfr			*proc = xmep->proc;
95518976Sdfr			*vers = xmep->vers;
95618976Sdfr			return 0;
95717680Spst		}
95875118Sfenner	nextitem:
95917680Spst		if (++i >= XIDMAPSIZE)
96017680Spst			i = 0;
96117680Spst	} while (i != xid_map_hint);
96217680Spst
96317680Spst	/* search failed */
96475118Sfenner	return (-1);
96517680Spst}
96617680Spst
96717680Spst/*
96817680Spst * Routines for parsing reply packets
96917680Spst */
97017680Spst
97117680Spst/*
97217680Spst * Return a pointer to the beginning of the actual results.
97375118Sfenner * If the packet was truncated, return 0.
97417680Spst */
975276788Sdelphijstatic const uint32_t *
976276788Sdelphijparserep(netdissect_options *ndo,
977276788Sdelphij         register const struct sunrpc_msg *rp, register u_int length)
97817680Spst{
979276788Sdelphij	register const uint32_t *dp;
98075118Sfenner	u_int len;
981146778Ssam	enum sunrpc_accept_stat astat;
98217680Spst
98317680Spst	/*
98417680Spst	 * Portability note:
98517680Spst	 * Here we find the address of the ar_verf credentials.
98617680Spst	 * Originally, this calculation was
987276788Sdelphij	 *	dp = (uint32_t *)&rp->rm_reply.rp_acpt.ar_verf
98817680Spst	 * On the wire, the rp_acpt field starts immediately after
98917680Spst	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
99017680Spst	 * "struct accepted_reply") contains a "struct opaque_auth",
99117680Spst	 * whose internal representation contains a pointer, so on a
99217680Spst	 * 64-bit machine the compiler inserts 32 bits of padding
99317680Spst	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
99417680Spst	 * the internal representation to parse the on-the-wire
99517680Spst	 * representation.  Instead, we skip past the rp_stat field,
99617680Spst	 * which is an "enum" and so occupies one 32-bit word.
99717680Spst	 */
998276788Sdelphij	dp = ((const uint32_t *)&rp->rm_reply) + 1;
999276788Sdelphij	ND_TCHECK(dp[1]);
1000127675Sbms	len = EXTRACT_32BITS(&dp[1]);
100117680Spst	if (len >= length)
100226183Sfenner		return (NULL);
100317680Spst	/*
100417680Spst	 * skip past the ar_verf credentials.
100517680Spst	 */
1006276788Sdelphij	dp += (len + (2*sizeof(uint32_t) + 3)) / sizeof(uint32_t);
100717680Spst
100817680Spst	/*
100917680Spst	 * now we can check the ar_stat field
101017680Spst	 */
1011327234Semaste	ND_TCHECK(dp[0]);
1012147904Ssam	astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
1013276788Sdelphij	if (astat != SUNRPC_SUCCESS) {
1014276788Sdelphij		ND_PRINT((ndo, " %s", tok2str(sunrpc_str, "ar_stat %d", astat)));
101526183Sfenner		nfserr = 1;		/* suppress trunc string */
101626183Sfenner		return (NULL);
101717680Spst	}
101817680Spst	/* successful return */
1019276788Sdelphij	ND_TCHECK2(*dp, sizeof(astat));
1020313537Sglebius	return ((const uint32_t *) (sizeof(astat) + ((const char *)dp)));
102126183Sfennertrunc:
102275118Sfenner	return (0);
102317680Spst}
102417680Spst
1025276788Sdelphijstatic const uint32_t *
1026276788Sdelphijparsestatus(netdissect_options *ndo,
1027276788Sdelphij            const uint32_t *dp, int *er)
102817680Spst{
102975118Sfenner	int errnum;
103017680Spst
1031276788Sdelphij	ND_TCHECK(dp[0]);
103275118Sfenner
1033127675Sbms	errnum = EXTRACT_32BITS(&dp[0]);
103418976Sdfr	if (er)
103526183Sfenner		*er = errnum;
103626183Sfenner	if (errnum != 0) {
1037276788Sdelphij		if (!ndo->ndo_qflag)
1038276788Sdelphij			ND_PRINT((ndo, " ERROR: %s",
1039276788Sdelphij			    tok2str(status2str, "unk %d", errnum)));
104026183Sfenner		nfserr = 1;
104117680Spst	}
104217680Spst	return (dp + 1);
104326183Sfennertrunc:
104475118Sfenner	return NULL;
104517680Spst}
104617680Spst
1047276788Sdelphijstatic const uint32_t *
1048276788Sdelphijparsefattr(netdissect_options *ndo,
1049276788Sdelphij           const uint32_t *dp, int verbose, int v3)
105017680Spst{
105118976Sdfr	const struct nfs_fattr *fap;
105217680Spst
105318976Sdfr	fap = (const struct nfs_fattr *)dp;
1054276788Sdelphij	ND_TCHECK(fap->fa_gid);
105517680Spst	if (verbose) {
1056276788Sdelphij		ND_PRINT((ndo, " %s %o ids %d/%d",
105775118Sfenner		    tok2str(type2str, "unk-ft %d ",
1058127675Sbms		    EXTRACT_32BITS(&fap->fa_type)),
1059127675Sbms		    EXTRACT_32BITS(&fap->fa_mode),
1060127675Sbms		    EXTRACT_32BITS(&fap->fa_uid),
1061276788Sdelphij		    EXTRACT_32BITS(&fap->fa_gid)));
106218976Sdfr		if (v3) {
1063276788Sdelphij			ND_TCHECK(fap->fa3_size);
1064276788Sdelphij			ND_PRINT((ndo, " sz %" PRIu64,
1065313537Sglebius				EXTRACT_64BITS((const uint32_t *)&fap->fa3_size)));
106626184Sfenner		} else {
1067276788Sdelphij			ND_TCHECK(fap->fa2_size);
1068276788Sdelphij			ND_PRINT((ndo, " sz %d", EXTRACT_32BITS(&fap->fa2_size)));
106918976Sdfr		}
107017680Spst	}
107117680Spst	/* print lots more stuff */
107217680Spst	if (verbose > 1) {
107318976Sdfr		if (v3) {
1074276788Sdelphij			ND_TCHECK(fap->fa3_ctime);
1075276788Sdelphij			ND_PRINT((ndo, " nlink %d rdev %d/%d",
1076127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1077127675Sbms			       EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
1078276788Sdelphij			       EXTRACT_32BITS(&fap->fa3_rdev.specdata2)));
1079276788Sdelphij			ND_PRINT((ndo, " fsid %" PRIx64,
1080313537Sglebius				EXTRACT_64BITS((const uint32_t *)&fap->fa3_fsid)));
1081276788Sdelphij			ND_PRINT((ndo, " fileid %" PRIx64,
1082313537Sglebius				EXTRACT_64BITS((const uint32_t *)&fap->fa3_fileid)));
1083276788Sdelphij			ND_PRINT((ndo, " a/m/ctime %u.%06u",
1084127675Sbms			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
1085276788Sdelphij			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec)));
1086276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1087127675Sbms			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
1088276788Sdelphij			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec)));
1089276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1090127675Sbms			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
1091276788Sdelphij			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec)));
109218976Sdfr		} else {
1093276788Sdelphij			ND_TCHECK(fap->fa2_ctime);
1094276788Sdelphij			ND_PRINT((ndo, " nlink %d rdev 0x%x fsid 0x%x nodeid 0x%x a/m/ctime",
1095127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1096127675Sbms			       EXTRACT_32BITS(&fap->fa2_rdev),
1097127675Sbms			       EXTRACT_32BITS(&fap->fa2_fsid),
1098276788Sdelphij			       EXTRACT_32BITS(&fap->fa2_fileid)));
1099276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1100127675Sbms			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
1101276788Sdelphij			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec)));
1102276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1103127675Sbms			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
1104276788Sdelphij			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec)));
1105276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1106127675Sbms			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
1107276788Sdelphij			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec)));
110818976Sdfr		}
110917680Spst	}
1110313537Sglebius	return ((const uint32_t *)((const unsigned char *)dp +
111118976Sdfr		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
111226184Sfennertrunc:
111326184Sfenner	return (NULL);
111417680Spst}
111517680Spst
111617680Spststatic int
1117276788Sdelphijparseattrstat(netdissect_options *ndo,
1118276788Sdelphij              const uint32_t *dp, int verbose, int v3)
111917680Spst{
112018976Sdfr	int er;
112118976Sdfr
1122276788Sdelphij	dp = parsestatus(ndo, dp, &er);
1123111729Sfenner	if (dp == NULL)
112417680Spst		return (0);
1125111729Sfenner	if (er)
1126111729Sfenner		return (1);
112717680Spst
1128276788Sdelphij	return (parsefattr(ndo, dp, verbose, v3) != NULL);
112917680Spst}
113017680Spst
113117680Spststatic int
1132276788Sdelphijparsediropres(netdissect_options *ndo,
1133276788Sdelphij              const uint32_t *dp)
113417680Spst{
113518976Sdfr	int er;
113618976Sdfr
1137276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
113817680Spst		return (0);
1139111729Sfenner	if (er)
1140111729Sfenner		return (1);
114117680Spst
1142276788Sdelphij	dp = parsefh(ndo, dp, 0);
114317680Spst	if (dp == NULL)
114417680Spst		return (0);
114517680Spst
1146276788Sdelphij	return (parsefattr(ndo, dp, ndo->ndo_vflag, 0) != NULL);
114717680Spst}
114817680Spst
114917680Spststatic int
1150276788Sdelphijparselinkres(netdissect_options *ndo,
1151276788Sdelphij             const uint32_t *dp, int v3)
115217680Spst{
115318976Sdfr	int er;
115418976Sdfr
1155276788Sdelphij	dp = parsestatus(ndo, dp, &er);
1156111729Sfenner	if (dp == NULL)
115717680Spst		return(0);
1158111729Sfenner	if (er)
1159111729Sfenner		return(1);
1160276788Sdelphij	if (v3 && !(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
116118976Sdfr		return (0);
1162276788Sdelphij	ND_PRINT((ndo, " "));
1163276788Sdelphij	return (parsefn(ndo, dp) != NULL);
116417680Spst}
116517680Spst
116617680Spststatic int
1167276788Sdelphijparsestatfs(netdissect_options *ndo,
1168276788Sdelphij            const uint32_t *dp, int v3)
116917680Spst{
117018976Sdfr	const struct nfs_statfs *sfsp;
117118976Sdfr	int er;
117217680Spst
1173276788Sdelphij	dp = parsestatus(ndo, dp, &er);
1174111729Sfenner	if (dp == NULL)
117575118Sfenner		return (0);
1176111729Sfenner	if (!v3 && er)
1177111729Sfenner		return (1);
117817680Spst
1179276788Sdelphij	if (ndo->ndo_qflag)
118018976Sdfr		return(1);
118118976Sdfr
118218976Sdfr	if (v3) {
1183276788Sdelphij		if (ndo->ndo_vflag)
1184276788Sdelphij			ND_PRINT((ndo, " POST:"));
1185276788Sdelphij		if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
118618976Sdfr			return (0);
118717680Spst	}
118817680Spst
1189276788Sdelphij	ND_TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
119018976Sdfr
119118976Sdfr	sfsp = (const struct nfs_statfs *)dp;
119218976Sdfr
119318976Sdfr	if (v3) {
1194276788Sdelphij		ND_PRINT((ndo, " tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
1195313537Sglebius			EXTRACT_64BITS((const uint32_t *)&sfsp->sf_tbytes),
1196313537Sglebius			EXTRACT_64BITS((const uint32_t *)&sfsp->sf_fbytes),
1197313537Sglebius			EXTRACT_64BITS((const uint32_t *)&sfsp->sf_abytes)));
1198276788Sdelphij		if (ndo->ndo_vflag) {
1199276788Sdelphij			ND_PRINT((ndo, " tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
1200313537Sglebius			       EXTRACT_64BITS((const uint32_t *)&sfsp->sf_tfiles),
1201313537Sglebius			       EXTRACT_64BITS((const uint32_t *)&sfsp->sf_ffiles),
1202313537Sglebius			       EXTRACT_64BITS((const uint32_t *)&sfsp->sf_afiles),
1203276788Sdelphij			       EXTRACT_32BITS(&sfsp->sf_invarsec)));
120418976Sdfr		}
120518976Sdfr	} else {
1206276788Sdelphij		ND_PRINT((ndo, " tsize %d bsize %d blocks %d bfree %d bavail %d",
1207127675Sbms			EXTRACT_32BITS(&sfsp->sf_tsize),
1208127675Sbms			EXTRACT_32BITS(&sfsp->sf_bsize),
1209127675Sbms			EXTRACT_32BITS(&sfsp->sf_blocks),
1210127675Sbms			EXTRACT_32BITS(&sfsp->sf_bfree),
1211276788Sdelphij			EXTRACT_32BITS(&sfsp->sf_bavail)));
121218976Sdfr	}
121318976Sdfr
121417680Spst	return (1);
121526184Sfennertrunc:
121626184Sfenner	return (0);
121717680Spst}
121817680Spst
121917680Spststatic int
1220276788Sdelphijparserddires(netdissect_options *ndo,
1221276788Sdelphij             const uint32_t *dp)
122217680Spst{
122318976Sdfr	int er;
122418976Sdfr
1225276788Sdelphij	dp = parsestatus(ndo, dp, &er);
1226111729Sfenner	if (dp == NULL)
122717680Spst		return (0);
1228111729Sfenner	if (er)
1229111729Sfenner		return (1);
1230276788Sdelphij	if (ndo->ndo_qflag)
123118976Sdfr		return (1);
123218976Sdfr
1233276788Sdelphij	ND_TCHECK(dp[2]);
1234276788Sdelphij	ND_PRINT((ndo, " offset 0x%x size %d ",
1235276788Sdelphij	       EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1])));
123618976Sdfr	if (dp[2] != 0)
1237276788Sdelphij		ND_PRINT((ndo, " eof"));
123818976Sdfr
123918976Sdfr	return (1);
124026184Sfennertrunc:
124126184Sfenner	return (0);
124218976Sdfr}
124318976Sdfr
1244276788Sdelphijstatic const uint32_t *
1245276788Sdelphijparse_wcc_attr(netdissect_options *ndo,
1246276788Sdelphij               const uint32_t *dp)
124718976Sdfr{
1248327234Semaste	/* Our caller has already checked this */
1249276788Sdelphij	ND_PRINT((ndo, " sz %" PRIu64, EXTRACT_64BITS(&dp[0])));
1250276788Sdelphij	ND_PRINT((ndo, " mtime %u.%06u ctime %u.%06u",
1251127675Sbms	       EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
1252276788Sdelphij	       EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5])));
125318976Sdfr	return (dp + 6);
125418976Sdfr}
125518976Sdfr
125618976Sdfr/*
125718976Sdfr * Pre operation attributes. Print only if vflag > 1.
125818976Sdfr */
1259276788Sdelphijstatic const uint32_t *
1260276788Sdelphijparse_pre_op_attr(netdissect_options *ndo,
1261276788Sdelphij                  const uint32_t *dp, int verbose)
126218976Sdfr{
1263276788Sdelphij	ND_TCHECK(dp[0]);
1264127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
126518976Sdfr		return (dp + 1);
126618976Sdfr	dp++;
1267276788Sdelphij	ND_TCHECK2(*dp, 24);
126818976Sdfr	if (verbose > 1) {
1269276788Sdelphij		return parse_wcc_attr(ndo, dp);
127018976Sdfr	} else {
127118976Sdfr		/* If not verbose enough, just skip over wcc_attr */
127218976Sdfr		return (dp + 6);
127317680Spst	}
127426184Sfennertrunc:
127526184Sfenner	return (NULL);
127618976Sdfr}
127717680Spst
127818976Sdfr/*
127918976Sdfr * Post operation attributes are printed if vflag >= 1
128018976Sdfr */
1281276788Sdelphijstatic const uint32_t *
1282276788Sdelphijparse_post_op_attr(netdissect_options *ndo,
1283276788Sdelphij                   const uint32_t *dp, int verbose)
128418976Sdfr{
1285276788Sdelphij	ND_TCHECK(dp[0]);
1286127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
128718976Sdfr		return (dp + 1);
128818976Sdfr	dp++;
128918976Sdfr	if (verbose) {
1290276788Sdelphij		return parsefattr(ndo, dp, verbose, 1);
129118976Sdfr	} else
1292276788Sdelphij		return (dp + (NFSX_V3FATTR / sizeof (uint32_t)));
129326184Sfennertrunc:
129426184Sfenner	return (NULL);
129518976Sdfr}
129618976Sdfr
1297276788Sdelphijstatic const uint32_t *
1298276788Sdelphijparse_wcc_data(netdissect_options *ndo,
1299276788Sdelphij               const uint32_t *dp, int verbose)
130018976Sdfr{
130118976Sdfr	if (verbose > 1)
1302276788Sdelphij		ND_PRINT((ndo, " PRE:"));
1303276788Sdelphij	if (!(dp = parse_pre_op_attr(ndo, dp, verbose)))
130475118Sfenner		return (0);
130518976Sdfr
130618976Sdfr	if (verbose)
1307276788Sdelphij		ND_PRINT((ndo, " POST:"));
1308276788Sdelphij	return parse_post_op_attr(ndo, dp, verbose);
130918976Sdfr}
131018976Sdfr
1311276788Sdelphijstatic const uint32_t *
1312276788Sdelphijparsecreateopres(netdissect_options *ndo,
1313276788Sdelphij                 const uint32_t *dp, int verbose)
131418976Sdfr{
131518976Sdfr	int er;
131618976Sdfr
1317276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
131875118Sfenner		return (0);
131918976Sdfr	if (er)
1320276788Sdelphij		dp = parse_wcc_data(ndo, dp, verbose);
132118976Sdfr	else {
1322276788Sdelphij		ND_TCHECK(dp[0]);
1323127675Sbms		if (!EXTRACT_32BITS(&dp[0]))
132418976Sdfr			return (dp + 1);
132518976Sdfr		dp++;
1326276788Sdelphij		if (!(dp = parsefh(ndo, dp, 1)))
132775118Sfenner			return (0);
132818976Sdfr		if (verbose) {
1329276788Sdelphij			if (!(dp = parse_post_op_attr(ndo, dp, verbose)))
133075118Sfenner				return (0);
1331276788Sdelphij			if (ndo->ndo_vflag > 1) {
1332276788Sdelphij				ND_PRINT((ndo, " dir attr:"));
1333276788Sdelphij				dp = parse_wcc_data(ndo, dp, verbose);
133418976Sdfr			}
133518976Sdfr		}
133618976Sdfr	}
133718976Sdfr	return (dp);
133826184Sfennertrunc:
133926184Sfenner	return (NULL);
134018976Sdfr}
134118976Sdfr
134218976Sdfrstatic int
1343276788Sdelphijparsewccres(netdissect_options *ndo,
1344276788Sdelphij            const uint32_t *dp, int verbose)
134518976Sdfr{
134618976Sdfr	int er;
134718976Sdfr
1348276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
134918976Sdfr		return (0);
1350313537Sglebius	return parse_wcc_data(ndo, dp, verbose) != NULL;
135118976Sdfr}
135218976Sdfr
1353276788Sdelphijstatic const uint32_t *
1354276788Sdelphijparsev3rddirres(netdissect_options *ndo,
1355276788Sdelphij                const uint32_t *dp, int verbose)
135618976Sdfr{
135718976Sdfr	int er;
135818976Sdfr
1359276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
136075118Sfenner		return (0);
1361276788Sdelphij	if (ndo->ndo_vflag)
1362276788Sdelphij		ND_PRINT((ndo, " POST:"));
1363276788Sdelphij	if (!(dp = parse_post_op_attr(ndo, dp, verbose)))
136475118Sfenner		return (0);
136518976Sdfr	if (er)
136618976Sdfr		return dp;
1367276788Sdelphij	if (ndo->ndo_vflag) {
1368276788Sdelphij		ND_TCHECK(dp[1]);
1369276788Sdelphij		ND_PRINT((ndo, " verf %08x%08x", dp[0], dp[1]));
137018976Sdfr		dp += 2;
137118976Sdfr	}
137218976Sdfr	return dp;
137326184Sfennertrunc:
137426184Sfenner	return (NULL);
137518976Sdfr}
137618976Sdfr
137718976Sdfrstatic int
1378276788Sdelphijparsefsinfo(netdissect_options *ndo,
1379276788Sdelphij            const uint32_t *dp)
138018976Sdfr{
1381313537Sglebius	const struct nfsv3_fsinfo *sfp;
138218976Sdfr	int er;
138318976Sdfr
1384276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
138518976Sdfr		return (0);
1386276788Sdelphij	if (ndo->ndo_vflag)
1387276788Sdelphij		ND_PRINT((ndo, " POST:"));
1388276788Sdelphij	if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
138918976Sdfr		return (0);
139018976Sdfr	if (er)
139118976Sdfr		return (1);
139218976Sdfr
1393313537Sglebius	sfp = (const struct nfsv3_fsinfo *)dp;
1394276788Sdelphij	ND_TCHECK(*sfp);
1395276788Sdelphij	ND_PRINT((ndo, " rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1396127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtmax),
1397127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtpref),
1398127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtmax),
1399127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtpref),
1400276788Sdelphij	       EXTRACT_32BITS(&sfp->fs_dtpref)));
1401276788Sdelphij	if (ndo->ndo_vflag) {
1402276788Sdelphij		ND_PRINT((ndo, " rtmult %u wtmult %u maxfsz %" PRIu64,
1403127675Sbms		       EXTRACT_32BITS(&sfp->fs_rtmult),
1404146778Ssam		       EXTRACT_32BITS(&sfp->fs_wtmult),
1405313537Sglebius		       EXTRACT_64BITS((const uint32_t *)&sfp->fs_maxfilesize)));
1406276788Sdelphij		ND_PRINT((ndo, " delta %u.%06u ",
1407127675Sbms		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
1408276788Sdelphij		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec)));
140918976Sdfr	}
1410111729Sfenner	return (1);
1411111729Sfennertrunc:
141275118Sfenner	return (0);
141318976Sdfr}
141418976Sdfr
141518976Sdfrstatic int
1416276788Sdelphijparsepathconf(netdissect_options *ndo,
1417276788Sdelphij              const uint32_t *dp)
141818976Sdfr{
141918976Sdfr	int er;
1420313537Sglebius	const struct nfsv3_pathconf *spp;
142118976Sdfr
1422276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
142318976Sdfr		return (0);
1424276788Sdelphij	if (ndo->ndo_vflag)
1425276788Sdelphij		ND_PRINT((ndo, " POST:"));
1426276788Sdelphij	if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
142718976Sdfr		return (0);
142818976Sdfr	if (er)
142918976Sdfr		return (1);
143018976Sdfr
1431313537Sglebius	spp = (const struct nfsv3_pathconf *)dp;
1432276788Sdelphij	ND_TCHECK(*spp);
143318976Sdfr
1434276788Sdelphij	ND_PRINT((ndo, " linkmax %u namemax %u %s %s %s %s",
1435127675Sbms	       EXTRACT_32BITS(&spp->pc_linkmax),
1436127675Sbms	       EXTRACT_32BITS(&spp->pc_namemax),
1437127675Sbms	       EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
1438127675Sbms	       EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
1439127675Sbms	       EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
1440276788Sdelphij	       EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : ""));
1441111729Sfenner	return (1);
1442111729Sfennertrunc:
144375118Sfenner	return (0);
144417680Spst}
144575118Sfenner
144617680Spststatic void
1447276788Sdelphijinterp_reply(netdissect_options *ndo,
1448276788Sdelphij             const struct sunrpc_msg *rp, uint32_t proc, uint32_t vers, int length)
144917680Spst{
1450276788Sdelphij	register const uint32_t *dp;
145118976Sdfr	register int v3;
145218976Sdfr	int er;
145317680Spst
145418976Sdfr	v3 = (vers == NFS_VER3);
145518976Sdfr
145618976Sdfr	if (!v3 && proc < NFS_NPROCS)
145718976Sdfr		proc = nfsv3_procid[proc];
145818976Sdfr
1459276788Sdelphij	ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc)));
146017680Spst	switch (proc) {
146117680Spst
146217680Spst	case NFSPROC_GETATTR:
1463276788Sdelphij		dp = parserep(ndo, rp, length);
1464276788Sdelphij		if (dp != NULL && parseattrstat(ndo, dp, !ndo->ndo_qflag, v3) != 0)
146517680Spst			return;
146617680Spst		break;
146717680Spst
146817680Spst	case NFSPROC_SETATTR:
1469276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
147017680Spst			return;
147118976Sdfr		if (v3) {
1472276788Sdelphij			if (parsewccres(ndo, dp, ndo->ndo_vflag))
147318976Sdfr				return;
147418976Sdfr		} else {
1475276788Sdelphij			if (parseattrstat(ndo, dp, !ndo->ndo_qflag, 0) != 0)
147618976Sdfr				return;
147718976Sdfr		}
147817680Spst		break;
147917680Spst
148017680Spst	case NFSPROC_LOOKUP:
1481276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
148218976Sdfr			break;
148318976Sdfr		if (v3) {
1484276788Sdelphij			if (!(dp = parsestatus(ndo, dp, &er)))
148518976Sdfr				break;
148618976Sdfr			if (er) {
1487276788Sdelphij				if (ndo->ndo_vflag > 1) {
1488276788Sdelphij					ND_PRINT((ndo, " post dattr:"));
1489276788Sdelphij					dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag);
149018976Sdfr				}
149118976Sdfr			} else {
1492276788Sdelphij				if (!(dp = parsefh(ndo, dp, v3)))
149318976Sdfr					break;
1494276788Sdelphij				if ((dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)) &&
1495276788Sdelphij				    ndo->ndo_vflag > 1) {
1496276788Sdelphij					ND_PRINT((ndo, " post dattr:"));
1497276788Sdelphij					dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag);
149818976Sdfr				}
149918976Sdfr			}
150075118Sfenner			if (dp)
150118976Sdfr				return;
150218976Sdfr		} else {
1503276788Sdelphij			if (parsediropres(ndo, dp) != 0)
150418976Sdfr				return;
150518976Sdfr		}
150617680Spst		break;
150717680Spst
150818976Sdfr	case NFSPROC_ACCESS:
1509276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
151098527Sfenner			break;
1511276788Sdelphij		if (!(dp = parsestatus(ndo, dp, &er)))
151218976Sdfr			break;
1513276788Sdelphij		if (ndo->ndo_vflag)
1514276788Sdelphij			ND_PRINT((ndo, " attr:"));
1515276788Sdelphij		if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
151618976Sdfr			break;
1517327234Semaste		if (!er) {
1518327234Semaste			ND_TCHECK(dp[0]);
1519276788Sdelphij			ND_PRINT((ndo, " c %04x", EXTRACT_32BITS(&dp[0])));
1520327234Semaste		}
152118976Sdfr		return;
152218976Sdfr
152317680Spst	case NFSPROC_READLINK:
1524276788Sdelphij		dp = parserep(ndo, rp, length);
1525276788Sdelphij		if (dp != NULL && parselinkres(ndo, dp, v3) != 0)
152617680Spst			return;
152717680Spst		break;
152817680Spst
152917680Spst	case NFSPROC_READ:
1530276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
153118976Sdfr			break;
153218976Sdfr		if (v3) {
1533276788Sdelphij			if (!(dp = parsestatus(ndo, dp, &er)))
153418976Sdfr				break;
1535276788Sdelphij			if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
153618976Sdfr				break;
153718976Sdfr			if (er)
153818976Sdfr				return;
1539276788Sdelphij			if (ndo->ndo_vflag) {
1540276788Sdelphij				ND_TCHECK(dp[1]);
1541276788Sdelphij				ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0])));
1542127675Sbms				if (EXTRACT_32BITS(&dp[1]))
1543276788Sdelphij					ND_PRINT((ndo, " EOF"));
154418976Sdfr			}
154517680Spst			return;
154618976Sdfr		} else {
1547276788Sdelphij			if (parseattrstat(ndo, dp, ndo->ndo_vflag, 0) != 0)
154818976Sdfr				return;
154918976Sdfr		}
155017680Spst		break;
155117680Spst
155217680Spst	case NFSPROC_WRITE:
1553276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
155418976Sdfr			break;
155518976Sdfr		if (v3) {
1556276788Sdelphij			if (!(dp = parsestatus(ndo, dp, &er)))
155718976Sdfr				break;
1558276788Sdelphij			if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
155918976Sdfr				break;
156018976Sdfr			if (er)
156118976Sdfr				return;
1562276788Sdelphij			if (ndo->ndo_vflag) {
1563276788Sdelphij				ND_TCHECK(dp[0]);
1564276788Sdelphij				ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0])));
1565276788Sdelphij				if (ndo->ndo_vflag > 1) {
1566276788Sdelphij					ND_TCHECK(dp[1]);
1567276788Sdelphij					ND_PRINT((ndo, " <%s>",
156875118Sfenner						tok2str(nfsv3_writemodes,
1569276788Sdelphij							NULL, EXTRACT_32BITS(&dp[1]))));
157018976Sdfr				}
157118976Sdfr			}
1572356341Scy			return;
157318976Sdfr		} else {
1574276788Sdelphij			if (parseattrstat(ndo, dp, ndo->ndo_vflag, v3) != 0)
157518976Sdfr				return;
157618976Sdfr		}
157717680Spst		break;
157817680Spst
157917680Spst	case NFSPROC_CREATE:
158018976Sdfr	case NFSPROC_MKDIR:
1581276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
158218976Sdfr			break;
158318976Sdfr		if (v3) {
1584313537Sglebius			if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != NULL)
158518976Sdfr				return;
158618976Sdfr		} else {
1587276788Sdelphij			if (parsediropres(ndo, dp) != 0)
158818976Sdfr				return;
158918976Sdfr		}
159018976Sdfr		break;
159118976Sdfr
159218976Sdfr	case NFSPROC_SYMLINK:
1593276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
159418976Sdfr			break;
159518976Sdfr		if (v3) {
1596313537Sglebius			if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != NULL)
159718976Sdfr				return;
159818976Sdfr		} else {
1599313537Sglebius			if (parsestatus(ndo, dp, &er) != NULL)
160018976Sdfr				return;
160118976Sdfr		}
160218976Sdfr		break;
160318976Sdfr
160418976Sdfr	case NFSPROC_MKNOD:
1605276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
160618976Sdfr			break;
1607313537Sglebius		if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != NULL)
160817680Spst			return;
160917680Spst		break;
161017680Spst
161117680Spst	case NFSPROC_REMOVE:
161218976Sdfr	case NFSPROC_RMDIR:
1613276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
161418976Sdfr			break;
161518976Sdfr		if (v3) {
1616276788Sdelphij			if (parsewccres(ndo, dp, ndo->ndo_vflag))
161718976Sdfr				return;
161818976Sdfr		} else {
1619313537Sglebius			if (parsestatus(ndo, dp, &er) != NULL)
162018976Sdfr				return;
162118976Sdfr		}
162218976Sdfr		break;
162318976Sdfr
162417680Spst	case NFSPROC_RENAME:
1625276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
162618976Sdfr			break;
162718976Sdfr		if (v3) {
1628276788Sdelphij			if (!(dp = parsestatus(ndo, dp, &er)))
162918976Sdfr				break;
1630276788Sdelphij			if (ndo->ndo_vflag) {
1631276788Sdelphij				ND_PRINT((ndo, " from:"));
1632276788Sdelphij				if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
163318976Sdfr					break;
1634276788Sdelphij				ND_PRINT((ndo, " to:"));
1635276788Sdelphij				if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
163618976Sdfr					break;
163718976Sdfr			}
163817680Spst			return;
163918976Sdfr		} else {
1640313537Sglebius			if (parsestatus(ndo, dp, &er) != NULL)
164118976Sdfr				return;
164218976Sdfr		}
164317680Spst		break;
164417680Spst
164517680Spst	case NFSPROC_LINK:
1646276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
164718976Sdfr			break;
164818976Sdfr		if (v3) {
1649276788Sdelphij			if (!(dp = parsestatus(ndo, dp, &er)))
165018976Sdfr				break;
1651276788Sdelphij			if (ndo->ndo_vflag) {
1652276788Sdelphij				ND_PRINT((ndo, " file POST:"));
1653276788Sdelphij				if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
165418976Sdfr					break;
1655276788Sdelphij				ND_PRINT((ndo, " dir:"));
1656276788Sdelphij				if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
165718976Sdfr					break;
165818976Sdfr			}
1659356341Scy			return;
166018976Sdfr		} else {
1661313537Sglebius			if (parsestatus(ndo, dp, &er) != NULL)
166218976Sdfr				return;
166318976Sdfr		}
166417680Spst		break;
166517680Spst
166618976Sdfr	case NFSPROC_READDIR:
1667276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
166818976Sdfr			break;
166918976Sdfr		if (v3) {
1670276788Sdelphij			if (parsev3rddirres(ndo, dp, ndo->ndo_vflag))
167118976Sdfr				return;
167218976Sdfr		} else {
1673276788Sdelphij			if (parserddires(ndo, dp) != 0)
167418976Sdfr				return;
167518976Sdfr		}
167618976Sdfr		break;
167718976Sdfr
167818976Sdfr	case NFSPROC_READDIRPLUS:
1679276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
168018976Sdfr			break;
1681276788Sdelphij		if (parsev3rddirres(ndo, dp, ndo->ndo_vflag))
168217680Spst			return;
168317680Spst		break;
168417680Spst
168518976Sdfr	case NFSPROC_FSSTAT:
1686276788Sdelphij		dp = parserep(ndo, rp, length);
1687276788Sdelphij		if (dp != NULL && parsestatfs(ndo, dp, v3) != 0)
168817680Spst			return;
168917680Spst		break;
169017680Spst
169118976Sdfr	case NFSPROC_FSINFO:
1692276788Sdelphij		dp = parserep(ndo, rp, length);
1693276788Sdelphij		if (dp != NULL && parsefsinfo(ndo, dp) != 0)
169417680Spst			return;
169517680Spst		break;
169617680Spst
169718976Sdfr	case NFSPROC_PATHCONF:
1698276788Sdelphij		dp = parserep(ndo, rp, length);
1699276788Sdelphij		if (dp != NULL && parsepathconf(ndo, dp) != 0)
170017680Spst			return;
170117680Spst		break;
170217680Spst
170318976Sdfr	case NFSPROC_COMMIT:
1704276788Sdelphij		dp = parserep(ndo, rp, length);
1705276788Sdelphij		if (dp != NULL && parsewccres(ndo, dp, ndo->ndo_vflag) != 0)
170617680Spst			return;
170717680Spst		break;
170817680Spst
170917680Spst	default:
171017680Spst		return;
171117680Spst	}
171218976Sdfrtrunc:
171326183Sfenner	if (!nfserr)
1714276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
171517680Spst}
1716