print-nfs.c revision 276788
117680Spst/*
239300Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2075118Sfenner *
2175118Sfenner * $FreeBSD: head/contrib/tcpdump/print-nfs.c 276788 2015-01-07 19:55:18Z delphij $
2217680Spst */
2317680Spst
24276788Sdelphij#define NETDISSECT_REWORKED
2575118Sfenner#ifdef HAVE_CONFIG_H
2675118Sfenner#include "config.h"
2775118Sfenner#endif
2875118Sfenner
29127675Sbms#include <tcpdump-stdinc.h>
3017680Spst
3117680Spst#include <stdio.h>
3217680Spst#include <string.h>
3317680Spst
3417680Spst#include "interface.h"
3517680Spst#include "addrtoname.h"
36127675Sbms#include "extract.h"
3717680Spst
3818976Sdfr#include "nfs.h"
3917680Spst#include "nfsfh.h"
4017680Spst
4175118Sfenner#include "ip.h"
4275118Sfenner#ifdef INET6
4375118Sfenner#include "ip6.h"
4475118Sfenner#endif
45146778Ssam#include "rpc_auth.h"
46146778Ssam#include "rpc_msg.h"
4775118Sfenner
48276788Sdelphijstatic const char tstr[] = " [|nfs]";
4917680Spst
50276788Sdelphijstatic void nfs_printfh(netdissect_options *, const uint32_t *, const u_int);
51276788Sdelphijstatic int xid_map_enter(netdissect_options *, const struct sunrpc_msg *, const u_char *);
52276788Sdelphijstatic int xid_map_find(const struct sunrpc_msg *, const u_char *,
53276788Sdelphij			    uint32_t *, uint32_t *);
54276788Sdelphijstatic void interp_reply(netdissect_options *, const struct sunrpc_msg *, uint32_t, uint32_t, int);
55276788Sdelphijstatic const uint32_t *parse_post_op_attr(netdissect_options *, const uint32_t *, int);
56276788Sdelphij
5718976Sdfr/*
5818976Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
5918976Sdfr */
60276788Sdelphijuint32_t nfsv3_procid[NFS_NPROCS] = {
6118976Sdfr	NFSPROC_NULL,
6218976Sdfr	NFSPROC_GETATTR,
6318976Sdfr	NFSPROC_SETATTR,
6418976Sdfr	NFSPROC_NOOP,
6518976Sdfr	NFSPROC_LOOKUP,
6618976Sdfr	NFSPROC_READLINK,
6718976Sdfr	NFSPROC_READ,
6818976Sdfr	NFSPROC_NOOP,
6918976Sdfr	NFSPROC_WRITE,
7018976Sdfr	NFSPROC_CREATE,
7118976Sdfr	NFSPROC_REMOVE,
7218976Sdfr	NFSPROC_RENAME,
7318976Sdfr	NFSPROC_LINK,
7418976Sdfr	NFSPROC_SYMLINK,
7518976Sdfr	NFSPROC_MKDIR,
7618976Sdfr	NFSPROC_RMDIR,
7718976Sdfr	NFSPROC_READDIR,
7818976Sdfr	NFSPROC_FSSTAT,
7918976Sdfr	NFSPROC_NOOP,
8018976Sdfr	NFSPROC_NOOP,
8118976Sdfr	NFSPROC_NOOP,
8218976Sdfr	NFSPROC_NOOP,
8318976Sdfr	NFSPROC_NOOP,
8418976Sdfr	NFSPROC_NOOP,
8518976Sdfr	NFSPROC_NOOP,
8618976Sdfr	NFSPROC_NOOP
8718976Sdfr};
8818976Sdfr
89276788Sdelphijstatic const struct tok nfsproc_str[] = {
90276788Sdelphij	{ NFSPROC_NOOP,        "nop"         },
91276788Sdelphij	{ NFSPROC_NULL,        "null"        },
92276788Sdelphij	{ NFSPROC_GETATTR,     "getattr"     },
93276788Sdelphij	{ NFSPROC_SETATTR,     "setattr"     },
94276788Sdelphij	{ NFSPROC_LOOKUP,      "lookup"      },
95276788Sdelphij	{ NFSPROC_ACCESS,      "access"      },
96276788Sdelphij	{ NFSPROC_READLINK,    "readlink"    },
97276788Sdelphij	{ NFSPROC_READ,        "read"        },
98276788Sdelphij	{ NFSPROC_WRITE,       "write"       },
99276788Sdelphij	{ NFSPROC_CREATE,      "create"      },
100276788Sdelphij	{ NFSPROC_MKDIR,       "mkdir"       },
101276788Sdelphij	{ NFSPROC_SYMLINK,     "symlink"     },
102276788Sdelphij	{ NFSPROC_MKNOD,       "mknod"       },
103276788Sdelphij	{ NFSPROC_REMOVE,      "remove"      },
104276788Sdelphij	{ NFSPROC_RMDIR,       "rmdir"       },
105276788Sdelphij	{ NFSPROC_RENAME,      "rename"      },
106276788Sdelphij	{ NFSPROC_LINK,        "link"        },
107276788Sdelphij	{ NFSPROC_READDIR,     "readdir"     },
108276788Sdelphij	{ NFSPROC_READDIRPLUS, "readdirplus" },
109276788Sdelphij	{ NFSPROC_FSSTAT,      "fsstat"      },
110276788Sdelphij	{ NFSPROC_FSINFO,      "fsinfo"      },
111276788Sdelphij	{ NFSPROC_PATHCONF,    "pathconf"    },
112276788Sdelphij	{ NFSPROC_COMMIT,      "commit"      },
113276788Sdelphij	{ 0, NULL }
114276788Sdelphij};
115276788Sdelphij
11675118Sfenner/*
11775118Sfenner * NFS V2 and V3 status values.
11875118Sfenner *
11975118Sfenner * Some of these come from the RFCs for NFS V2 and V3, with the message
12075118Sfenner * strings taken from the FreeBSD C library "errlst.c".
12175118Sfenner *
12275118Sfenner * Others are errors that are not in the RFC but that I suspect some
12375118Sfenner * NFS servers could return; the values are FreeBSD errno values, as
12475118Sfenner * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
12575118Sfenner * was primarily BSD-derived.
12675118Sfenner */
127276788Sdelphijstatic const struct tok status2str[] = {
12875118Sfenner	{ 1,     "Operation not permitted" },	/* EPERM */
12975118Sfenner	{ 2,     "No such file or directory" },	/* ENOENT */
13075118Sfenner	{ 5,     "Input/output error" },	/* EIO */
13175118Sfenner	{ 6,     "Device not configured" },	/* ENXIO */
13275118Sfenner	{ 11,    "Resource deadlock avoided" },	/* EDEADLK */
13375118Sfenner	{ 12,    "Cannot allocate memory" },	/* ENOMEM */
13475118Sfenner	{ 13,    "Permission denied" },		/* EACCES */
13575118Sfenner	{ 17,    "File exists" },		/* EEXIST */
13675118Sfenner	{ 18,    "Cross-device link" },		/* EXDEV */
13775118Sfenner	{ 19,    "Operation not supported by device" }, /* ENODEV */
13875118Sfenner	{ 20,    "Not a directory" },		/* ENOTDIR */
13975118Sfenner	{ 21,    "Is a directory" },		/* EISDIR */
14075118Sfenner	{ 22,    "Invalid argument" },		/* EINVAL */
14175118Sfenner	{ 26,    "Text file busy" },		/* ETXTBSY */
14275118Sfenner	{ 27,    "File too large" },		/* EFBIG */
14375118Sfenner	{ 28,    "No space left on device" },	/* ENOSPC */
14475118Sfenner	{ 30,    "Read-only file system" },	/* EROFS */
14575118Sfenner	{ 31,    "Too many links" },		/* EMLINK */
14675118Sfenner	{ 45,    "Operation not supported" },	/* EOPNOTSUPP */
14775118Sfenner	{ 62,    "Too many levels of symbolic links" }, /* ELOOP */
14875118Sfenner	{ 63,    "File name too long" },	/* ENAMETOOLONG */
14975118Sfenner	{ 66,    "Directory not empty" },	/* ENOTEMPTY */
15075118Sfenner	{ 69,    "Disc quota exceeded" },	/* EDQUOT */
15175118Sfenner	{ 70,    "Stale NFS file handle" },	/* ESTALE */
15275118Sfenner	{ 71,    "Too many levels of remote in path" }, /* EREMOTE */
15375118Sfenner	{ 99,    "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
15475118Sfenner	{ 10001, "Illegal NFS file handle" },	/* NFS3ERR_BADHANDLE */
15575118Sfenner	{ 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
15675118Sfenner	{ 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
15775118Sfenner	{ 10004, "Operation not supported" },	/* NFS3ERR_NOTSUPP */
15875118Sfenner	{ 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
15975118Sfenner	{ 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
16075118Sfenner	{ 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
16175118Sfenner	{ 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
16275118Sfenner	{ 0,     NULL }
16318976Sdfr};
16418976Sdfr
165276788Sdelphijstatic const struct tok nfsv3_writemodes[] = {
16675118Sfenner	{ 0,		"unstable" },
16775118Sfenner	{ 1,		"datasync" },
16875118Sfenner	{ 2,		"filesync" },
16975118Sfenner	{ 0,		NULL }
17075118Sfenner};
17175118Sfenner
172276788Sdelphijstatic const struct tok type2str[] = {
17318976Sdfr	{ NFNON,	"NON" },
17418976Sdfr	{ NFREG,	"REG" },
17518976Sdfr	{ NFDIR,	"DIR" },
17618976Sdfr	{ NFBLK,	"BLK" },
17718976Sdfr	{ NFCHR,	"CHR" },
17818976Sdfr	{ NFLNK,	"LNK" },
17918976Sdfr	{ NFFIFO,	"FIFO" },
18018976Sdfr	{ 0,		NULL }
18118976Sdfr};
18218976Sdfr
183276788Sdelphijstatic const struct tok sunrpc_auth_str[] = {
184276788Sdelphij	{ SUNRPC_AUTH_OK,           "OK"                                                     },
185276788Sdelphij	{ SUNRPC_AUTH_BADCRED,      "Bogus Credentials (seal broken)"                        },
186276788Sdelphij	{ SUNRPC_AUTH_REJECTEDCRED, "Rejected Credentials (client should begin new session)" },
187276788Sdelphij	{ SUNRPC_AUTH_BADVERF,      "Bogus Verifier (seal broken)"                           },
188276788Sdelphij	{ SUNRPC_AUTH_REJECTEDVERF, "Verifier expired or was replayed"                       },
189276788Sdelphij	{ SUNRPC_AUTH_TOOWEAK,      "Credentials are too weak"                               },
190276788Sdelphij	{ SUNRPC_AUTH_INVALIDRESP,  "Bogus response verifier"                                },
191276788Sdelphij	{ SUNRPC_AUTH_FAILED,       "Unknown failure"                                        },
192276788Sdelphij	{ 0, NULL }
193276788Sdelphij};
194276788Sdelphij
195276788Sdelphijstatic const struct tok sunrpc_str[] = {
196276788Sdelphij	{ SUNRPC_PROG_UNAVAIL,  "PROG_UNAVAIL"  },
197276788Sdelphij	{ SUNRPC_PROG_MISMATCH, "PROG_MISMATCH" },
198276788Sdelphij	{ SUNRPC_PROC_UNAVAIL,  "PROC_UNAVAIL"  },
199276788Sdelphij	{ SUNRPC_GARBAGE_ARGS,  "GARBAGE_ARGS"  },
200276788Sdelphij	{ SUNRPC_SYSTEM_ERR,    "SYSTEM_ERR"    },
201276788Sdelphij	{ 0, NULL }
202276788Sdelphij};
203276788Sdelphij
20475118Sfennerstatic void
205276788Sdelphijprint_nfsaddr(netdissect_options *ndo,
206276788Sdelphij              const u_char *bp, const char *s, const char *d)
20775118Sfenner{
20875118Sfenner	struct ip *ip;
20975118Sfenner#ifdef INET6
21075118Sfenner	struct ip6_hdr *ip6;
21175118Sfenner	char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
21275118Sfenner#else
21375118Sfenner#ifndef INET_ADDRSTRLEN
21475118Sfenner#define INET_ADDRSTRLEN	16
21575118Sfenner#endif
21675118Sfenner	char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN];
21775118Sfenner#endif
21875118Sfenner
21975118Sfenner	srcaddr[0] = dstaddr[0] = '\0';
22075118Sfenner	switch (IP_V((struct ip *)bp)) {
22175118Sfenner	case 4:
22275118Sfenner		ip = (struct ip *)bp;
223276788Sdelphij		strlcpy(srcaddr, ipaddr_string(ndo, &ip->ip_src), sizeof(srcaddr));
224276788Sdelphij		strlcpy(dstaddr, ipaddr_string(ndo, &ip->ip_dst), sizeof(dstaddr));
22575118Sfenner		break;
22675118Sfenner#ifdef INET6
22775118Sfenner	case 6:
22875118Sfenner		ip6 = (struct ip6_hdr *)bp;
229276788Sdelphij		strlcpy(srcaddr, ip6addr_string(ndo, &ip6->ip6_src),
23075118Sfenner		    sizeof(srcaddr));
231276788Sdelphij		strlcpy(dstaddr, ip6addr_string(ndo, &ip6->ip6_dst),
23275118Sfenner		    sizeof(dstaddr));
23375118Sfenner		break;
23475118Sfenner#endif
23575118Sfenner	default:
23675118Sfenner		strlcpy(srcaddr, "?", sizeof(srcaddr));
23775118Sfenner		strlcpy(dstaddr, "?", sizeof(dstaddr));
23875118Sfenner		break;
23975118Sfenner	}
24075118Sfenner
241276788Sdelphij	ND_PRINT((ndo, "%s.%s > %s.%s: ", srcaddr, s, dstaddr, d));
24275118Sfenner}
24375118Sfenner
244276788Sdelphijstatic const uint32_t *
245276788Sdelphijparse_sattr3(netdissect_options *ndo,
246276788Sdelphij             const uint32_t *dp, struct nfsv3_sattr *sa3)
24718976Sdfr{
248276788Sdelphij	ND_TCHECK(dp[0]);
249127675Sbms	sa3->sa_modeset = EXTRACT_32BITS(dp);
250127675Sbms	dp++;
251127675Sbms	if (sa3->sa_modeset) {
252276788Sdelphij		ND_TCHECK(dp[0]);
253127675Sbms		sa3->sa_mode = EXTRACT_32BITS(dp);
254127675Sbms		dp++;
25518976Sdfr	}
25618976Sdfr
257276788Sdelphij	ND_TCHECK(dp[0]);
258127675Sbms	sa3->sa_uidset = EXTRACT_32BITS(dp);
259127675Sbms	dp++;
260127675Sbms	if (sa3->sa_uidset) {
261276788Sdelphij		ND_TCHECK(dp[0]);
262127675Sbms		sa3->sa_uid = EXTRACT_32BITS(dp);
263127675Sbms		dp++;
26418976Sdfr	}
26518976Sdfr
266276788Sdelphij	ND_TCHECK(dp[0]);
267127675Sbms	sa3->sa_gidset = EXTRACT_32BITS(dp);
268127675Sbms	dp++;
269127675Sbms	if (sa3->sa_gidset) {
270276788Sdelphij		ND_TCHECK(dp[0]);
271127675Sbms		sa3->sa_gid = EXTRACT_32BITS(dp);
272127675Sbms		dp++;
27318976Sdfr	}
27418976Sdfr
275276788Sdelphij	ND_TCHECK(dp[0]);
276127675Sbms	sa3->sa_sizeset = EXTRACT_32BITS(dp);
277127675Sbms	dp++;
278127675Sbms	if (sa3->sa_sizeset) {
279276788Sdelphij		ND_TCHECK(dp[0]);
280127675Sbms		sa3->sa_size = EXTRACT_32BITS(dp);
281127675Sbms		dp++;
28218976Sdfr	}
28318976Sdfr
284276788Sdelphij	ND_TCHECK(dp[0]);
285127675Sbms	sa3->sa_atimetype = EXTRACT_32BITS(dp);
286127675Sbms	dp++;
287127675Sbms	if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) {
288276788Sdelphij		ND_TCHECK(dp[1]);
289127675Sbms		sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp);
290127675Sbms		dp++;
291127675Sbms		sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp);
292127675Sbms		dp++;
29318976Sdfr	}
29418976Sdfr
295276788Sdelphij	ND_TCHECK(dp[0]);
296127675Sbms	sa3->sa_mtimetype = EXTRACT_32BITS(dp);
297127675Sbms	dp++;
298127675Sbms	if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) {
299276788Sdelphij		ND_TCHECK(dp[1]);
300127675Sbms		sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp);
301127675Sbms		dp++;
302127675Sbms		sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp);
303127675Sbms		dp++;
30418976Sdfr	}
30518976Sdfr
30618976Sdfr	return dp;
30775118Sfennertrunc:
30875118Sfenner	return NULL;
30918976Sdfr}
31018976Sdfr
31175118Sfennerstatic int nfserr;		/* true if we error rather than trunc */
31275118Sfenner
31375118Sfennerstatic void
314276788Sdelphijprint_sattr3(netdissect_options *ndo,
315276788Sdelphij             const struct nfsv3_sattr *sa3, int verbose)
31618976Sdfr{
31718976Sdfr	if (sa3->sa_modeset)
318276788Sdelphij		ND_PRINT((ndo, " mode %o", sa3->sa_mode));
31918976Sdfr	if (sa3->sa_uidset)
320276788Sdelphij		ND_PRINT((ndo, " uid %u", sa3->sa_uid));
32118976Sdfr	if (sa3->sa_gidset)
322276788Sdelphij		ND_PRINT((ndo, " gid %u", sa3->sa_gid));
32318976Sdfr	if (verbose > 1) {
32418976Sdfr		if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
325276788Sdelphij			ND_PRINT((ndo, " atime %u.%06u", sa3->sa_atime.nfsv3_sec,
326276788Sdelphij			       sa3->sa_atime.nfsv3_nsec));
32718976Sdfr		if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
328276788Sdelphij			ND_PRINT((ndo, " mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
329276788Sdelphij			       sa3->sa_mtime.nfsv3_nsec));
33018976Sdfr	}
33118976Sdfr}
33218976Sdfr
33318976Sdfrvoid
334276788Sdelphijnfsreply_print(netdissect_options *ndo,
335276788Sdelphij               register const u_char *bp, u_int length,
336276788Sdelphij               register const u_char *bp2)
33717680Spst{
338146778Ssam	register const struct sunrpc_msg *rp;
33975118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
34017680Spst
34126183Sfenner	nfserr = 0;		/* assume no error */
342146778Ssam	rp = (const struct sunrpc_msg *)bp;
34317680Spst
344276788Sdelphij	ND_TCHECK(rp->rm_xid);
345276788Sdelphij	if (!ndo->ndo_nflag) {
34675118Sfenner		strlcpy(srcid, "nfs", sizeof(srcid));
34775118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
348127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
34975118Sfenner	} else {
35075118Sfenner		snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
35175118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
352127675Sbms		    EXTRACT_32BITS(&rp->rm_xid));
35375118Sfenner	}
354276788Sdelphij	print_nfsaddr(ndo, bp2, srcid, dstid);
355276788Sdelphij
356276788Sdelphij	nfsreply_print_noaddr(ndo, bp, length, bp2);
357276788Sdelphij	return;
358276788Sdelphij
359276788Sdelphijtrunc:
360276788Sdelphij	if (!nfserr)
361276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
362276788Sdelphij}
363276788Sdelphij
364276788Sdelphijvoid
365276788Sdelphijnfsreply_print_noaddr(netdissect_options *ndo,
366276788Sdelphij                      register const u_char *bp, u_int length,
367276788Sdelphij                      register const u_char *bp2)
368276788Sdelphij{
369276788Sdelphij	register const struct sunrpc_msg *rp;
370276788Sdelphij	uint32_t proc, vers, reply_stat;
371276788Sdelphij	enum sunrpc_reject_stat rstat;
372276788Sdelphij	uint32_t rlow;
373276788Sdelphij	uint32_t rhigh;
374276788Sdelphij	enum sunrpc_auth_stat rwhy;
375276788Sdelphij
376276788Sdelphij	nfserr = 0;		/* assume no error */
377276788Sdelphij	rp = (const struct sunrpc_msg *)bp;
378276788Sdelphij
379276788Sdelphij	ND_TCHECK(rp->rm_reply.rp_stat);
380172686Smlaier	reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat);
381172686Smlaier	switch (reply_stat) {
38217680Spst
383172686Smlaier	case SUNRPC_MSG_ACCEPTED:
384276788Sdelphij		ND_PRINT((ndo, "reply ok %u", length));
385172686Smlaier		if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
386276788Sdelphij			interp_reply(ndo, rp, proc, vers, length);
387172686Smlaier		break;
388172686Smlaier
389172686Smlaier	case SUNRPC_MSG_DENIED:
390276788Sdelphij		ND_PRINT((ndo, "reply ERR %u: ", length));
391276788Sdelphij		ND_TCHECK(rp->rm_reply.rp_reject.rj_stat);
392172686Smlaier		rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat);
393172686Smlaier		switch (rstat) {
394172686Smlaier
395172686Smlaier		case SUNRPC_RPC_MISMATCH:
396276788Sdelphij			ND_TCHECK(rp->rm_reply.rp_reject.rj_vers.high);
397172686Smlaier			rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low);
398172686Smlaier			rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high);
399276788Sdelphij			ND_PRINT((ndo, "RPC Version mismatch (%u-%u)", rlow, rhigh));
400172686Smlaier			break;
401172686Smlaier
402172686Smlaier		case SUNRPC_AUTH_ERROR:
403276788Sdelphij			ND_TCHECK(rp->rm_reply.rp_reject.rj_why);
404172686Smlaier			rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why);
405276788Sdelphij			ND_PRINT((ndo, "Auth %s", tok2str(sunrpc_auth_str, "Invalid failure code %u", rwhy)));
406172686Smlaier			break;
407172686Smlaier
408172686Smlaier		default:
409276788Sdelphij			ND_PRINT((ndo, "Unknown reason for rejecting rpc message %u", (unsigned int)rstat));
410172686Smlaier			break;
411172686Smlaier		}
412172686Smlaier		break;
413172686Smlaier
414172686Smlaier	default:
415276788Sdelphij		ND_PRINT((ndo, "reply Unknown rpc response code=%u %u", reply_stat, length));
416172686Smlaier		break;
417172686Smlaier	}
418190207Srpaulo	return;
419190207Srpaulo
420190207Srpaulotrunc:
421190207Srpaulo	if (!nfserr)
422276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
42317680Spst}
42417680Spst
42517680Spst/*
42617680Spst * Return a pointer to the first file handle in the packet.
42775118Sfenner * If the packet was truncated, return 0.
42817680Spst */
429276788Sdelphijstatic const uint32_t *
430276788Sdelphijparsereq(netdissect_options *ndo,
431276788Sdelphij         register const struct sunrpc_msg *rp, register u_int length)
43217680Spst{
433276788Sdelphij	register const uint32_t *dp;
43417680Spst	register u_int len;
43517680Spst
43617680Spst	/*
43717680Spst	 * find the start of the req data (if we captured it)
43817680Spst	 */
439276788Sdelphij	dp = (uint32_t *)&rp->rm_call.cb_cred;
440276788Sdelphij	ND_TCHECK(dp[1]);
441127675Sbms	len = EXTRACT_32BITS(&dp[1]);
44226183Sfenner	if (len < length) {
44326183Sfenner		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
444276788Sdelphij		ND_TCHECK(dp[1]);
445127675Sbms		len = EXTRACT_32BITS(&dp[1]);
44626183Sfenner		if (len < length) {
44726183Sfenner			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
448276788Sdelphij			ND_TCHECK2(dp[0], 0);
44926183Sfenner			return (dp);
45017680Spst		}
45117680Spst	}
45226183Sfennertrunc:
45326183Sfenner	return (NULL);
45417680Spst}
45517680Spst
45617680Spst/*
45717680Spst * Print out an NFS file handle and return a pointer to following word.
45875118Sfenner * If packet was truncated, return 0.
45917680Spst */
460276788Sdelphijstatic const uint32_t *
461276788Sdelphijparsefh(netdissect_options *ndo,
462276788Sdelphij        register const uint32_t *dp, int v3)
46317680Spst{
464127675Sbms	u_int len;
46518976Sdfr
46618976Sdfr	if (v3) {
467276788Sdelphij		ND_TCHECK(dp[0]);
468127675Sbms		len = EXTRACT_32BITS(dp) / 4;
46918976Sdfr		dp++;
47018976Sdfr	} else
47118976Sdfr		len = NFSX_V2FH / 4;
47218976Sdfr
473276788Sdelphij	if (ND_TTEST2(*dp, len * sizeof(*dp))) {
474276788Sdelphij		nfs_printfh(ndo, dp, len);
47518976Sdfr		return (dp + len);
47617680Spst	}
47726183Sfennertrunc:
47826183Sfenner	return (NULL);
47917680Spst}
48017680Spst
48117680Spst/*
48217680Spst * Print out a file name and return pointer to 32-bit word past it.
48375118Sfenner * If packet was truncated, return 0.
48417680Spst */
485276788Sdelphijstatic const uint32_t *
486276788Sdelphijparsefn(netdissect_options *ndo,
487276788Sdelphij        register const uint32_t *dp)
48817680Spst{
489276788Sdelphij	register uint32_t len;
49017680Spst	register const u_char *cp;
49117680Spst
49217680Spst	/* Bail if we don't have the string length */
493276788Sdelphij	ND_TCHECK(*dp);
49417680Spst
49517680Spst	/* Fetch string length; convert to host order */
49617680Spst	len = *dp++;
49717680Spst	NTOHL(len);
49817680Spst
499276788Sdelphij	ND_TCHECK2(*dp, ((len + 3) & ~3));
50075118Sfenner
50117680Spst	cp = (u_char *)dp;
50217680Spst	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
50317680Spst	dp += ((len + 3) & ~3) / sizeof(*dp);
504276788Sdelphij	ND_PRINT((ndo, "\""));
505276788Sdelphij	if (fn_printn(ndo, cp, len, ndo->ndo_snapend)) {
506276788Sdelphij		ND_PRINT((ndo, "\""));
507147904Ssam		goto trunc;
508147904Ssam	}
509276788Sdelphij	ND_PRINT((ndo, "\""));
51017680Spst
51117680Spst	return (dp);
51275118Sfennertrunc:
51375118Sfenner	return NULL;
51417680Spst}
51517680Spst
51617680Spst/*
51717680Spst * Print out file handle and file name.
51817680Spst * Return pointer to 32-bit word past file name.
51975118Sfenner * If packet was truncated (or there was some other error), return 0.
52017680Spst */
521276788Sdelphijstatic const uint32_t *
522276788Sdelphijparsefhn(netdissect_options *ndo,
523276788Sdelphij         register const uint32_t *dp, int v3)
52417680Spst{
525276788Sdelphij	dp = parsefh(ndo, dp, v3);
52626183Sfenner	if (dp == NULL)
52726183Sfenner		return (NULL);
528276788Sdelphij	ND_PRINT((ndo, " "));
529276788Sdelphij	return (parsefn(ndo, dp));
53017680Spst}
53117680Spst
53217680Spstvoid
533276788Sdelphijnfsreq_print_noaddr(netdissect_options *ndo,
534276788Sdelphij                    register const u_char *bp, u_int length,
535276788Sdelphij                    register const u_char *bp2)
53617680Spst{
537146778Ssam	register const struct sunrpc_msg *rp;
538276788Sdelphij	register const uint32_t *dp;
53975118Sfenner	nfs_type type;
54075118Sfenner	int v3;
541276788Sdelphij	uint32_t proc;
542276788Sdelphij	uint32_t access_flags;
54318976Sdfr	struct nfsv3_sattr sa3;
54417680Spst
545276788Sdelphij	ND_PRINT((ndo, "%d", length));
54626183Sfenner	nfserr = 0;		/* assume no error */
547146778Ssam	rp = (const struct sunrpc_msg *)bp;
548190207Srpaulo
549276788Sdelphij	if (!xid_map_enter(ndo, rp, bp2))	/* record proc number for later on */
550190207Srpaulo		goto trunc;
55117680Spst
552127675Sbms	v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
553127675Sbms	proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
55418976Sdfr
55518976Sdfr	if (!v3 && proc < NFS_NPROCS)
55618976Sdfr		proc =  nfsv3_procid[proc];
55718976Sdfr
558276788Sdelphij	ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc)));
55918976Sdfr	switch (proc) {
56017680Spst
56117680Spst	case NFSPROC_GETATTR:
56217680Spst	case NFSPROC_SETATTR:
563276788Sdelphij	case NFSPROC_READLINK:
564276788Sdelphij	case NFSPROC_FSSTAT:
565276788Sdelphij	case NFSPROC_FSINFO:
566276788Sdelphij	case NFSPROC_PATHCONF:
567276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
568276788Sdelphij		    parsefh(ndo, dp, v3) != NULL)
56917680Spst			return;
57017680Spst		break;
57117680Spst
57217680Spst	case NFSPROC_LOOKUP:
573276788Sdelphij	case NFSPROC_CREATE:
574276788Sdelphij	case NFSPROC_MKDIR:
575276788Sdelphij	case NFSPROC_REMOVE:
576276788Sdelphij	case NFSPROC_RMDIR:
577276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
578276788Sdelphij		    parsefhn(ndo, dp, v3) != NULL)
57917680Spst			return;
58017680Spst		break;
58117680Spst
58218976Sdfr	case NFSPROC_ACCESS:
583276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
584276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
585276788Sdelphij			ND_TCHECK(dp[0]);
586214478Srpaulo			access_flags = EXTRACT_32BITS(&dp[0]);
587214478Srpaulo			if (access_flags & ~NFSV3ACCESS_FULL) {
588214478Srpaulo				/* NFSV3ACCESS definitions aren't up to date */
589276788Sdelphij				ND_PRINT((ndo, " %04x", access_flags));
590214478Srpaulo			} else if ((access_flags & NFSV3ACCESS_FULL) == NFSV3ACCESS_FULL) {
591276788Sdelphij				ND_PRINT((ndo, " NFS_ACCESS_FULL"));
592214478Srpaulo			} else {
593214478Srpaulo				char separator = ' ';
594214478Srpaulo				if (access_flags & NFSV3ACCESS_READ) {
595276788Sdelphij					ND_PRINT((ndo, " NFS_ACCESS_READ"));
596214478Srpaulo					separator = '|';
597214478Srpaulo				}
598214478Srpaulo				if (access_flags & NFSV3ACCESS_LOOKUP) {
599276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_LOOKUP", separator));
600214478Srpaulo					separator = '|';
601214478Srpaulo				}
602214478Srpaulo				if (access_flags & NFSV3ACCESS_MODIFY) {
603276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_MODIFY", separator));
604214478Srpaulo					separator = '|';
605214478Srpaulo				}
606214478Srpaulo				if (access_flags & NFSV3ACCESS_EXTEND) {
607276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_EXTEND", separator));
608214478Srpaulo					separator = '|';
609214478Srpaulo				}
610214478Srpaulo				if (access_flags & NFSV3ACCESS_DELETE) {
611276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_DELETE", separator));
612214478Srpaulo					separator = '|';
613214478Srpaulo				}
614214478Srpaulo				if (access_flags & NFSV3ACCESS_EXECUTE)
615276788Sdelphij					ND_PRINT((ndo, "%cNFS_ACCESS_EXECUTE", separator));
616214478Srpaulo			}
61718976Sdfr			return;
61818976Sdfr		}
61918976Sdfr		break;
62018976Sdfr
62117680Spst	case NFSPROC_READ:
622276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
623276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
62418976Sdfr			if (v3) {
625276788Sdelphij				ND_TCHECK(dp[2]);
626276788Sdelphij				ND_PRINT((ndo, " %u bytes @ %" PRIu64,
627146778Ssam				       EXTRACT_32BITS(&dp[2]),
628276788Sdelphij				       EXTRACT_64BITS(&dp[0])));
62918976Sdfr			} else {
630276788Sdelphij				ND_TCHECK(dp[1]);
631276788Sdelphij				ND_PRINT((ndo, " %u bytes @ %u",
632127675Sbms				    EXTRACT_32BITS(&dp[1]),
633276788Sdelphij				    EXTRACT_32BITS(&dp[0])));
63418976Sdfr			}
63517680Spst			return;
63617680Spst		}
63717680Spst		break;
63817680Spst
63917680Spst	case NFSPROC_WRITE:
640276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
641276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
64218976Sdfr			if (v3) {
643276788Sdelphij				ND_TCHECK(dp[2]);
644276788Sdelphij				ND_PRINT((ndo, " %u (%u) bytes @ %" PRIu64,
645146778Ssam						EXTRACT_32BITS(&dp[4]),
646146778Ssam						EXTRACT_32BITS(&dp[2]),
647276788Sdelphij						EXTRACT_64BITS(&dp[0])));
648276788Sdelphij				if (ndo->ndo_vflag) {
64918976Sdfr					dp += 3;
650276788Sdelphij					ND_TCHECK(dp[0]);
651276788Sdelphij					ND_PRINT((ndo, " <%s>",
65275118Sfenner						tok2str(nfsv3_writemodes,
653276788Sdelphij							NULL, EXTRACT_32BITS(dp))));
65418976Sdfr				}
65518976Sdfr			} else {
656276788Sdelphij				ND_TCHECK(dp[3]);
657276788Sdelphij				ND_PRINT((ndo, " %u (%u) bytes @ %u (%u)",
658127675Sbms						EXTRACT_32BITS(&dp[3]),
659127675Sbms						EXTRACT_32BITS(&dp[2]),
660127675Sbms						EXTRACT_32BITS(&dp[1]),
661276788Sdelphij						EXTRACT_32BITS(&dp[0])));
66218976Sdfr			}
66317680Spst			return;
66417680Spst		}
66517680Spst		break;
66617680Spst
66718976Sdfr	case NFSPROC_SYMLINK:
668276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != 0 &&
669276788Sdelphij		    (dp = parsefhn(ndo, dp, v3)) != 0) {
670276788Sdelphij			ND_PRINT((ndo, " ->"));
671276788Sdelphij			if (v3 && (dp = parse_sattr3(ndo, dp, &sa3)) == 0)
67218976Sdfr				break;
673276788Sdelphij			if (parsefn(ndo, dp) == 0)
67418976Sdfr				break;
675276788Sdelphij			if (v3 && ndo->ndo_vflag)
676276788Sdelphij				print_sattr3(ndo, &sa3, ndo->ndo_vflag);
67718976Sdfr			return;
67818976Sdfr		}
67918976Sdfr		break;
68018976Sdfr
68118976Sdfr	case NFSPROC_MKNOD:
682276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != 0 &&
683276788Sdelphij		    (dp = parsefhn(ndo, dp, v3)) != 0) {
684276788Sdelphij			ND_TCHECK(*dp);
685127675Sbms			type = (nfs_type)EXTRACT_32BITS(dp);
686127675Sbms			dp++;
687276788Sdelphij			if ((dp = parse_sattr3(ndo, dp, &sa3)) == 0)
68818976Sdfr				break;
689276788Sdelphij			ND_PRINT((ndo, " %s", tok2str(type2str, "unk-ft %d", type)));
690276788Sdelphij			if (ndo->ndo_vflag && (type == NFCHR || type == NFBLK)) {
691276788Sdelphij				ND_TCHECK(dp[1]);
692276788Sdelphij				ND_PRINT((ndo, " %u/%u",
693127675Sbms				       EXTRACT_32BITS(&dp[0]),
694276788Sdelphij				       EXTRACT_32BITS(&dp[1])));
69518976Sdfr				dp += 2;
69618976Sdfr			}
697276788Sdelphij			if (ndo->ndo_vflag)
698276788Sdelphij				print_sattr3(ndo, &sa3, ndo->ndo_vflag);
69918976Sdfr			return;
70018976Sdfr		}
70118976Sdfr		break;
70218976Sdfr
70317680Spst	case NFSPROC_RENAME:
704276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
705276788Sdelphij		    (dp = parsefhn(ndo, dp, v3)) != NULL) {
706276788Sdelphij			ND_PRINT((ndo, " ->"));
707276788Sdelphij			if (parsefhn(ndo, dp, v3) != NULL)
70817680Spst				return;
70917680Spst		}
71017680Spst		break;
71117680Spst
71217680Spst	case NFSPROC_LINK:
713276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
714276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
715276788Sdelphij			ND_PRINT((ndo, " ->"));
716276788Sdelphij			if (parsefhn(ndo, dp, v3) != NULL)
71717680Spst				return;
71817680Spst		}
71917680Spst		break;
72017680Spst
72118976Sdfr	case NFSPROC_READDIR:
722276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
723276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
72418976Sdfr			if (v3) {
725276788Sdelphij				ND_TCHECK(dp[4]);
72618976Sdfr				/*
72718976Sdfr				 * We shouldn't really try to interpret the
72818976Sdfr				 * offset cookie here.
72918976Sdfr				 */
730276788Sdelphij				ND_PRINT((ndo, " %u bytes @ %" PRId64,
731146778Ssam				    EXTRACT_32BITS(&dp[4]),
732276788Sdelphij				    EXTRACT_64BITS(&dp[0])));
733276788Sdelphij				if (ndo->ndo_vflag)
734276788Sdelphij					ND_PRINT((ndo, " verf %08x%08x", dp[2], dp[3]));
73518976Sdfr			} else {
736276788Sdelphij				ND_TCHECK(dp[1]);
73718976Sdfr				/*
73818976Sdfr				 * Print the offset as signed, since -1 is
73918976Sdfr				 * common, but offsets > 2^31 aren't.
74018976Sdfr				 */
741276788Sdelphij				ND_PRINT((ndo, " %u bytes @ %d",
742127675Sbms				    EXTRACT_32BITS(&dp[1]),
743276788Sdelphij				    EXTRACT_32BITS(&dp[0])));
74418976Sdfr			}
74518976Sdfr			return;
74617680Spst		}
74717680Spst		break;
74817680Spst
74918976Sdfr	case NFSPROC_READDIRPLUS:
750276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
751276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
752276788Sdelphij			ND_TCHECK(dp[4]);
75318976Sdfr			/*
75418976Sdfr			 * We don't try to interpret the offset
75518976Sdfr			 * cookie here.
75618976Sdfr			 */
757276788Sdelphij			ND_PRINT((ndo, " %u bytes @ %" PRId64,
758146778Ssam				EXTRACT_32BITS(&dp[4]),
759276788Sdelphij				EXTRACT_64BITS(&dp[0])));
760276788Sdelphij			if (ndo->ndo_vflag) {
761276788Sdelphij				ND_TCHECK(dp[5]);
762276788Sdelphij				ND_PRINT((ndo, " max %u verf %08x%08x",
763276788Sdelphij				       EXTRACT_32BITS(&dp[5]), dp[2], dp[3]));
764146778Ssam			}
76517680Spst			return;
76618976Sdfr		}
76717680Spst		break;
76817680Spst
76918976Sdfr	case NFSPROC_COMMIT:
770276788Sdelphij		if ((dp = parsereq(ndo, rp, length)) != NULL &&
771276788Sdelphij		    (dp = parsefh(ndo, dp, v3)) != NULL) {
772276788Sdelphij			ND_TCHECK(dp[2]);
773276788Sdelphij			ND_PRINT((ndo, " %u bytes @ %" PRIu64,
774146778Ssam				EXTRACT_32BITS(&dp[2]),
775276788Sdelphij				EXTRACT_64BITS(&dp[0])));
77617680Spst			return;
77717680Spst		}
77817680Spst		break;
77917680Spst
78017680Spst	default:
78117680Spst		return;
78217680Spst	}
78375118Sfenner
78417680Spsttrunc:
78526183Sfenner	if (!nfserr)
786276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
78717680Spst}
78817680Spst
78917680Spst/*
79017680Spst * Print out an NFS file handle.
79117680Spst * We assume packet was not truncated before the end of the
79217680Spst * file handle pointed to by dp.
79317680Spst *
79417680Spst * Note: new version (using portable file-handle parser) doesn't produce
79517680Spst * generation number.  It probably could be made to do that, with some
79617680Spst * additional hacking on the parser code.
79717680Spst */
79817680Spststatic void
799276788Sdelphijnfs_printfh(netdissect_options *ndo,
800276788Sdelphij            register const uint32_t *dp, const u_int len)
80117680Spst{
80217680Spst	my_fsid fsid;
803276788Sdelphij	uint32_t ino;
804127675Sbms	const char *sfsname = NULL;
805127675Sbms	char *spacep;
80617680Spst
807276788Sdelphij	if (ndo->ndo_uflag) {
808127675Sbms		u_int i;
809127675Sbms		char const *sep = "";
81017680Spst
811276788Sdelphij		ND_PRINT((ndo, " fh["));
812127675Sbms		for (i=0; i<len; i++) {
813276788Sdelphij			ND_PRINT((ndo, "%s%x", sep, dp[i]));
814127675Sbms			sep = ":";
815127675Sbms		}
816276788Sdelphij		ND_PRINT((ndo, "]"));
817127675Sbms		return;
818127675Sbms	}
819127675Sbms
820127675Sbms	Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
821127675Sbms
82217680Spst	if (sfsname) {
82326183Sfenner		/* file system ID is ASCII, not numeric, for this server OS */
82426183Sfenner		static char temp[NFSX_V3FHMAX+1];
82517680Spst
82626183Sfenner		/* Make sure string is null-terminated */
82726183Sfenner		strncpy(temp, sfsname, NFSX_V3FHMAX);
82875118Sfenner		temp[sizeof(temp) - 1] = '\0';
82926183Sfenner		/* Remove trailing spaces */
830127675Sbms		spacep = strchr(temp, ' ');
831127675Sbms		if (spacep)
832127675Sbms			*spacep = '\0';
83317680Spst
834276788Sdelphij		ND_PRINT((ndo, " fh %s/", temp));
83526183Sfenner	} else {
836276788Sdelphij		ND_PRINT((ndo, " fh %d,%d/",
837276788Sdelphij			     fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor));
83817680Spst	}
83975118Sfenner
840127675Sbms	if(fsid.Fsid_dev.Minor == 257)
841127675Sbms		/* Print the undecoded handle */
842276788Sdelphij		ND_PRINT((ndo, "%s", fsid.Opaque_Handle));
84375118Sfenner	else
844276788Sdelphij		ND_PRINT((ndo, "%ld", (long) ino));
84517680Spst}
84617680Spst
84717680Spst/*
84817680Spst * Maintain a small cache of recent client.XID.server/proc pairs, to allow
84917680Spst * us to match up replies with requests and thus to know how to parse
85017680Spst * the reply.
85117680Spst */
85217680Spst
85317680Spststruct xid_map_entry {
854276788Sdelphij	uint32_t	xid;		/* transaction ID (net order) */
85575118Sfenner	int ipver;			/* IP version (4 or 6) */
85675118Sfenner#ifdef INET6
85775118Sfenner	struct in6_addr	client;		/* client IP address (net order) */
85875118Sfenner	struct in6_addr	server;		/* server IP address (net order) */
85975118Sfenner#else
86017680Spst	struct in_addr	client;		/* client IP address (net order) */
86117680Spst	struct in_addr	server;		/* server IP address (net order) */
86275118Sfenner#endif
863276788Sdelphij	uint32_t	proc;		/* call proc number (host order) */
864276788Sdelphij	uint32_t	vers;		/* program version (host order) */
86517680Spst};
86617680Spst
86717680Spst/*
86817680Spst * Map entries are kept in an array that we manage as a ring;
86917680Spst * new entries are always added at the tail of the ring.  Initially,
87017680Spst * all the entries are zero and hence don't match anything.
87117680Spst */
87217680Spst
87317680Spst#define	XIDMAPSIZE	64
87417680Spst
87517680Spststruct xid_map_entry xid_map[XIDMAPSIZE];
87617680Spst
87717680Spstint	xid_map_next = 0;
87817680Spstint	xid_map_hint = 0;
87917680Spst
880190207Srpaulostatic int
881276788Sdelphijxid_map_enter(netdissect_options *ndo,
882276788Sdelphij              const struct sunrpc_msg *rp, const u_char *bp)
88317680Spst{
88475118Sfenner	struct ip *ip = NULL;
88575118Sfenner#ifdef INET6
88675118Sfenner	struct ip6_hdr *ip6 = NULL;
88775118Sfenner#endif
88817680Spst	struct xid_map_entry *xmep;
88917680Spst
890276788Sdelphij	if (!ND_TTEST(rp->rm_call.cb_vers))
891190207Srpaulo		return (0);
89275118Sfenner	switch (IP_V((struct ip *)bp)) {
89375118Sfenner	case 4:
89475118Sfenner		ip = (struct ip *)bp;
89575118Sfenner		break;
89675118Sfenner#ifdef INET6
89775118Sfenner	case 6:
89875118Sfenner		ip6 = (struct ip6_hdr *)bp;
89975118Sfenner		break;
90075118Sfenner#endif
90175118Sfenner	default:
902190207Srpaulo		return (1);
90375118Sfenner	}
90475118Sfenner
90517680Spst	xmep = &xid_map[xid_map_next];
90617680Spst
90717680Spst	if (++xid_map_next >= XIDMAPSIZE)
90817680Spst		xid_map_next = 0;
90917680Spst
910276788Sdelphij	UNALIGNED_MEMCPY(&xmep->xid, &rp->rm_xid, sizeof(xmep->xid));
91175118Sfenner	if (ip) {
91275118Sfenner		xmep->ipver = 4;
913276788Sdelphij		UNALIGNED_MEMCPY(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
914276788Sdelphij		UNALIGNED_MEMCPY(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
91575118Sfenner	}
91675118Sfenner#ifdef INET6
91775118Sfenner	else if (ip6) {
91875118Sfenner		xmep->ipver = 6;
919276788Sdelphij		UNALIGNED_MEMCPY(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
920276788Sdelphij		UNALIGNED_MEMCPY(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
92175118Sfenner	}
92275118Sfenner#endif
923127675Sbms	xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
924127675Sbms	xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
925190207Srpaulo	return (1);
92617680Spst}
92717680Spst
92826183Sfenner/*
92926183Sfenner * Returns 0 and puts NFSPROC_xxx in proc return and
93026183Sfenner * version in vers return, or returns -1 on failure
93126183Sfenner */
93218976Sdfrstatic int
933276788Sdelphijxid_map_find(const struct sunrpc_msg *rp, const u_char *bp, uint32_t *proc,
934276788Sdelphij	     uint32_t *vers)
93517680Spst{
93617680Spst	int i;
93717680Spst	struct xid_map_entry *xmep;
938276788Sdelphij	uint32_t xid = rp->rm_xid;
93975118Sfenner	struct ip *ip = (struct ip *)bp;
94075118Sfenner#ifdef INET6
94175118Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
94275118Sfenner#endif
94375118Sfenner	int cmp;
94417680Spst
94517680Spst	/* Start searching from where we last left off */
946127675Sbms	i = xid_map_hint;
94717680Spst	do {
94817680Spst		xmep = &xid_map[i];
94975118Sfenner		cmp = 1;
95075118Sfenner		if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
95175118Sfenner			goto nextitem;
95275118Sfenner		switch (xmep->ipver) {
95375118Sfenner		case 4:
954276788Sdelphij			if (UNALIGNED_MEMCMP(&ip->ip_src, &xmep->server,
95575118Sfenner				   sizeof(ip->ip_src)) != 0 ||
956276788Sdelphij			    UNALIGNED_MEMCMP(&ip->ip_dst, &xmep->client,
95775118Sfenner				   sizeof(ip->ip_dst)) != 0) {
95875118Sfenner				cmp = 0;
95975118Sfenner			}
96075118Sfenner			break;
96175118Sfenner#ifdef INET6
96275118Sfenner		case 6:
963276788Sdelphij			if (UNALIGNED_MEMCMP(&ip6->ip6_src, &xmep->server,
96475118Sfenner				   sizeof(ip6->ip6_src)) != 0 ||
965276788Sdelphij			    UNALIGNED_MEMCMP(&ip6->ip6_dst, &xmep->client,
96675118Sfenner				   sizeof(ip6->ip6_dst)) != 0) {
96775118Sfenner				cmp = 0;
96875118Sfenner			}
96975118Sfenner			break;
97075118Sfenner#endif
97175118Sfenner		default:
97275118Sfenner			cmp = 0;
97375118Sfenner			break;
97475118Sfenner		}
97575118Sfenner		if (cmp) {
97617680Spst			/* match */
97717680Spst			xid_map_hint = i;
97818976Sdfr			*proc = xmep->proc;
97918976Sdfr			*vers = xmep->vers;
98018976Sdfr			return 0;
98117680Spst		}
98275118Sfenner	nextitem:
98317680Spst		if (++i >= XIDMAPSIZE)
98417680Spst			i = 0;
98517680Spst	} while (i != xid_map_hint);
98617680Spst
98717680Spst	/* search failed */
98875118Sfenner	return (-1);
98917680Spst}
99017680Spst
99117680Spst/*
99217680Spst * Routines for parsing reply packets
99317680Spst */
99417680Spst
99517680Spst/*
99617680Spst * Return a pointer to the beginning of the actual results.
99775118Sfenner * If the packet was truncated, return 0.
99817680Spst */
999276788Sdelphijstatic const uint32_t *
1000276788Sdelphijparserep(netdissect_options *ndo,
1001276788Sdelphij         register const struct sunrpc_msg *rp, register u_int length)
100217680Spst{
1003276788Sdelphij	register const uint32_t *dp;
100475118Sfenner	u_int len;
1005146778Ssam	enum sunrpc_accept_stat astat;
100617680Spst
100717680Spst	/*
100817680Spst	 * Portability note:
100917680Spst	 * Here we find the address of the ar_verf credentials.
101017680Spst	 * Originally, this calculation was
1011276788Sdelphij	 *	dp = (uint32_t *)&rp->rm_reply.rp_acpt.ar_verf
101217680Spst	 * On the wire, the rp_acpt field starts immediately after
101317680Spst	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
101417680Spst	 * "struct accepted_reply") contains a "struct opaque_auth",
101517680Spst	 * whose internal representation contains a pointer, so on a
101617680Spst	 * 64-bit machine the compiler inserts 32 bits of padding
101717680Spst	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
101817680Spst	 * the internal representation to parse the on-the-wire
101917680Spst	 * representation.  Instead, we skip past the rp_stat field,
102017680Spst	 * which is an "enum" and so occupies one 32-bit word.
102117680Spst	 */
1022276788Sdelphij	dp = ((const uint32_t *)&rp->rm_reply) + 1;
1023276788Sdelphij	ND_TCHECK(dp[1]);
1024127675Sbms	len = EXTRACT_32BITS(&dp[1]);
102517680Spst	if (len >= length)
102626183Sfenner		return (NULL);
102717680Spst	/*
102817680Spst	 * skip past the ar_verf credentials.
102917680Spst	 */
1030276788Sdelphij	dp += (len + (2*sizeof(uint32_t) + 3)) / sizeof(uint32_t);
1031276788Sdelphij	ND_TCHECK2(dp[0], 0);
103217680Spst
103317680Spst	/*
103417680Spst	 * now we can check the ar_stat field
103517680Spst	 */
1036147904Ssam	astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
1037276788Sdelphij	if (astat != SUNRPC_SUCCESS) {
1038276788Sdelphij		ND_PRINT((ndo, " %s", tok2str(sunrpc_str, "ar_stat %d", astat)));
103926183Sfenner		nfserr = 1;		/* suppress trunc string */
104026183Sfenner		return (NULL);
104117680Spst	}
104217680Spst	/* successful return */
1043276788Sdelphij	ND_TCHECK2(*dp, sizeof(astat));
1044276788Sdelphij	return ((uint32_t *) (sizeof(astat) + ((char *)dp)));
104526183Sfennertrunc:
104675118Sfenner	return (0);
104717680Spst}
104817680Spst
1049276788Sdelphijstatic const uint32_t *
1050276788Sdelphijparsestatus(netdissect_options *ndo,
1051276788Sdelphij            const uint32_t *dp, int *er)
105217680Spst{
105375118Sfenner	int errnum;
105417680Spst
1055276788Sdelphij	ND_TCHECK(dp[0]);
105675118Sfenner
1057127675Sbms	errnum = EXTRACT_32BITS(&dp[0]);
105818976Sdfr	if (er)
105926183Sfenner		*er = errnum;
106026183Sfenner	if (errnum != 0) {
1061276788Sdelphij		if (!ndo->ndo_qflag)
1062276788Sdelphij			ND_PRINT((ndo, " ERROR: %s",
1063276788Sdelphij			    tok2str(status2str, "unk %d", errnum)));
106426183Sfenner		nfserr = 1;
106517680Spst	}
106617680Spst	return (dp + 1);
106726183Sfennertrunc:
106875118Sfenner	return NULL;
106917680Spst}
107017680Spst
1071276788Sdelphijstatic const uint32_t *
1072276788Sdelphijparsefattr(netdissect_options *ndo,
1073276788Sdelphij           const uint32_t *dp, int verbose, int v3)
107417680Spst{
107518976Sdfr	const struct nfs_fattr *fap;
107617680Spst
107718976Sdfr	fap = (const struct nfs_fattr *)dp;
1078276788Sdelphij	ND_TCHECK(fap->fa_gid);
107917680Spst	if (verbose) {
1080276788Sdelphij		ND_PRINT((ndo, " %s %o ids %d/%d",
108175118Sfenner		    tok2str(type2str, "unk-ft %d ",
1082127675Sbms		    EXTRACT_32BITS(&fap->fa_type)),
1083127675Sbms		    EXTRACT_32BITS(&fap->fa_mode),
1084127675Sbms		    EXTRACT_32BITS(&fap->fa_uid),
1085276788Sdelphij		    EXTRACT_32BITS(&fap->fa_gid)));
108618976Sdfr		if (v3) {
1087276788Sdelphij			ND_TCHECK(fap->fa3_size);
1088276788Sdelphij			ND_PRINT((ndo, " sz %" PRIu64,
1089276788Sdelphij				EXTRACT_64BITS((uint32_t *)&fap->fa3_size)));
109026184Sfenner		} else {
1091276788Sdelphij			ND_TCHECK(fap->fa2_size);
1092276788Sdelphij			ND_PRINT((ndo, " sz %d", EXTRACT_32BITS(&fap->fa2_size)));
109318976Sdfr		}
109417680Spst	}
109517680Spst	/* print lots more stuff */
109617680Spst	if (verbose > 1) {
109718976Sdfr		if (v3) {
1098276788Sdelphij			ND_TCHECK(fap->fa3_ctime);
1099276788Sdelphij			ND_PRINT((ndo, " nlink %d rdev %d/%d",
1100127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1101127675Sbms			       EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
1102276788Sdelphij			       EXTRACT_32BITS(&fap->fa3_rdev.specdata2)));
1103276788Sdelphij			ND_PRINT((ndo, " fsid %" PRIx64,
1104276788Sdelphij				EXTRACT_64BITS((uint32_t *)&fap->fa3_fsid)));
1105276788Sdelphij			ND_PRINT((ndo, " fileid %" PRIx64,
1106276788Sdelphij				EXTRACT_64BITS((uint32_t *)&fap->fa3_fileid)));
1107276788Sdelphij			ND_PRINT((ndo, " a/m/ctime %u.%06u",
1108127675Sbms			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
1109276788Sdelphij			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec)));
1110276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1111127675Sbms			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
1112276788Sdelphij			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec)));
1113276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1114127675Sbms			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
1115276788Sdelphij			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec)));
111618976Sdfr		} else {
1117276788Sdelphij			ND_TCHECK(fap->fa2_ctime);
1118276788Sdelphij			ND_PRINT((ndo, " nlink %d rdev 0x%x fsid 0x%x nodeid 0x%x a/m/ctime",
1119127675Sbms			       EXTRACT_32BITS(&fap->fa_nlink),
1120127675Sbms			       EXTRACT_32BITS(&fap->fa2_rdev),
1121127675Sbms			       EXTRACT_32BITS(&fap->fa2_fsid),
1122276788Sdelphij			       EXTRACT_32BITS(&fap->fa2_fileid)));
1123276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1124127675Sbms			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
1125276788Sdelphij			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec)));
1126276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1127127675Sbms			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
1128276788Sdelphij			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec)));
1129276788Sdelphij			ND_PRINT((ndo, " %u.%06u",
1130127675Sbms			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
1131276788Sdelphij			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec)));
113218976Sdfr		}
113317680Spst	}
1134276788Sdelphij	return ((const uint32_t *)((unsigned char *)dp +
113518976Sdfr		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
113626184Sfennertrunc:
113726184Sfenner	return (NULL);
113817680Spst}
113917680Spst
114017680Spststatic int
1141276788Sdelphijparseattrstat(netdissect_options *ndo,
1142276788Sdelphij              const uint32_t *dp, int verbose, int v3)
114317680Spst{
114418976Sdfr	int er;
114518976Sdfr
1146276788Sdelphij	dp = parsestatus(ndo, dp, &er);
1147111729Sfenner	if (dp == NULL)
114817680Spst		return (0);
1149111729Sfenner	if (er)
1150111729Sfenner		return (1);
115117680Spst
1152276788Sdelphij	return (parsefattr(ndo, dp, verbose, v3) != NULL);
115317680Spst}
115417680Spst
115517680Spststatic int
1156276788Sdelphijparsediropres(netdissect_options *ndo,
1157276788Sdelphij              const uint32_t *dp)
115817680Spst{
115918976Sdfr	int er;
116018976Sdfr
1161276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
116217680Spst		return (0);
1163111729Sfenner	if (er)
1164111729Sfenner		return (1);
116517680Spst
1166276788Sdelphij	dp = parsefh(ndo, dp, 0);
116717680Spst	if (dp == NULL)
116817680Spst		return (0);
116917680Spst
1170276788Sdelphij	return (parsefattr(ndo, dp, ndo->ndo_vflag, 0) != NULL);
117117680Spst}
117217680Spst
117317680Spststatic int
1174276788Sdelphijparselinkres(netdissect_options *ndo,
1175276788Sdelphij             const uint32_t *dp, int v3)
117617680Spst{
117718976Sdfr	int er;
117818976Sdfr
1179276788Sdelphij	dp = parsestatus(ndo, dp, &er);
1180111729Sfenner	if (dp == NULL)
118117680Spst		return(0);
1182111729Sfenner	if (er)
1183111729Sfenner		return(1);
1184276788Sdelphij	if (v3 && !(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
118518976Sdfr		return (0);
1186276788Sdelphij	ND_PRINT((ndo, " "));
1187276788Sdelphij	return (parsefn(ndo, dp) != NULL);
118817680Spst}
118917680Spst
119017680Spststatic int
1191276788Sdelphijparsestatfs(netdissect_options *ndo,
1192276788Sdelphij            const uint32_t *dp, int v3)
119317680Spst{
119418976Sdfr	const struct nfs_statfs *sfsp;
119518976Sdfr	int er;
119617680Spst
1197276788Sdelphij	dp = parsestatus(ndo, dp, &er);
1198111729Sfenner	if (dp == NULL)
119975118Sfenner		return (0);
1200111729Sfenner	if (!v3 && er)
1201111729Sfenner		return (1);
120217680Spst
1203276788Sdelphij	if (ndo->ndo_qflag)
120418976Sdfr		return(1);
120518976Sdfr
120618976Sdfr	if (v3) {
1207276788Sdelphij		if (ndo->ndo_vflag)
1208276788Sdelphij			ND_PRINT((ndo, " POST:"));
1209276788Sdelphij		if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
121018976Sdfr			return (0);
121117680Spst	}
121217680Spst
1213276788Sdelphij	ND_TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
121418976Sdfr
121518976Sdfr	sfsp = (const struct nfs_statfs *)dp;
121618976Sdfr
121718976Sdfr	if (v3) {
1218276788Sdelphij		ND_PRINT((ndo, " tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
1219276788Sdelphij			EXTRACT_64BITS((uint32_t *)&sfsp->sf_tbytes),
1220276788Sdelphij			EXTRACT_64BITS((uint32_t *)&sfsp->sf_fbytes),
1221276788Sdelphij			EXTRACT_64BITS((uint32_t *)&sfsp->sf_abytes)));
1222276788Sdelphij		if (ndo->ndo_vflag) {
1223276788Sdelphij			ND_PRINT((ndo, " tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
1224276788Sdelphij			       EXTRACT_64BITS((uint32_t *)&sfsp->sf_tfiles),
1225276788Sdelphij			       EXTRACT_64BITS((uint32_t *)&sfsp->sf_ffiles),
1226276788Sdelphij			       EXTRACT_64BITS((uint32_t *)&sfsp->sf_afiles),
1227276788Sdelphij			       EXTRACT_32BITS(&sfsp->sf_invarsec)));
122818976Sdfr		}
122918976Sdfr	} else {
1230276788Sdelphij		ND_PRINT((ndo, " tsize %d bsize %d blocks %d bfree %d bavail %d",
1231127675Sbms			EXTRACT_32BITS(&sfsp->sf_tsize),
1232127675Sbms			EXTRACT_32BITS(&sfsp->sf_bsize),
1233127675Sbms			EXTRACT_32BITS(&sfsp->sf_blocks),
1234127675Sbms			EXTRACT_32BITS(&sfsp->sf_bfree),
1235276788Sdelphij			EXTRACT_32BITS(&sfsp->sf_bavail)));
123618976Sdfr	}
123718976Sdfr
123817680Spst	return (1);
123926184Sfennertrunc:
124026184Sfenner	return (0);
124117680Spst}
124217680Spst
124317680Spststatic int
1244276788Sdelphijparserddires(netdissect_options *ndo,
1245276788Sdelphij             const uint32_t *dp)
124617680Spst{
124718976Sdfr	int er;
124818976Sdfr
1249276788Sdelphij	dp = parsestatus(ndo, dp, &er);
1250111729Sfenner	if (dp == NULL)
125117680Spst		return (0);
1252111729Sfenner	if (er)
1253111729Sfenner		return (1);
1254276788Sdelphij	if (ndo->ndo_qflag)
125518976Sdfr		return (1);
125618976Sdfr
1257276788Sdelphij	ND_TCHECK(dp[2]);
1258276788Sdelphij	ND_PRINT((ndo, " offset 0x%x size %d ",
1259276788Sdelphij	       EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1])));
126018976Sdfr	if (dp[2] != 0)
1261276788Sdelphij		ND_PRINT((ndo, " eof"));
126218976Sdfr
126318976Sdfr	return (1);
126426184Sfennertrunc:
126526184Sfenner	return (0);
126618976Sdfr}
126718976Sdfr
1268276788Sdelphijstatic const uint32_t *
1269276788Sdelphijparse_wcc_attr(netdissect_options *ndo,
1270276788Sdelphij               const uint32_t *dp)
127118976Sdfr{
1272276788Sdelphij	ND_PRINT((ndo, " sz %" PRIu64, EXTRACT_64BITS(&dp[0])));
1273276788Sdelphij	ND_PRINT((ndo, " mtime %u.%06u ctime %u.%06u",
1274127675Sbms	       EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
1275276788Sdelphij	       EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5])));
127618976Sdfr	return (dp + 6);
127718976Sdfr}
127818976Sdfr
127918976Sdfr/*
128018976Sdfr * Pre operation attributes. Print only if vflag > 1.
128118976Sdfr */
1282276788Sdelphijstatic const uint32_t *
1283276788Sdelphijparse_pre_op_attr(netdissect_options *ndo,
1284276788Sdelphij                  const uint32_t *dp, int verbose)
128518976Sdfr{
1286276788Sdelphij	ND_TCHECK(dp[0]);
1287127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
128818976Sdfr		return (dp + 1);
128918976Sdfr	dp++;
1290276788Sdelphij	ND_TCHECK2(*dp, 24);
129118976Sdfr	if (verbose > 1) {
1292276788Sdelphij		return parse_wcc_attr(ndo, dp);
129318976Sdfr	} else {
129418976Sdfr		/* If not verbose enough, just skip over wcc_attr */
129518976Sdfr		return (dp + 6);
129617680Spst	}
129726184Sfennertrunc:
129826184Sfenner	return (NULL);
129918976Sdfr}
130017680Spst
130118976Sdfr/*
130218976Sdfr * Post operation attributes are printed if vflag >= 1
130318976Sdfr */
1304276788Sdelphijstatic const uint32_t *
1305276788Sdelphijparse_post_op_attr(netdissect_options *ndo,
1306276788Sdelphij                   const uint32_t *dp, int verbose)
130718976Sdfr{
1308276788Sdelphij	ND_TCHECK(dp[0]);
1309127675Sbms	if (!EXTRACT_32BITS(&dp[0]))
131018976Sdfr		return (dp + 1);
131118976Sdfr	dp++;
131218976Sdfr	if (verbose) {
1313276788Sdelphij		return parsefattr(ndo, dp, verbose, 1);
131418976Sdfr	} else
1315276788Sdelphij		return (dp + (NFSX_V3FATTR / sizeof (uint32_t)));
131626184Sfennertrunc:
131726184Sfenner	return (NULL);
131818976Sdfr}
131918976Sdfr
1320276788Sdelphijstatic const uint32_t *
1321276788Sdelphijparse_wcc_data(netdissect_options *ndo,
1322276788Sdelphij               const uint32_t *dp, int verbose)
132318976Sdfr{
132418976Sdfr	if (verbose > 1)
1325276788Sdelphij		ND_PRINT((ndo, " PRE:"));
1326276788Sdelphij	if (!(dp = parse_pre_op_attr(ndo, dp, verbose)))
132775118Sfenner		return (0);
132818976Sdfr
132918976Sdfr	if (verbose)
1330276788Sdelphij		ND_PRINT((ndo, " POST:"));
1331276788Sdelphij	return parse_post_op_attr(ndo, dp, verbose);
133218976Sdfr}
133318976Sdfr
1334276788Sdelphijstatic const uint32_t *
1335276788Sdelphijparsecreateopres(netdissect_options *ndo,
1336276788Sdelphij                 const uint32_t *dp, int verbose)
133718976Sdfr{
133818976Sdfr	int er;
133918976Sdfr
1340276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
134175118Sfenner		return (0);
134218976Sdfr	if (er)
1343276788Sdelphij		dp = parse_wcc_data(ndo, dp, verbose);
134418976Sdfr	else {
1345276788Sdelphij		ND_TCHECK(dp[0]);
1346127675Sbms		if (!EXTRACT_32BITS(&dp[0]))
134718976Sdfr			return (dp + 1);
134818976Sdfr		dp++;
1349276788Sdelphij		if (!(dp = parsefh(ndo, dp, 1)))
135075118Sfenner			return (0);
135118976Sdfr		if (verbose) {
1352276788Sdelphij			if (!(dp = parse_post_op_attr(ndo, dp, verbose)))
135375118Sfenner				return (0);
1354276788Sdelphij			if (ndo->ndo_vflag > 1) {
1355276788Sdelphij				ND_PRINT((ndo, " dir attr:"));
1356276788Sdelphij				dp = parse_wcc_data(ndo, dp, verbose);
135718976Sdfr			}
135818976Sdfr		}
135918976Sdfr	}
136018976Sdfr	return (dp);
136126184Sfennertrunc:
136226184Sfenner	return (NULL);
136318976Sdfr}
136418976Sdfr
136518976Sdfrstatic int
1366276788Sdelphijparsewccres(netdissect_options *ndo,
1367276788Sdelphij            const uint32_t *dp, int verbose)
136818976Sdfr{
136918976Sdfr	int er;
137018976Sdfr
1371276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
137218976Sdfr		return (0);
1373276788Sdelphij	return parse_wcc_data(ndo, dp, verbose) != 0;
137418976Sdfr}
137518976Sdfr
1376276788Sdelphijstatic const uint32_t *
1377276788Sdelphijparsev3rddirres(netdissect_options *ndo,
1378276788Sdelphij                const uint32_t *dp, int verbose)
137918976Sdfr{
138018976Sdfr	int er;
138118976Sdfr
1382276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
138375118Sfenner		return (0);
1384276788Sdelphij	if (ndo->ndo_vflag)
1385276788Sdelphij		ND_PRINT((ndo, " POST:"));
1386276788Sdelphij	if (!(dp = parse_post_op_attr(ndo, dp, verbose)))
138775118Sfenner		return (0);
138818976Sdfr	if (er)
138918976Sdfr		return dp;
1390276788Sdelphij	if (ndo->ndo_vflag) {
1391276788Sdelphij		ND_TCHECK(dp[1]);
1392276788Sdelphij		ND_PRINT((ndo, " verf %08x%08x", dp[0], dp[1]));
139318976Sdfr		dp += 2;
139418976Sdfr	}
139518976Sdfr	return dp;
139626184Sfennertrunc:
139726184Sfenner	return (NULL);
139818976Sdfr}
139918976Sdfr
140018976Sdfrstatic int
1401276788Sdelphijparsefsinfo(netdissect_options *ndo,
1402276788Sdelphij            const uint32_t *dp)
140318976Sdfr{
140418976Sdfr	struct nfsv3_fsinfo *sfp;
140518976Sdfr	int er;
140618976Sdfr
1407276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
140818976Sdfr		return (0);
1409276788Sdelphij	if (ndo->ndo_vflag)
1410276788Sdelphij		ND_PRINT((ndo, " POST:"));
1411276788Sdelphij	if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
141218976Sdfr		return (0);
141318976Sdfr	if (er)
141418976Sdfr		return (1);
141518976Sdfr
141618976Sdfr	sfp = (struct nfsv3_fsinfo *)dp;
1417276788Sdelphij	ND_TCHECK(*sfp);
1418276788Sdelphij	ND_PRINT((ndo, " rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1419127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtmax),
1420127675Sbms	       EXTRACT_32BITS(&sfp->fs_rtpref),
1421127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtmax),
1422127675Sbms	       EXTRACT_32BITS(&sfp->fs_wtpref),
1423276788Sdelphij	       EXTRACT_32BITS(&sfp->fs_dtpref)));
1424276788Sdelphij	if (ndo->ndo_vflag) {
1425276788Sdelphij		ND_PRINT((ndo, " rtmult %u wtmult %u maxfsz %" PRIu64,
1426127675Sbms		       EXTRACT_32BITS(&sfp->fs_rtmult),
1427146778Ssam		       EXTRACT_32BITS(&sfp->fs_wtmult),
1428276788Sdelphij		       EXTRACT_64BITS((uint32_t *)&sfp->fs_maxfilesize)));
1429276788Sdelphij		ND_PRINT((ndo, " delta %u.%06u ",
1430127675Sbms		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
1431276788Sdelphij		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec)));
143218976Sdfr	}
1433111729Sfenner	return (1);
1434111729Sfennertrunc:
143575118Sfenner	return (0);
143618976Sdfr}
143718976Sdfr
143818976Sdfrstatic int
1439276788Sdelphijparsepathconf(netdissect_options *ndo,
1440276788Sdelphij              const uint32_t *dp)
144118976Sdfr{
144218976Sdfr	int er;
144318976Sdfr	struct nfsv3_pathconf *spp;
144418976Sdfr
1445276788Sdelphij	if (!(dp = parsestatus(ndo, dp, &er)))
144618976Sdfr		return (0);
1447276788Sdelphij	if (ndo->ndo_vflag)
1448276788Sdelphij		ND_PRINT((ndo, " POST:"));
1449276788Sdelphij	if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
145018976Sdfr		return (0);
145118976Sdfr	if (er)
145218976Sdfr		return (1);
145318976Sdfr
145418976Sdfr	spp = (struct nfsv3_pathconf *)dp;
1455276788Sdelphij	ND_TCHECK(*spp);
145618976Sdfr
1457276788Sdelphij	ND_PRINT((ndo, " linkmax %u namemax %u %s %s %s %s",
1458127675Sbms	       EXTRACT_32BITS(&spp->pc_linkmax),
1459127675Sbms	       EXTRACT_32BITS(&spp->pc_namemax),
1460127675Sbms	       EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
1461127675Sbms	       EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
1462127675Sbms	       EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
1463276788Sdelphij	       EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : ""));
1464111729Sfenner	return (1);
1465111729Sfennertrunc:
146675118Sfenner	return (0);
146717680Spst}
146875118Sfenner
146917680Spststatic void
1470276788Sdelphijinterp_reply(netdissect_options *ndo,
1471276788Sdelphij             const struct sunrpc_msg *rp, uint32_t proc, uint32_t vers, int length)
147217680Spst{
1473276788Sdelphij	register const uint32_t *dp;
147418976Sdfr	register int v3;
147518976Sdfr	int er;
147617680Spst
147718976Sdfr	v3 = (vers == NFS_VER3);
147818976Sdfr
147918976Sdfr	if (!v3 && proc < NFS_NPROCS)
148018976Sdfr		proc = nfsv3_procid[proc];
148118976Sdfr
1482276788Sdelphij	ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc)));
148317680Spst	switch (proc) {
148417680Spst
148517680Spst	case NFSPROC_GETATTR:
1486276788Sdelphij		dp = parserep(ndo, rp, length);
1487276788Sdelphij		if (dp != NULL && parseattrstat(ndo, dp, !ndo->ndo_qflag, v3) != 0)
148817680Spst			return;
148917680Spst		break;
149017680Spst
149117680Spst	case NFSPROC_SETATTR:
1492276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
149317680Spst			return;
149418976Sdfr		if (v3) {
1495276788Sdelphij			if (parsewccres(ndo, dp, ndo->ndo_vflag))
149618976Sdfr				return;
149718976Sdfr		} else {
1498276788Sdelphij			if (parseattrstat(ndo, dp, !ndo->ndo_qflag, 0) != 0)
149918976Sdfr				return;
150018976Sdfr		}
150117680Spst		break;
150217680Spst
150317680Spst	case NFSPROC_LOOKUP:
1504276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
150518976Sdfr			break;
150618976Sdfr		if (v3) {
1507276788Sdelphij			if (!(dp = parsestatus(ndo, dp, &er)))
150818976Sdfr				break;
150918976Sdfr			if (er) {
1510276788Sdelphij				if (ndo->ndo_vflag > 1) {
1511276788Sdelphij					ND_PRINT((ndo, " post dattr:"));
1512276788Sdelphij					dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag);
151318976Sdfr				}
151418976Sdfr			} else {
1515276788Sdelphij				if (!(dp = parsefh(ndo, dp, v3)))
151618976Sdfr					break;
1517276788Sdelphij				if ((dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)) &&
1518276788Sdelphij				    ndo->ndo_vflag > 1) {
1519276788Sdelphij					ND_PRINT((ndo, " post dattr:"));
1520276788Sdelphij					dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag);
152118976Sdfr				}
152218976Sdfr			}
152375118Sfenner			if (dp)
152418976Sdfr				return;
152518976Sdfr		} else {
1526276788Sdelphij			if (parsediropres(ndo, dp) != 0)
152718976Sdfr				return;
152818976Sdfr		}
152917680Spst		break;
153017680Spst
153118976Sdfr	case NFSPROC_ACCESS:
1532276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
153398527Sfenner			break;
1534276788Sdelphij		if (!(dp = parsestatus(ndo, dp, &er)))
153518976Sdfr			break;
1536276788Sdelphij		if (ndo->ndo_vflag)
1537276788Sdelphij			ND_PRINT((ndo, " attr:"));
1538276788Sdelphij		if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
153918976Sdfr			break;
154018976Sdfr		if (!er)
1541276788Sdelphij			ND_PRINT((ndo, " c %04x", EXTRACT_32BITS(&dp[0])));
154218976Sdfr		return;
154318976Sdfr
154417680Spst	case NFSPROC_READLINK:
1545276788Sdelphij		dp = parserep(ndo, rp, length);
1546276788Sdelphij		if (dp != NULL && parselinkres(ndo, dp, v3) != 0)
154717680Spst			return;
154817680Spst		break;
154917680Spst
155017680Spst	case NFSPROC_READ:
1551276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
155218976Sdfr			break;
155318976Sdfr		if (v3) {
1554276788Sdelphij			if (!(dp = parsestatus(ndo, dp, &er)))
155518976Sdfr				break;
1556276788Sdelphij			if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
155718976Sdfr				break;
155818976Sdfr			if (er)
155918976Sdfr				return;
1560276788Sdelphij			if (ndo->ndo_vflag) {
1561276788Sdelphij				ND_TCHECK(dp[1]);
1562276788Sdelphij				ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0])));
1563127675Sbms				if (EXTRACT_32BITS(&dp[1]))
1564276788Sdelphij					ND_PRINT((ndo, " EOF"));
156518976Sdfr			}
156617680Spst			return;
156718976Sdfr		} else {
1568276788Sdelphij			if (parseattrstat(ndo, dp, ndo->ndo_vflag, 0) != 0)
156918976Sdfr				return;
157018976Sdfr		}
157117680Spst		break;
157217680Spst
157317680Spst	case NFSPROC_WRITE:
1574276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
157518976Sdfr			break;
157618976Sdfr		if (v3) {
1577276788Sdelphij			if (!(dp = parsestatus(ndo, dp, &er)))
157818976Sdfr				break;
1579276788Sdelphij			if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
158018976Sdfr				break;
158118976Sdfr			if (er)
158218976Sdfr				return;
1583276788Sdelphij			if (ndo->ndo_vflag) {
1584276788Sdelphij				ND_TCHECK(dp[0]);
1585276788Sdelphij				ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0])));
1586276788Sdelphij				if (ndo->ndo_vflag > 1) {
1587276788Sdelphij					ND_TCHECK(dp[1]);
1588276788Sdelphij					ND_PRINT((ndo, " <%s>",
158975118Sfenner						tok2str(nfsv3_writemodes,
1590276788Sdelphij							NULL, EXTRACT_32BITS(&dp[1]))));
159118976Sdfr				}
159218976Sdfr				return;
159318976Sdfr			}
159418976Sdfr		} else {
1595276788Sdelphij			if (parseattrstat(ndo, dp, ndo->ndo_vflag, v3) != 0)
159618976Sdfr				return;
159718976Sdfr		}
159817680Spst		break;
159917680Spst
160017680Spst	case NFSPROC_CREATE:
160118976Sdfr	case NFSPROC_MKDIR:
1602276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
160318976Sdfr			break;
160418976Sdfr		if (v3) {
1605276788Sdelphij			if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != 0)
160618976Sdfr				return;
160718976Sdfr		} else {
1608276788Sdelphij			if (parsediropres(ndo, dp) != 0)
160918976Sdfr				return;
161018976Sdfr		}
161118976Sdfr		break;
161218976Sdfr
161318976Sdfr	case NFSPROC_SYMLINK:
1614276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
161518976Sdfr			break;
161618976Sdfr		if (v3) {
1617276788Sdelphij			if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != 0)
161818976Sdfr				return;
161918976Sdfr		} else {
1620276788Sdelphij			if (parsestatus(ndo, dp, &er) != 0)
162118976Sdfr				return;
162218976Sdfr		}
162318976Sdfr		break;
162418976Sdfr
162518976Sdfr	case NFSPROC_MKNOD:
1626276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
162718976Sdfr			break;
1628276788Sdelphij		if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != 0)
162917680Spst			return;
163017680Spst		break;
163117680Spst
163217680Spst	case NFSPROC_REMOVE:
163318976Sdfr	case NFSPROC_RMDIR:
1634276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
163518976Sdfr			break;
163618976Sdfr		if (v3) {
1637276788Sdelphij			if (parsewccres(ndo, dp, ndo->ndo_vflag))
163818976Sdfr				return;
163918976Sdfr		} else {
1640276788Sdelphij			if (parsestatus(ndo, dp, &er) != 0)
164118976Sdfr				return;
164218976Sdfr		}
164318976Sdfr		break;
164418976Sdfr
164517680Spst	case NFSPROC_RENAME:
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, " from:"));
1653276788Sdelphij				if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
165418976Sdfr					break;
1655276788Sdelphij				ND_PRINT((ndo, " to:"));
1656276788Sdelphij				if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
165718976Sdfr					break;
165818976Sdfr			}
165917680Spst			return;
166018976Sdfr		} else {
1661276788Sdelphij			if (parsestatus(ndo, dp, &er) != 0)
166218976Sdfr				return;
166318976Sdfr		}
166417680Spst		break;
166517680Spst
166617680Spst	case NFSPROC_LINK:
1667276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
166818976Sdfr			break;
166918976Sdfr		if (v3) {
1670276788Sdelphij			if (!(dp = parsestatus(ndo, dp, &er)))
167118976Sdfr				break;
1672276788Sdelphij			if (ndo->ndo_vflag) {
1673276788Sdelphij				ND_PRINT((ndo, " file POST:"));
1674276788Sdelphij				if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
167518976Sdfr					break;
1676276788Sdelphij				ND_PRINT((ndo, " dir:"));
1677276788Sdelphij				if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
167818976Sdfr					break;
167918976Sdfr				return;
168018976Sdfr			}
168118976Sdfr		} else {
1682276788Sdelphij			if (parsestatus(ndo, dp, &er) != 0)
168318976Sdfr				return;
168418976Sdfr		}
168517680Spst		break;
168617680Spst
168718976Sdfr	case NFSPROC_READDIR:
1688276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
168918976Sdfr			break;
169018976Sdfr		if (v3) {
1691276788Sdelphij			if (parsev3rddirres(ndo, dp, ndo->ndo_vflag))
169218976Sdfr				return;
169318976Sdfr		} else {
1694276788Sdelphij			if (parserddires(ndo, dp) != 0)
169518976Sdfr				return;
169618976Sdfr		}
169718976Sdfr		break;
169818976Sdfr
169918976Sdfr	case NFSPROC_READDIRPLUS:
1700276788Sdelphij		if (!(dp = parserep(ndo, rp, length)))
170118976Sdfr			break;
1702276788Sdelphij		if (parsev3rddirres(ndo, dp, ndo->ndo_vflag))
170317680Spst			return;
170417680Spst		break;
170517680Spst
170618976Sdfr	case NFSPROC_FSSTAT:
1707276788Sdelphij		dp = parserep(ndo, rp, length);
1708276788Sdelphij		if (dp != NULL && parsestatfs(ndo, dp, v3) != 0)
170917680Spst			return;
171017680Spst		break;
171117680Spst
171218976Sdfr	case NFSPROC_FSINFO:
1713276788Sdelphij		dp = parserep(ndo, rp, length);
1714276788Sdelphij		if (dp != NULL && parsefsinfo(ndo, dp) != 0)
171517680Spst			return;
171617680Spst		break;
171717680Spst
171818976Sdfr	case NFSPROC_PATHCONF:
1719276788Sdelphij		dp = parserep(ndo, rp, length);
1720276788Sdelphij		if (dp != NULL && parsepathconf(ndo, dp) != 0)
172117680Spst			return;
172217680Spst		break;
172317680Spst
172418976Sdfr	case NFSPROC_COMMIT:
1725276788Sdelphij		dp = parserep(ndo, rp, length);
1726276788Sdelphij		if (dp != NULL && parsewccres(ndo, dp, ndo->ndo_vflag) != 0)
172717680Spst			return;
172817680Spst		break;
172917680Spst
173017680Spst	default:
173117680Spst		return;
173217680Spst	}
173318976Sdfrtrunc:
173426183Sfenner	if (!nfserr)
1735276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
173617680Spst}
1737