xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_xdr.c (revision f7877f5d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
527242a7cSthurlow  * Common Development and Distribution License (the "License").
627242a7cSthurlow  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21bbe876c0SMarcel Telka 
22bbe876c0SMarcel Telka /*
235dde82e7SMarcel Telka  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
24bbe876c0SMarcel Telka  */
25bbe876c0SMarcel Telka 
267c478bd9Sstevel@tonic-gate /*
27c242f9a0Schunli zhang - Sun Microsystems - Irvine United States  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
280a701b1eSRobert Gordon  * Use is subject to license terms.
297c478bd9Sstevel@tonic-gate  */
30297b4d80SVitaliy Gusev /*
31e36d7b11SSebastien Roy  * Copyright (c) 2013 by Delphix. All rights reserved.
32297b4d80SVitaliy Gusev  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * A handcoded version based on the original rpcgen code.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * Note: All future NFS4 protocol changes should be added by hand
387c478bd9Sstevel@tonic-gate  * to this file.
397c478bd9Sstevel@tonic-gate  *
407c478bd9Sstevel@tonic-gate  * CAUTION: All protocol changes must also be propagated to:
417c478bd9Sstevel@tonic-gate  *     usr/src/cmd/cmd-inet/usr.sbin/snoop/nfs4_xdr.c
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
467c478bd9Sstevel@tonic-gate #include <sys/dnlc.h>
477c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
487c478bd9Sstevel@tonic-gate #include <nfs/nfs4_kprot.h>
497c478bd9Sstevel@tonic-gate #include <nfs/rnode4.h>
507c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h>
517c478bd9Sstevel@tonic-gate #include <nfs/nfs4_clnt.h>
527c478bd9Sstevel@tonic-gate #include <sys/sdt.h>
532f172c55SRobert Thurlow #include <sys/mkdev.h>
547c478bd9Sstevel@tonic-gate #include <rpc/rpc_rdma.h>
552f172c55SRobert Thurlow #include <rpc/xdr.h>
562f172c55SRobert Thurlow 
572f172c55SRobert Thurlow #define	xdr_dev_t xdr_u_int
582f172c55SRobert Thurlow 
592f172c55SRobert Thurlow extern bool_t xdr_netbuf(XDR *, struct netbuf *);
602f172c55SRobert Thurlow extern bool_t xdr_vector(XDR *, char *, const uint_t, const uint_t,
612f172c55SRobert Thurlow 	const xdrproc_t);
622f172c55SRobert Thurlow bool_t xdr_knetconfig(XDR *, struct knetconfig *);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate bool_t
xdr_bitmap4(XDR * xdrs,bitmap4 * objp)657c478bd9Sstevel@tonic-gate xdr_bitmap4(XDR *xdrs, bitmap4 *objp)
667c478bd9Sstevel@tonic-gate {
677c478bd9Sstevel@tonic-gate 	int32_t len, size;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	if (xdrs->x_op == XDR_FREE)
707c478bd9Sstevel@tonic-gate 		return (TRUE);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	/*
737c478bd9Sstevel@tonic-gate 	 * Simplified bitmap4 processing, always encode from uint64_t
747c478bd9Sstevel@tonic-gate 	 * to 2 uint32_t's, always decode first 2 uint32_t's into a
757c478bd9Sstevel@tonic-gate 	 * uint64_t and ignore all of the rest.
767c478bd9Sstevel@tonic-gate 	 */
777c478bd9Sstevel@tonic-gate 	if (xdrs->x_op == XDR_ENCODE) {
787c478bd9Sstevel@tonic-gate 		len = 2;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 		if (!XDR_PUTINT32(xdrs, &len))
817c478bd9Sstevel@tonic-gate 			return (FALSE);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN)
847c478bd9Sstevel@tonic-gate 		if (XDR_PUTINT32(xdrs, (int32_t *)((char *)objp +
850a701b1eSRobert Gordon 		    BYTES_PER_XDR_UNIT)) == TRUE) {
867c478bd9Sstevel@tonic-gate 			return (XDR_PUTINT32(xdrs, (int32_t *)objp));
877c478bd9Sstevel@tonic-gate 		}
887c478bd9Sstevel@tonic-gate #elif defined(_BIG_ENDIAN)
897c478bd9Sstevel@tonic-gate 		if (XDR_PUTINT32(xdrs, (int32_t *)objp) == TRUE) {
907c478bd9Sstevel@tonic-gate 			return (XDR_PUTINT32(xdrs, (int32_t *)((char *)objp +
910a701b1eSRobert Gordon 			    BYTES_PER_XDR_UNIT)));
927c478bd9Sstevel@tonic-gate 		}
937c478bd9Sstevel@tonic-gate #endif
947c478bd9Sstevel@tonic-gate 		return (FALSE);
957c478bd9Sstevel@tonic-gate 	}
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	if (!XDR_GETINT32(xdrs, &len))
987c478bd9Sstevel@tonic-gate 		return (FALSE);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	/*
1017c478bd9Sstevel@tonic-gate 	 * Common fast DECODE cases
1027c478bd9Sstevel@tonic-gate 	 */
1037c478bd9Sstevel@tonic-gate 	if (len == 2) {
1047c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN)
1057c478bd9Sstevel@tonic-gate 		if (XDR_GETINT32(xdrs, (int32_t *)((char *)objp +
1060a701b1eSRobert Gordon 		    BYTES_PER_XDR_UNIT)) == TRUE) {
1077c478bd9Sstevel@tonic-gate 			return (XDR_GETINT32(xdrs, (int32_t *)objp));
1087c478bd9Sstevel@tonic-gate 		}
1097c478bd9Sstevel@tonic-gate #elif defined(_BIG_ENDIAN)
1107c478bd9Sstevel@tonic-gate 		if (XDR_GETINT32(xdrs, (int32_t *)objp) == TRUE) {
1117c478bd9Sstevel@tonic-gate 			return (XDR_GETINT32(xdrs, (int32_t *)((char *)objp +
1120a701b1eSRobert Gordon 			    BYTES_PER_XDR_UNIT)));
1137c478bd9Sstevel@tonic-gate 		}
1147c478bd9Sstevel@tonic-gate #endif
1157c478bd9Sstevel@tonic-gate 		return (FALSE);
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	*objp = 0;
1197c478bd9Sstevel@tonic-gate 	if (len == 0)
1207c478bd9Sstevel@tonic-gate 		return (TRUE);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	/*
1237c478bd9Sstevel@tonic-gate 	 * The not so common DECODE cases, len == 1 || len > 2
1247c478bd9Sstevel@tonic-gate 	 */
1257c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN)
1267c478bd9Sstevel@tonic-gate 	if (!XDR_GETINT32(xdrs, (int32_t *)((char *)objp + BYTES_PER_XDR_UNIT)))
1277c478bd9Sstevel@tonic-gate 		return (FALSE);
1287c478bd9Sstevel@tonic-gate 	if (--len == 0)
1297c478bd9Sstevel@tonic-gate 		return (TRUE);
1307c478bd9Sstevel@tonic-gate 	if (!XDR_GETINT32(xdrs, (int32_t *)objp))
1317c478bd9Sstevel@tonic-gate 		return (FALSE);
1327c478bd9Sstevel@tonic-gate #elif defined(_BIG_ENDIAN)
1337c478bd9Sstevel@tonic-gate 	if (!XDR_GETINT32(xdrs, (int32_t *)objp))
1347c478bd9Sstevel@tonic-gate 		return (FALSE);
1357c478bd9Sstevel@tonic-gate 	if (--len == 0)
1367c478bd9Sstevel@tonic-gate 		return (TRUE);
1377c478bd9Sstevel@tonic-gate 	if (!XDR_GETINT32(xdrs, (int32_t *)((char *)objp + BYTES_PER_XDR_UNIT)))
1387c478bd9Sstevel@tonic-gate 		return (FALSE);
1397c478bd9Sstevel@tonic-gate #else
1407c478bd9Sstevel@tonic-gate 	return (FALSE);
1417c478bd9Sstevel@tonic-gate #endif
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	if (--len == 0)
1447c478bd9Sstevel@tonic-gate 		return (TRUE);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	size = len * BYTES_PER_XDR_UNIT;
1477c478bd9Sstevel@tonic-gate 	return (XDR_CONTROL(xdrs, XDR_SKIPBYTES, &size));
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate /* Called by xdr_array, nfsid_map_xdr */
1517c478bd9Sstevel@tonic-gate bool_t
xdr_utf8string(XDR * xdrs,utf8string * objp)1527c478bd9Sstevel@tonic-gate xdr_utf8string(XDR *xdrs, utf8string *objp)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	if (xdrs->x_op != XDR_FREE)
1557c478bd9Sstevel@tonic-gate 		return (xdr_bytes(xdrs, (char **)&objp->utf8string_val,
1560a701b1eSRobert Gordon 		    (uint_t *)&objp->utf8string_len, NFS4_MAX_UTF8STRING));
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if (objp->utf8string_val != NULL) {
1597c478bd9Sstevel@tonic-gate 		kmem_free(objp->utf8string_val, objp->utf8string_len);
1607c478bd9Sstevel@tonic-gate 		objp->utf8string_val = NULL;
1617c478bd9Sstevel@tonic-gate 	}
1627c478bd9Sstevel@tonic-gate 	return (TRUE);
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1652f172c55SRobert Thurlow /*
1662f172c55SRobert Thurlow  * used by NFSv4 referrals to get info needed for NFSv4 referral mount.
1672f172c55SRobert Thurlow  */
1682f172c55SRobert Thurlow bool_t
xdr_nfs_fsl_info(XDR * xdrs,struct nfs_fsl_info * objp)1692f172c55SRobert Thurlow xdr_nfs_fsl_info(XDR *xdrs, struct nfs_fsl_info *objp)
1702f172c55SRobert Thurlow {
1712f172c55SRobert Thurlow 
1722f172c55SRobert Thurlow 	if (!xdr_u_int(xdrs, &objp->netbuf_len))
1732f172c55SRobert Thurlow 		return (FALSE);
1742f172c55SRobert Thurlow 	if (!xdr_u_int(xdrs, &objp->netnm_len))
1752f172c55SRobert Thurlow 		return (FALSE);
1762f172c55SRobert Thurlow 	if (!xdr_u_int(xdrs, &objp->knconf_len))
1772f172c55SRobert Thurlow 		return (FALSE);
1782f172c55SRobert Thurlow 
1792f172c55SRobert Thurlow #if defined(_LP64)
1802f172c55SRobert Thurlow 	/*
1812f172c55SRobert Thurlow 	 * The object can come from a 32-bit binary; nfsmapid.
1822f172c55SRobert Thurlow 	 * To be safe we double the size of the knetconfig to
1832f172c55SRobert Thurlow 	 * allow some buffering for decoding.
1842f172c55SRobert Thurlow 	 */
1852f172c55SRobert Thurlow 	if (xdrs->x_op == XDR_DECODE)
1862f172c55SRobert Thurlow 		objp->knconf_len += sizeof (struct knetconfig);
1872f172c55SRobert Thurlow #endif
1882f172c55SRobert Thurlow 
1892f172c55SRobert Thurlow 	if (!xdr_string(xdrs, &objp->netname, ~0))
1902f172c55SRobert Thurlow 		return (FALSE);
1912f172c55SRobert Thurlow 	if (!xdr_pointer(xdrs, (char **)&objp->addr, objp->netbuf_len,
1922f172c55SRobert Thurlow 	    (xdrproc_t)xdr_netbuf))
1932f172c55SRobert Thurlow 		return (FALSE);
1942f172c55SRobert Thurlow 	if (!xdr_pointer(xdrs, (char **)&objp->knconf,
1952f172c55SRobert Thurlow 	    objp->knconf_len, (xdrproc_t)xdr_knetconfig))
1962f172c55SRobert Thurlow 		return (FALSE);
1972f172c55SRobert Thurlow 	return (TRUE);
1982f172c55SRobert Thurlow }
1992f172c55SRobert Thurlow 
2002f172c55SRobert Thurlow bool_t
xdr_knetconfig(XDR * xdrs,struct knetconfig * objp)2012f172c55SRobert Thurlow xdr_knetconfig(XDR *xdrs, struct knetconfig *objp)
2022f172c55SRobert Thurlow {
2032f172c55SRobert Thurlow 	rpc_inline_t *buf;
2042f172c55SRobert Thurlow 	u_longlong_t dev64;
2052f172c55SRobert Thurlow #if !defined(_LP64)
2062f172c55SRobert Thurlow 	uint32_t major, minor;
2072f172c55SRobert Thurlow #endif
2082f172c55SRobert Thurlow 	int i;
2092f172c55SRobert Thurlow 
2102f172c55SRobert Thurlow 	if (!xdr_u_int(xdrs, &objp->knc_semantics))
2112f172c55SRobert Thurlow 		return (FALSE);
2122f172c55SRobert Thurlow 	if (xdrs->x_op == XDR_DECODE) {
2132f172c55SRobert Thurlow 		objp->knc_protofmly = (((char *)objp) +
2142f172c55SRobert Thurlow 		    sizeof (struct knetconfig));
2152f172c55SRobert Thurlow 		objp->knc_proto = objp->knc_protofmly + KNC_STRSIZE;
2162f172c55SRobert Thurlow 	}
2172f172c55SRobert Thurlow 	if (!xdr_opaque(xdrs, objp->knc_protofmly, KNC_STRSIZE))
2182f172c55SRobert Thurlow 		return (FALSE);
2192f172c55SRobert Thurlow 	if (!xdr_opaque(xdrs, objp->knc_proto, KNC_STRSIZE))
2202f172c55SRobert Thurlow 		return (FALSE);
2212f172c55SRobert Thurlow 
2222f172c55SRobert Thurlow 	/*
2232f172c55SRobert Thurlow 	 * For interoperability between 32-bit daemon and 64-bit kernel,
2242f172c55SRobert Thurlow 	 * we always treat dev_t as 64-bit number and do the expanding
2252f172c55SRobert Thurlow 	 * or compression of dev_t as needed.
2262f172c55SRobert Thurlow 	 * We have to hand craft the conversion since there is no available
2272f172c55SRobert Thurlow 	 * function in ddi.c. Besides ddi.c is available only in the kernel
2282f172c55SRobert Thurlow 	 * and we want to keep both user and kernel of xdr_knetconfig() the
2292f172c55SRobert Thurlow 	 * same for consistency.
2302f172c55SRobert Thurlow 	 */
2312f172c55SRobert Thurlow 	if (xdrs->x_op == XDR_ENCODE) {
2322f172c55SRobert Thurlow #if defined(_LP64)
2332f172c55SRobert Thurlow 		dev64 = objp->knc_rdev;
2342f172c55SRobert Thurlow #else
2352f172c55SRobert Thurlow 		major = (objp->knc_rdev >> NBITSMINOR32) & MAXMAJ32;
2362f172c55SRobert Thurlow 		minor = objp->knc_rdev & MAXMIN32;
2372f172c55SRobert Thurlow 		dev64 = (((unsigned long long)major) << NBITSMINOR64) | minor;
2382f172c55SRobert Thurlow #endif
2392f172c55SRobert Thurlow 		if (!xdr_u_longlong_t(xdrs, &dev64))
2402f172c55SRobert Thurlow 			return (FALSE);
2412f172c55SRobert Thurlow 	}
2422f172c55SRobert Thurlow 	if (xdrs->x_op == XDR_DECODE) {
2432f172c55SRobert Thurlow #if defined(_LP64)
2442f172c55SRobert Thurlow 		if (!xdr_u_longlong_t(xdrs, (u_longlong_t *)&objp->knc_rdev))
2452f172c55SRobert Thurlow 			return (FALSE);
2462f172c55SRobert Thurlow #else
2472f172c55SRobert Thurlow 		if (!xdr_u_longlong_t(xdrs, &dev64))
2482f172c55SRobert Thurlow 			return (FALSE);
2492f172c55SRobert Thurlow 
2502f172c55SRobert Thurlow 		major = (dev64 >> NBITSMINOR64) & L_MAXMAJ32;
2512f172c55SRobert Thurlow 		minor = dev64 & L_MAXMIN32;
2522f172c55SRobert Thurlow 		objp->knc_rdev = (major << L_BITSMINOR32) | minor;
2532f172c55SRobert Thurlow #endif
2542f172c55SRobert Thurlow 	}
2552f172c55SRobert Thurlow 
2562f172c55SRobert Thurlow 	if (xdrs->x_op == XDR_ENCODE) {
2572f172c55SRobert Thurlow 		buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
2582f172c55SRobert Thurlow 		if (buf == NULL) {
2592f172c55SRobert Thurlow 			if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
2602f172c55SRobert Thurlow 			    sizeof (uint_t), (xdrproc_t)xdr_u_int))
2612f172c55SRobert Thurlow 				return (FALSE);
2622f172c55SRobert Thurlow 		} else {
2632f172c55SRobert Thurlow 			uint_t *genp;
2642f172c55SRobert Thurlow 
2652f172c55SRobert Thurlow 			for (i = 0, genp = objp->knc_unused;
2662f172c55SRobert Thurlow 			    i < 8; i++) {
2672f172c55SRobert Thurlow #if defined(_LP64) || defined(_KERNEL)
2682f172c55SRobert Thurlow 				IXDR_PUT_U_INT32(buf, *genp++);
2692f172c55SRobert Thurlow #else
2702f172c55SRobert Thurlow 				IXDR_PUT_U_LONG(buf, *genp++);
2712f172c55SRobert Thurlow #endif
2722f172c55SRobert Thurlow 			}
2732f172c55SRobert Thurlow 		}
2742f172c55SRobert Thurlow 		return (TRUE);
2752f172c55SRobert Thurlow 	} else if (xdrs->x_op == XDR_DECODE) {
2762f172c55SRobert Thurlow 		buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
2772f172c55SRobert Thurlow 		if (buf == NULL) {
2782f172c55SRobert Thurlow 			if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
2792f172c55SRobert Thurlow 			    sizeof (uint_t), (xdrproc_t)xdr_u_int))
2802f172c55SRobert Thurlow 				return (FALSE);
2812f172c55SRobert Thurlow 		} else {
2822f172c55SRobert Thurlow 			uint_t *genp;
2832f172c55SRobert Thurlow 
2842f172c55SRobert Thurlow 			for (i = 0, genp = objp->knc_unused;
2852f172c55SRobert Thurlow 			    i < 8; i++) {
2862f172c55SRobert Thurlow #if defined(_LP64) || defined(_KERNEL)
2872f172c55SRobert Thurlow 					*genp++ = IXDR_GET_U_INT32(buf);
2882f172c55SRobert Thurlow #else
2892f172c55SRobert Thurlow 					*genp++ = IXDR_GET_U_LONG(buf);
2902f172c55SRobert Thurlow #endif
2912f172c55SRobert Thurlow 			}
2922f172c55SRobert Thurlow 		}
2932f172c55SRobert Thurlow 		return (TRUE);
2942f172c55SRobert Thurlow 	}
2952f172c55SRobert Thurlow 
2962f172c55SRobert Thurlow 	if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
2972f172c55SRobert Thurlow 	    sizeof (uint_t), (xdrproc_t)xdr_u_int))
2982f172c55SRobert Thurlow 		return (FALSE);
2992f172c55SRobert Thurlow 	return (TRUE);
3002f172c55SRobert Thurlow }
3012f172c55SRobert Thurlow 
3027c478bd9Sstevel@tonic-gate /*
303eac3aab7Srobinson  * XDR_INLINE decode a filehandle.
3047c46fb7fSek  */
3057c46fb7fSek bool_t
xdr_inline_decode_nfs_fh4(uint32_t * ptr,nfs_fh4_fmt_t * fhp,uint32_t fhsize)306eac3aab7Srobinson xdr_inline_decode_nfs_fh4(uint32_t *ptr, nfs_fh4_fmt_t *fhp, uint32_t fhsize)
3077c46fb7fSek {
308eac3aab7Srobinson 	uchar_t *bp = (uchar_t *)ptr;
3094f85d229Srobinson 	uchar_t *cp;
310eac3aab7Srobinson 	uint32_t dsize;
311eac3aab7Srobinson 	uintptr_t resid;
3124f85d229Srobinson 
3137c46fb7fSek 	/*
314eac3aab7Srobinson 	 * Check to see if what the client sent us is bigger or smaller
315eac3aab7Srobinson 	 * than what we can ever possibly send out. NFS_FHMAXDATA is
316eac3aab7Srobinson 	 * unfortunately badly named as it is no longer the max and is
317eac3aab7Srobinson 	 * really the min of what is sent over the wire.
3187c46fb7fSek 	 */
319eac3aab7Srobinson 	if (fhsize > sizeof (nfs_fh4_fmt_t) || fhsize < (sizeof (fsid_t) +
320eac3aab7Srobinson 	    sizeof (ushort_t) + NFS_FHMAXDATA +
321eac3aab7Srobinson 	    sizeof (ushort_t) + NFS_FHMAXDATA)) {
322eac3aab7Srobinson 		return (FALSE);
323eac3aab7Srobinson 	}
3244f85d229Srobinson 
3257c46fb7fSek 	/*
326eac3aab7Srobinson 	 * All internal parts of a filehandle are in native byte order.
327eac3aab7Srobinson 	 *
328eac3aab7Srobinson 	 * Decode what should be fh4_fsid, it is aligned.
3297c46fb7fSek 	 */
330eac3aab7Srobinson 	fhp->fh4_fsid.val[0] = *(uint32_t *)bp;
331eac3aab7Srobinson 	bp += BYTES_PER_XDR_UNIT;
332eac3aab7Srobinson 	fhp->fh4_fsid.val[1] = *(uint32_t *)bp;
333eac3aab7Srobinson 	bp += BYTES_PER_XDR_UNIT;
3347c46fb7fSek 
3357c46fb7fSek 	/*
336eac3aab7Srobinson 	 * Decode what should be fh4_len.  fh4_len is two bytes, so we're
337eac3aab7Srobinson 	 * unaligned now.
3387c46fb7fSek 	 */
339eac3aab7Srobinson 	cp = (uchar_t *)&fhp->fh4_len;
340eac3aab7Srobinson 	*cp++ = *bp++;
341eac3aab7Srobinson 	*cp++ = *bp++;
342eac3aab7Srobinson 	fhsize -= 2 * BYTES_PER_XDR_UNIT + sizeof (ushort_t);
3437c46fb7fSek 
3447c46fb7fSek 	/*
345da6c28aaSamw 	 * For backwards compatibility, the fid length may be less than
346eac3aab7Srobinson 	 * NFS_FHMAXDATA, but it was always encoded as NFS_FHMAXDATA bytes.
3477c46fb7fSek 	 */
348eac3aab7Srobinson 	dsize = fhp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_len;
3497c46fb7fSek 
3507c46fb7fSek 	/*
351eac3aab7Srobinson 	 * Make sure the client isn't sending us a bogus length for fh4_data.
3527c46fb7fSek 	 */
353eac3aab7Srobinson 	if (fhsize < dsize)
354eac3aab7Srobinson 		return (FALSE);
355eac3aab7Srobinson 	bcopy(bp, fhp->fh4_data, dsize);
356eac3aab7Srobinson 	bp += dsize;
357eac3aab7Srobinson 	fhsize -= dsize;
3587c46fb7fSek 
359eac3aab7Srobinson 	if (fhsize < sizeof (ushort_t))
360eac3aab7Srobinson 		return (FALSE);
361eac3aab7Srobinson 	cp = (uchar_t *)&fhp->fh4_xlen;
362eac3aab7Srobinson 	*cp++ = *bp++;
363eac3aab7Srobinson 	*cp++ = *bp++;
364eac3aab7Srobinson 	fhsize -= sizeof (ushort_t);
365eac3aab7Srobinson 
366eac3aab7Srobinson 	dsize = fhp->fh4_xlen < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_xlen;
3677c46fb7fSek 
3687c46fb7fSek 	/*
369eac3aab7Srobinson 	 * Make sure the client isn't sending us a bogus length for fh4_xdata.
3707c46fb7fSek 	 */
371eac3aab7Srobinson 	if (fhsize < dsize)
372eac3aab7Srobinson 		return (FALSE);
373eac3aab7Srobinson 	bcopy(bp, fhp->fh4_xdata, dsize);
374eac3aab7Srobinson 	fhsize -= dsize;
375eac3aab7Srobinson 	bp += dsize;
3767c46fb7fSek 
3777c46fb7fSek 	/*
378eac3aab7Srobinson 	 * We realign things on purpose, so skip any padding
3797c46fb7fSek 	 */
380eac3aab7Srobinson 	resid = (uintptr_t)bp % BYTES_PER_XDR_UNIT;
381eac3aab7Srobinson 	if (resid != 0) {
382eac3aab7Srobinson 		if (fhsize < (BYTES_PER_XDR_UNIT - resid))
383eac3aab7Srobinson 			return (FALSE);
384eac3aab7Srobinson 		bp += BYTES_PER_XDR_UNIT - resid;
385eac3aab7Srobinson 		fhsize -= BYTES_PER_XDR_UNIT - resid;
386eac3aab7Srobinson 	}
3877c46fb7fSek 
388eac3aab7Srobinson 	if (fhsize < BYTES_PER_XDR_UNIT)
389eac3aab7Srobinson 		return (FALSE);
390eac3aab7Srobinson 	fhp->fh4_flag = *(uint32_t *)bp;
391eac3aab7Srobinson 	bp += BYTES_PER_XDR_UNIT;
392eac3aab7Srobinson 	fhsize -= BYTES_PER_XDR_UNIT;
3937c46fb7fSek 
3947c46fb7fSek #ifdef VOLATILE_FH_TEST
395eac3aab7Srobinson 	if (fhsize < BYTES_PER_XDR_UNIT)
396eac3aab7Srobinson 		return (FALSE);
397eac3aab7Srobinson 	fhp->fh4_volatile_id = *(uint32_t *)bp;
398eac3aab7Srobinson 	bp += BYTES_PER_XDR_UNIT;
399eac3aab7Srobinson 	fhsize -= BYTES_PER_XDR_UNIT;
4007c46fb7fSek #endif
401eac3aab7Srobinson 	/*
402eac3aab7Srobinson 	 * Make sure client didn't send extra bytes
403eac3aab7Srobinson 	 */
404eac3aab7Srobinson 	if (fhsize != 0)
405eac3aab7Srobinson 		return (FALSE);
4067c46fb7fSek 	return (TRUE);
4077c46fb7fSek }
4087c46fb7fSek 
4097c46fb7fSek static bool_t
xdr_decode_nfs_fh4(XDR * xdrs,nfs_fh4 * objp)4107c46fb7fSek xdr_decode_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
4117c46fb7fSek {
4127c46fb7fSek 	uint32_t fhsize;		/* filehandle size */
4134f85d229Srobinson 	uint32_t bufsize;
4144f85d229Srobinson 	rpc_inline_t *ptr;
41527242a7cSthurlow 	uchar_t *bp;
4167c46fb7fSek 
4177c46fb7fSek 	ASSERT(xdrs->x_op == XDR_DECODE);
4187c46fb7fSek 
4197c46fb7fSek 	/*
4207c46fb7fSek 	 * Retrieve the filehandle length.
4217c46fb7fSek 	 */
4227c46fb7fSek 	if (!XDR_GETINT32(xdrs, (int32_t *)&fhsize))
4237c46fb7fSek 		return (FALSE);
4247c46fb7fSek 
4254f85d229Srobinson 	objp->nfs_fh4_val = NULL;
4264f85d229Srobinson 	objp->nfs_fh4_len = 0;
4274f85d229Srobinson 
4287c46fb7fSek 	/*
4294f85d229Srobinson 	 * Check to see if what the client sent us is bigger or smaller
4304f85d229Srobinson 	 * than what we can ever possibly send out. NFS_FHMAXDATA is
4314f85d229Srobinson 	 * unfortunately badly named as it is no longer the max and is
4324f85d229Srobinson 	 * really the min of what is sent over the wire.
4337c46fb7fSek 	 */
4344f85d229Srobinson 	if (fhsize > sizeof (nfs_fh4_fmt_t) || fhsize < (sizeof (fsid_t) +
4354f85d229Srobinson 	    sizeof (ushort_t) + NFS_FHMAXDATA +
4364f85d229Srobinson 	    sizeof (ushort_t) + NFS_FHMAXDATA)) {
4374f85d229Srobinson 		if (!XDR_CONTROL(xdrs, XDR_SKIPBYTES, &fhsize))
4384f85d229Srobinson 			return (FALSE);
4394f85d229Srobinson 		return (TRUE);
4404f85d229Srobinson 	}
4417c46fb7fSek 
4424f85d229Srobinson 	/*
4434f85d229Srobinson 	 * bring in fhsize plus any padding
4444f85d229Srobinson 	 */
4454f85d229Srobinson 	bufsize = RNDUP(fhsize);
4464f85d229Srobinson 	ptr = XDR_INLINE(xdrs, bufsize);
447eac3aab7Srobinson 	bp = (uchar_t *)ptr;
4484f85d229Srobinson 	if (ptr == NULL) {
44927242a7cSthurlow 		bp = kmem_alloc(bufsize, KM_SLEEP);
45027242a7cSthurlow 		if (!xdr_opaque(xdrs, (char *)bp, bufsize)) {
45127242a7cSthurlow 			kmem_free(bp, bufsize);
4524f85d229Srobinson 			return (FALSE);
45327242a7cSthurlow 		}
4544f85d229Srobinson 	}
4557c46fb7fSek 
4567c46fb7fSek 	objp->nfs_fh4_val = kmem_zalloc(sizeof (nfs_fh4_fmt_t), KM_SLEEP);
4577c46fb7fSek 	objp->nfs_fh4_len = sizeof (nfs_fh4_fmt_t);
458eac3aab7Srobinson 
459eac3aab7Srobinson 	if (xdr_inline_decode_nfs_fh4((uint32_t *)bp,
460eac3aab7Srobinson 	    (nfs_fh4_fmt_t *)objp->nfs_fh4_val, fhsize) == FALSE) {
461eac3aab7Srobinson 		/*
462eac3aab7Srobinson 		 * If in the process of decoding we find the file handle
463eac3aab7Srobinson 		 * is not correctly formed, we need to continue decoding
464eac3aab7Srobinson 		 * and trigger an NFS layer error. Set the nfs_fh4_len to
465eac3aab7Srobinson 		 * zero so it gets caught as a bad length.
466eac3aab7Srobinson 		 */
467eac3aab7Srobinson 		kmem_free(objp->nfs_fh4_val, objp->nfs_fh4_len);
468eac3aab7Srobinson 		objp->nfs_fh4_val = NULL;
469eac3aab7Srobinson 		objp->nfs_fh4_len = 0;
470eac3aab7Srobinson 	}
471eac3aab7Srobinson 
472eac3aab7Srobinson 	if (ptr == NULL)
47327242a7cSthurlow 		kmem_free(bp, bufsize);
474eac3aab7Srobinson 	return (TRUE);
475eac3aab7Srobinson }
476eac3aab7Srobinson 
477eac3aab7Srobinson /*
478eac3aab7Srobinson  * XDR_INLINE encode a filehandle.
479eac3aab7Srobinson  */
480eac3aab7Srobinson bool_t
xdr_inline_encode_nfs_fh4(uint32_t ** ptrp,uint32_t * ptr_redzone,nfs_fh4_fmt_t * fhp)481eac3aab7Srobinson xdr_inline_encode_nfs_fh4(uint32_t **ptrp, uint32_t *ptr_redzone,
4825dde82e7SMarcel Telka     nfs_fh4_fmt_t *fhp)
483eac3aab7Srobinson {
484eac3aab7Srobinson 	uint32_t *ptr = *ptrp;
485eac3aab7Srobinson 	uchar_t *cp;
486eac3aab7Srobinson 	uint_t otw_len, fsize, xsize;   /* otw, file, and export sizes */
487eac3aab7Srobinson 	uint32_t padword;
488eac3aab7Srobinson 
489eac3aab7Srobinson 	fsize = fhp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_len;
490eac3aab7Srobinson 	xsize = fhp->fh4_xlen < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_xlen;
4917c46fb7fSek 
4927c46fb7fSek 	/*
493eac3aab7Srobinson 	 * First get the initial and variable sized part of the filehandle.
4947c46fb7fSek 	 */
495eac3aab7Srobinson 	otw_len = sizeof (fhp->fh4_fsid) +
496eac3aab7Srobinson 	    sizeof (fhp->fh4_len) + fsize +
497eac3aab7Srobinson 	    sizeof (fhp->fh4_xlen) + xsize;
4987c46fb7fSek 
4997c46fb7fSek 	/*
500eac3aab7Srobinson 	 * Round out to a full word.
5017c46fb7fSek 	 */
502eac3aab7Srobinson 	otw_len = RNDUP(otw_len);
503eac3aab7Srobinson 	padword = (otw_len / BYTES_PER_XDR_UNIT);	/* includes fhlen */
5047c46fb7fSek 
5057c46fb7fSek 	/*
506eac3aab7Srobinson 	 * Add in the fixed sized pieces.
5077c46fb7fSek 	 */
508eac3aab7Srobinson 	otw_len += sizeof (fhp->fh4_flag);
509eac3aab7Srobinson #ifdef VOLATILE_FH_TEST
510eac3aab7Srobinson 	otw_len += sizeof (fhp->fh4_volatile_id);
511eac3aab7Srobinson #endif
5127c46fb7fSek 
5134f85d229Srobinson 	/*
514eac3aab7Srobinson 	 * Make sure we don't exceed our buffer.
5154f85d229Srobinson 	 */
516eac3aab7Srobinson 	if ((ptr + (otw_len / BYTES_PER_XDR_UNIT) + 1) > ptr_redzone)
517eac3aab7Srobinson 		return (FALSE);
5187c46fb7fSek 
5197c46fb7fSek 	/*
52027242a7cSthurlow 	 * Zero out the padding.
5217c46fb7fSek 	 */
522eac3aab7Srobinson 	ptr[padword] = 0;
5237c46fb7fSek 
52427242a7cSthurlow 	IXDR_PUT_U_INT32(ptr, otw_len);
52527242a7cSthurlow 
5264f85d229Srobinson 	/*
527eac3aab7Srobinson 	 * The rest of the filehandle is in native byteorder
5284f85d229Srobinson 	 */
529eac3aab7Srobinson 	/* fh4_fsid */
530eac3aab7Srobinson 	*ptr++ = (uint32_t)fhp->fh4_fsid.val[0];
531eac3aab7Srobinson 	*ptr++ = (uint32_t)fhp->fh4_fsid.val[1];
5327c46fb7fSek 
5337c46fb7fSek 	/*
534eac3aab7Srobinson 	 * Since the next pieces are unaligned, we need to
535eac3aab7Srobinson 	 * do bytewise copies.
5367c46fb7fSek 	 */
537eac3aab7Srobinson 	cp = (uchar_t *)ptr;
5387c46fb7fSek 
539eac3aab7Srobinson 	/* fh4_len + fh4_data */
540eac3aab7Srobinson 	bcopy(&fhp->fh4_len, cp, sizeof (fhp->fh4_len) + fsize);
541eac3aab7Srobinson 	cp += sizeof (fhp->fh4_len) + fsize;
542eac3aab7Srobinson 
543eac3aab7Srobinson 	/* fh4_xlen + fh4_xdata */
544eac3aab7Srobinson 	bcopy(&fhp->fh4_xlen, cp, sizeof (fhp->fh4_xlen) + xsize);
545eac3aab7Srobinson 	cp += sizeof (fhp->fh4_xlen) + xsize;
546eac3aab7Srobinson 
547eac3aab7Srobinson 	/* do necessary rounding/padding */
548eac3aab7Srobinson 	cp = (uchar_t *)RNDUP((uintptr_t)cp);
549eac3aab7Srobinson 	ptr = (uint32_t *)cp;
5507c46fb7fSek 
5514f85d229Srobinson 	/*
552eac3aab7Srobinson 	 * With the above padding, we're word aligned again.
5534f85d229Srobinson 	 */
554eac3aab7Srobinson 	ASSERT(((uintptr_t)ptr % BYTES_PER_XDR_UNIT) == 0);
555eac3aab7Srobinson 
556eac3aab7Srobinson 	/* fh4_flag */
557eac3aab7Srobinson 	*ptr++ = (uint32_t)fhp->fh4_flag;
558eac3aab7Srobinson 
559eac3aab7Srobinson #ifdef VOLATILE_FH_TEST
560eac3aab7Srobinson 	/* fh4_volatile_id */
561eac3aab7Srobinson 	*ptr++ = (uint32_t)fhp->fh4_volatile_id;
562eac3aab7Srobinson #endif
563eac3aab7Srobinson 	*ptrp = ptr;
564eac3aab7Srobinson 
5657c46fb7fSek 	return (TRUE);
5667c46fb7fSek }
5677c46fb7fSek 
5687c46fb7fSek static bool_t
xdr_encode_nfs_fh4(XDR * xdrs,nfs_fh4 * objp)5697c46fb7fSek xdr_encode_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
5707c46fb7fSek {
5714f85d229Srobinson 	uint_t otw_len, fsize, xsize;   /* otw, file, and export sizes */
5724f85d229Srobinson 	bool_t ret;
5734f85d229Srobinson 	rpc_inline_t *ptr;
5744f85d229Srobinson 	rpc_inline_t *buf = NULL;
5754f85d229Srobinson 	uint32_t *ptr_redzone;
5764f85d229Srobinson 	nfs_fh4_fmt_t *fhp;
5777c46fb7fSek 
5787c46fb7fSek 	ASSERT(xdrs->x_op == XDR_ENCODE);
5797c46fb7fSek 
5804f85d229Srobinson 	fhp = (nfs_fh4_fmt_t *)objp->nfs_fh4_val;
5814f85d229Srobinson 	fsize = fhp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_len;
5824f85d229Srobinson 	xsize = fhp->fh4_xlen < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_xlen;
5837c46fb7fSek 
5844f85d229Srobinson 	/*
5854f85d229Srobinson 	 * First get the over the wire size, it is the 4 bytes
5864f85d229Srobinson 	 * for the length, plus the combined size of the
5874f85d229Srobinson 	 * file handle components.
5884f85d229Srobinson 	 */
5894f85d229Srobinson 	otw_len = BYTES_PER_XDR_UNIT + sizeof (fhp->fh4_fsid) +
5904f85d229Srobinson 	    sizeof (fhp->fh4_len) + fsize +
5914f85d229Srobinson 	    sizeof (fhp->fh4_xlen) + xsize +
5924f85d229Srobinson 	    sizeof (fhp->fh4_flag);
5937c46fb7fSek #ifdef VOLATILE_FH_TEST
5944f85d229Srobinson 	otw_len += sizeof (fhp->fh4_volatile_id);
5957c46fb7fSek #endif
5967c46fb7fSek 	/*
5974f85d229Srobinson 	 * Round out to a full word.
5987c46fb7fSek 	 */
5994f85d229Srobinson 	otw_len = RNDUP(otw_len);
6007c46fb7fSek 
6017c46fb7fSek 	/*
6024f85d229Srobinson 	 * Next try to inline the XDR stream, if that fails (rare)
6034f85d229Srobinson 	 * allocate a buffer to encode the file handle and then
6044f85d229Srobinson 	 * copy it using xdr_opaque and free the buffer.
6057c46fb7fSek 	 */
6064f85d229Srobinson 	ptr = XDR_INLINE(xdrs, otw_len);
6074f85d229Srobinson 	if (ptr == NULL)
6084f85d229Srobinson 		ptr = buf = kmem_alloc(otw_len, KM_SLEEP);
6097c46fb7fSek 
6104f85d229Srobinson 	ptr_redzone = (uint32_t *)(ptr + (otw_len / BYTES_PER_XDR_UNIT));
6114f85d229Srobinson 	ret = xdr_inline_encode_nfs_fh4((uint32_t **)&ptr, ptr_redzone, fhp);
6127c46fb7fSek 
6134f85d229Srobinson 	if (buf != NULL) {
6144f85d229Srobinson 		if (ret == TRUE)
6154f85d229Srobinson 			ret = xdr_opaque(xdrs, (char *)buf, otw_len);
6164f85d229Srobinson 		kmem_free(buf, otw_len);
6174f85d229Srobinson 	}
6184f85d229Srobinson 	return (ret);
6197c46fb7fSek }
6207c46fb7fSek 
6217c46fb7fSek /*
6227c46fb7fSek  * XDR a NFSv4 filehandle.
623eac3aab7Srobinson  * Encoding interprets the contents (server).
624eac3aab7Srobinson  * Decoding the contents are opaque (client).
6257c478bd9Sstevel@tonic-gate  */
6267c478bd9Sstevel@tonic-gate bool_t
xdr_nfs_fh4(XDR * xdrs,nfs_fh4 * objp)6277c478bd9Sstevel@tonic-gate xdr_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
6287c478bd9Sstevel@tonic-gate {
629eac3aab7Srobinson 	switch (xdrs->x_op) {
630eac3aab7Srobinson 	case XDR_ENCODE:
6317c46fb7fSek 		return (xdr_encode_nfs_fh4(xdrs, objp));
632eac3aab7Srobinson 	case XDR_DECODE:
633eac3aab7Srobinson 		return (xdr_bytes(xdrs, (char **)&objp->nfs_fh4_val,
634eac3aab7Srobinson 		    (uint_t *)&objp->nfs_fh4_len, NFS4_FHSIZE));
635eac3aab7Srobinson 	case XDR_FREE:
636eac3aab7Srobinson 		if (objp->nfs_fh4_val != NULL) {
637eac3aab7Srobinson 			kmem_free(objp->nfs_fh4_val, objp->nfs_fh4_len);
638eac3aab7Srobinson 			objp->nfs_fh4_val = NULL;
639eac3aab7Srobinson 		}
640eac3aab7Srobinson 		return (TRUE);
6417c478bd9Sstevel@tonic-gate 	}
642eac3aab7Srobinson 	return (FALSE);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate /* Called by xdr_array */
6467c478bd9Sstevel@tonic-gate static bool_t
xdr_fs_location4(XDR * xdrs,fs_location4 * objp)6477c478bd9Sstevel@tonic-gate xdr_fs_location4(XDR *xdrs, fs_location4 *objp)
6487c478bd9Sstevel@tonic-gate {
6492f172c55SRobert Thurlow 	if (xdrs->x_op == XDR_DECODE) {
6502f172c55SRobert Thurlow 		objp->server_val = NULL;
6512f172c55SRobert Thurlow 		objp->rootpath.pathname4_val = NULL;
6522f172c55SRobert Thurlow 	}
6537c478bd9Sstevel@tonic-gate 	if (!xdr_array(xdrs, (char **)&objp->server_val,
6542f172c55SRobert Thurlow 	    (uint_t *)&objp->server_len, NFS4_MAX_UTF8STRING,
6550a701b1eSRobert Gordon 	    sizeof (utf8string), (xdrproc_t)xdr_utf8string))
6567c478bd9Sstevel@tonic-gate 		return (FALSE);
6577c478bd9Sstevel@tonic-gate 	return (xdr_array(xdrs, (char **)&objp->rootpath.pathname4_val,
6580a701b1eSRobert Gordon 	    (uint_t *)&objp->rootpath.pathname4_len,
6590a701b1eSRobert Gordon 	    NFS4_MAX_PATHNAME4,
6600a701b1eSRobert Gordon 	    sizeof (utf8string), (xdrproc_t)xdr_utf8string));
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate /* Called by xdr_array */
6647c478bd9Sstevel@tonic-gate static bool_t
xdr_nfsace4(XDR * xdrs,nfsace4 * objp)6657c478bd9Sstevel@tonic-gate xdr_nfsace4(XDR *xdrs, nfsace4 *objp)
6667c478bd9Sstevel@tonic-gate {
6677c478bd9Sstevel@tonic-gate 	if (xdrs->x_op != XDR_FREE) {
6687c478bd9Sstevel@tonic-gate 		if (!xdr_u_int(xdrs, &objp->type))
6697c478bd9Sstevel@tonic-gate 			return (FALSE);
6707c478bd9Sstevel@tonic-gate 		if (!xdr_u_int(xdrs, &objp->flag))
6717c478bd9Sstevel@tonic-gate 			return (FALSE);
6727c478bd9Sstevel@tonic-gate 		if (!xdr_u_int(xdrs, &objp->access_mask))
6737c478bd9Sstevel@tonic-gate 			return (FALSE);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		if (xdrs->x_op == XDR_DECODE) {
6767c478bd9Sstevel@tonic-gate 			objp->who.utf8string_val = NULL;
6777c478bd9Sstevel@tonic-gate 			objp->who.utf8string_len = 0;
6787c478bd9Sstevel@tonic-gate 		}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 		return (xdr_bytes(xdrs, (char **)&objp->who.utf8string_val,
6810a701b1eSRobert Gordon 		    (uint_t *)&objp->who.utf8string_len,
6820a701b1eSRobert Gordon 		    NFS4_MAX_UTF8STRING));
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	/*
6867c478bd9Sstevel@tonic-gate 	 * Optimized free case
6877c478bd9Sstevel@tonic-gate 	 */
6887c478bd9Sstevel@tonic-gate 	if (objp->who.utf8string_val != NULL) {
6897c478bd9Sstevel@tonic-gate 		kmem_free(objp->who.utf8string_val, objp->who.utf8string_len);
6907c478bd9Sstevel@tonic-gate 		objp->who.utf8string_val = NULL;
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 	return (TRUE);
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate /*
6967c478bd9Sstevel@tonic-gate  * These functions are called out of nfs4_attr.c
6977c478bd9Sstevel@tonic-gate  */
6987c478bd9Sstevel@tonic-gate bool_t
xdr_fattr4_fsid(XDR * xdrs,fattr4_fsid * objp)6997c478bd9Sstevel@tonic-gate xdr_fattr4_fsid(XDR *xdrs, fattr4_fsid *objp)
7007c478bd9Sstevel@tonic-gate {
7017c478bd9Sstevel@tonic-gate 	if (xdrs->x_op == XDR_FREE)
7027c478bd9Sstevel@tonic-gate 		return (TRUE);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	if (!xdr_u_longlong_t(xdrs, (u_longlong_t *)&objp->major))
7057c478bd9Sstevel@tonic-gate 		return (FALSE);
7067c478bd9Sstevel@tonic-gate 	return (xdr_u_longlong_t(xdrs, (u_longlong_t *)&objp->minor));
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate bool_t
xdr_fattr4_acl(XDR * xdrs,fattr4_acl * objp)7117c478bd9Sstevel@tonic-gate xdr_fattr4_acl(XDR *xdrs, fattr4_acl *objp)
7127c478bd9Sstevel@tonic-gate {
7137c478bd9Sstevel@tonic-gate 	return (xdr_array(xdrs, (char **)&objp->fattr4_acl_val,
7140a701b1eSRobert Gordon 	    (uint_t *)&objp->fattr4_acl_len, NFS4_ACL_LIMIT,
7150a701b1eSRobert Gordon 	    sizeof (nfsace4), (xdrproc_t)xdr_nfsace4));
7167c478bd9Sstevel@tonic-gate }
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate bool_t
xdr_fattr4_fs_locations(XDR * xdrs,fattr4_fs_locations * objp)7197c478bd9Sstevel@tonic-gate xdr_fattr4_fs_locations(XDR *xdrs, fattr4_fs_locations *objp)
7207c478bd9Sstevel@tonic-gate {
7212f172c55SRobert Thurlow 	if (xdrs->x_op == XDR_DECODE) {
7222f172c55SRobert Thurlow 		objp->fs_root.pathname4_len = 0;
7232f172c55SRobert Thurlow 		objp->fs_root.pathname4_val = NULL;
7242f172c55SRobert Thurlow 		objp->locations_val = NULL;
7252f172c55SRobert Thurlow 	}
7267c478bd9Sstevel@tonic-gate 	if (!xdr_array(xdrs, (char **)&objp->fs_root.pathname4_val,
7270a701b1eSRobert Gordon 	    (uint_t *)&objp->fs_root.pathname4_len,
7280a701b1eSRobert Gordon 	    NFS4_MAX_PATHNAME4,
7290a701b1eSRobert Gordon 	    sizeof (utf8string), (xdrproc_t)xdr_utf8string))
7307c478bd9Sstevel@tonic-gate 		return (FALSE);
7317c478bd9Sstevel@tonic-gate 	return (xdr_array(xdrs, (char **)&objp->locations_val,
7320a701b1eSRobert Gordon 	    (uint_t *)&objp->locations_len, NFS4_FS_LOCATIONS_LIMIT,
7330a701b1eSRobert Gordon 	    sizeof (fs_location4), (xdrproc_t)xdr_fs_location4));
7347c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate bool_t
xdr_fattr4_rawdev(XDR * xdrs,fattr4_rawdev * objp)7377c478bd9Sstevel@tonic-gate xdr_fattr4_rawdev(XDR *xdrs, fattr4_rawdev *objp)
7387c478bd9Sstevel@tonic-gate {
7397c478bd9Sstevel@tonic-gate 	if (xdrs->x_op == XDR_FREE)
7407c478bd9Sstevel@tonic-gate 		return (TRUE);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	if (!xdr_u_int(xdrs, &objp->specdata1))
7437c478bd9Sstevel@tonic-gate 		return (FALSE);
7447c478bd9Sstevel@tonic-gate 	return (xdr_u_int(xdrs, &objp->specdata2));
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate bool_t
xdr_nfstime4(XDR * xdrs,nfstime4 * objp)7487c478bd9Sstevel@tonic-gate xdr_nfstime4(XDR *xdrs, nfstime4 *objp)
7497c478bd9Sstevel@tonic-gate {
7507c478bd9Sstevel@tonic-gate 	if (xdrs->x_op == XDR_FREE)
7517c478bd9Sstevel@tonic-gate 		return (TRUE);
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	if (!xdr_longlong_t(xdrs, (longlong_t *)&objp->seconds))
7547c478bd9Sstevel@tonic-gate 		return (FALSE);
7557c478bd9Sstevel@tonic-gate 	return (xdr_u_int(xdrs, &objp->nseconds));
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate /*
7607c478bd9Sstevel@tonic-gate  * structured used for calls into xdr_ga_fattr_res() as a means
7617c478bd9Sstevel@tonic-gate  * to do an immediate/short-term cache of owner/group strings
7627c478bd9Sstevel@tonic-gate  * for callers like the readdir processing.  In the case of readdir,
7637c478bd9Sstevel@tonic-gate  * it is likely that the directory objects will be owned by the same
7647c478bd9Sstevel@tonic-gate  * owner/group and if so there is no need to call into the uid/gid
7657c478bd9Sstevel@tonic-gate  * mapping code.  While the uid/gid interfaces have their own cache
7667c478bd9Sstevel@tonic-gate  * having one here will reduct pathlength further.
7677c478bd9Sstevel@tonic-gate  */
7687c478bd9Sstevel@tonic-gate #define	MAX_OG_NAME 100
7697c478bd9Sstevel@tonic-gate typedef struct ug_cache
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate 	uid_t	uid;
7727c478bd9Sstevel@tonic-gate 	gid_t	gid;
7737c478bd9Sstevel@tonic-gate 	utf8string u_curr, u_last;
7747c478bd9Sstevel@tonic-gate 	utf8string g_curr, g_last;
7757c478bd9Sstevel@tonic-gate 	char	u_buf1[MAX_OG_NAME];
7767c478bd9Sstevel@tonic-gate 	char	u_buf2[MAX_OG_NAME];
7777c478bd9Sstevel@tonic-gate 	char	g_buf1[MAX_OG_NAME];
7787c478bd9Sstevel@tonic-gate 	char	g_buf2[MAX_OG_NAME];
7797c478bd9Sstevel@tonic-gate } ug_cache_t;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate #define	U_SWAP_CURR_LAST(ug) \
7827c478bd9Sstevel@tonic-gate 	(ug)->u_last.utf8string_len = (ug)->u_curr.utf8string_len;	\
7837c478bd9Sstevel@tonic-gate 	if ((ug)->u_last.utf8string_val == (ug)->u_buf1) {		\
7847c478bd9Sstevel@tonic-gate 		(ug)->u_last.utf8string_val = (ug)->u_buf2;		\
7857c478bd9Sstevel@tonic-gate 		(ug)->u_curr.utf8string_val = (ug)->u_buf1;		\
7867c478bd9Sstevel@tonic-gate 	} else {							\
7877c478bd9Sstevel@tonic-gate 		(ug)->u_last.utf8string_val = (ug)->u_buf1;		\
7887c478bd9Sstevel@tonic-gate 		(ug)->u_curr.utf8string_val = (ug)->u_buf2;		\
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate #define	G_SWAP_CURR_LAST(ug) \
7927c478bd9Sstevel@tonic-gate 	(ug)->g_last.utf8string_len = (ug)->g_curr.utf8string_len;	\
7937c478bd9Sstevel@tonic-gate 	if ((ug)->g_last.utf8string_val == (ug)->g_buf1) {		\
7947c478bd9Sstevel@tonic-gate 		(ug)->g_last.utf8string_val = (ug)->g_buf2;		\
7957c478bd9Sstevel@tonic-gate 		(ug)->g_curr.utf8string_val = (ug)->g_buf1;		\
7967c478bd9Sstevel@tonic-gate 	} else {							\
7977c478bd9Sstevel@tonic-gate 		(ug)->g_last.utf8string_val = (ug)->g_buf1;		\
7987c478bd9Sstevel@tonic-gate 		(ug)->g_curr.utf8string_val = (ug)->g_buf2;		\
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate static ug_cache_t *
alloc_ugcache()8027c478bd9Sstevel@tonic-gate alloc_ugcache()
8037c478bd9Sstevel@tonic-gate {
8047c478bd9Sstevel@tonic-gate 	ug_cache_t *pug = kmem_alloc(sizeof (ug_cache_t), KM_SLEEP);
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	pug->uid = pug->gid = 0;
8077c478bd9Sstevel@tonic-gate 	pug->u_curr.utf8string_len = 0;
8087c478bd9Sstevel@tonic-gate 	pug->u_last.utf8string_len = 0;
8097c478bd9Sstevel@tonic-gate 	pug->g_curr.utf8string_len = 0;
8107c478bd9Sstevel@tonic-gate 	pug->g_last.utf8string_len = 0;
8117c478bd9Sstevel@tonic-gate 	pug->u_curr.utf8string_val = pug->u_buf1;
8127c478bd9Sstevel@tonic-gate 	pug->u_last.utf8string_val = pug->u_buf2;
8137c478bd9Sstevel@tonic-gate 	pug->g_curr.utf8string_val = pug->g_buf1;
8147c478bd9Sstevel@tonic-gate 	pug->g_last.utf8string_val = pug->g_buf2;
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	return (pug);
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate static void
xdr_ga_prefill_vattr(struct nfs4_ga_res * garp,struct mntinfo4 * mi)8207c478bd9Sstevel@tonic-gate xdr_ga_prefill_vattr(struct nfs4_ga_res *garp, struct mntinfo4 *mi)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate 	static vattr_t s_vattr = {
8237c478bd9Sstevel@tonic-gate 		AT_ALL,		/* va_mask */
8247c478bd9Sstevel@tonic-gate 		VNON,		/* va_type */
8257c478bd9Sstevel@tonic-gate 		0777,		/* va_mode */
8267c478bd9Sstevel@tonic-gate 		UID_NOBODY,	/* va_uid */
8277c478bd9Sstevel@tonic-gate 		GID_NOBODY,	/* va_gid */
8287c478bd9Sstevel@tonic-gate 		0,		/* va_fsid */
8297c478bd9Sstevel@tonic-gate 		0,		/* va_nodeid */
8307c478bd9Sstevel@tonic-gate 		1,		/* va_nlink */
8317c478bd9Sstevel@tonic-gate 		0,		/* va_size */
8327c478bd9Sstevel@tonic-gate 		{0, 0},		/* va_atime */
8337c478bd9Sstevel@tonic-gate 		{0, 0},		/* va_mtime */
8347c478bd9Sstevel@tonic-gate 		{0, 0},		/* va_ctime */
8357c478bd9Sstevel@tonic-gate 		0,		/* va_rdev */
8367c478bd9Sstevel@tonic-gate 		MAXBSIZE,	/* va_blksize */
8377c478bd9Sstevel@tonic-gate 		0,		/* va_nblocks */
8387c478bd9Sstevel@tonic-gate 		0		/* va_seq */
8397c478bd9Sstevel@tonic-gate 	};
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	garp->n4g_va = s_vattr;
8437c478bd9Sstevel@tonic-gate 	garp->n4g_va.va_fsid = mi->mi_vfsp->vfs_dev;
8447c478bd9Sstevel@tonic-gate 	hrt2ts(gethrtime(), &garp->n4g_va.va_atime);
8457c478bd9Sstevel@tonic-gate 	garp->n4g_va.va_mtime = garp->n4g_va.va_ctime = garp->n4g_va.va_atime;
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate static void
xdr_ga_prefill_statvfs(struct nfs4_ga_ext_res * gesp,struct mntinfo4 * mi)8497c478bd9Sstevel@tonic-gate xdr_ga_prefill_statvfs(struct nfs4_ga_ext_res *gesp, struct mntinfo4 *mi)
8507c478bd9Sstevel@tonic-gate {
8517c478bd9Sstevel@tonic-gate 	static statvfs64_t s_sb = {
8527c478bd9Sstevel@tonic-gate 		MAXBSIZE,	/* f_bsize */
8537c478bd9Sstevel@tonic-gate 		DEV_BSIZE,	/* f_frsize */
8547c478bd9Sstevel@tonic-gate 		(fsfilcnt64_t)-1, /* f_blocks */
8557c478bd9Sstevel@tonic-gate 		(fsfilcnt64_t)-1, /* f_bfree */
8567c478bd9Sstevel@tonic-gate 		(fsfilcnt64_t)-1, /* f_bavail */
8577c478bd9Sstevel@tonic-gate 		(fsfilcnt64_t)-1, /* f_files */
8587c478bd9Sstevel@tonic-gate 		(fsfilcnt64_t)-1, /* f_ffree */
8597c478bd9Sstevel@tonic-gate 		(fsfilcnt64_t)-1, /* f_favail */
8607c478bd9Sstevel@tonic-gate 		0,		/* f_fsid */
8617c478bd9Sstevel@tonic-gate 		"\0",		/* f_basetype */
8627c478bd9Sstevel@tonic-gate 		0,		/* f_flag */
8637c478bd9Sstevel@tonic-gate 		MAXNAMELEN,	/* f_namemax */
8647c478bd9Sstevel@tonic-gate 		"\0",		/* f_fstr */
8657c478bd9Sstevel@tonic-gate 	};
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	gesp->n4g_sb = s_sb;
8687c478bd9Sstevel@tonic-gate 	gesp->n4g_sb.f_fsid = mi->mi_vfsp->vfs_fsid.val[0];
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate static bool_t
xdr_ga_fattr_res(XDR * xdrs,struct nfs4_ga_res * garp,bitmap4 resbmap,bitmap4 argbmap,struct mntinfo4 * mi,ug_cache_t * pug)8727c478bd9Sstevel@tonic-gate xdr_ga_fattr_res(XDR *xdrs, struct nfs4_ga_res *garp, bitmap4 resbmap,
8735dde82e7SMarcel Telka     bitmap4 argbmap, struct mntinfo4 *mi, ug_cache_t *pug)
8747c478bd9Sstevel@tonic-gate {
8757c478bd9Sstevel@tonic-gate 	int truefalse;
8767c478bd9Sstevel@tonic-gate 	struct nfs4_ga_ext_res ges, *gesp;
8777c478bd9Sstevel@tonic-gate 	vattr_t *vap = &garp->n4g_va;
8787c478bd9Sstevel@tonic-gate 	vsecattr_t *vsap = &garp->n4g_vsa;
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	ASSERT(xdrs->x_op == XDR_DECODE);
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (garp->n4g_ext_res)
8837c478bd9Sstevel@tonic-gate 		gesp = garp->n4g_ext_res;
8847c478bd9Sstevel@tonic-gate 	else
8857c478bd9Sstevel@tonic-gate 		gesp = &ges;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	vap->va_mask = 0;
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	/* Check to see if the vattr should be pre-filled */
8907c478bd9Sstevel@tonic-gate 	if (argbmap & NFS4_VATTR_MASK)
8917c478bd9Sstevel@tonic-gate 		xdr_ga_prefill_vattr(garp, mi);
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	if (argbmap & NFS4_STATFS_ATTR_MASK)
8947c478bd9Sstevel@tonic-gate 		xdr_ga_prefill_statvfs(gesp, mi);
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	if (resbmap &
8977c478bd9Sstevel@tonic-gate 	    (FATTR4_SUPPORTED_ATTRS_MASK |
8987c478bd9Sstevel@tonic-gate 	    FATTR4_TYPE_MASK |
8997c478bd9Sstevel@tonic-gate 	    FATTR4_FH_EXPIRE_TYPE_MASK |
9007c478bd9Sstevel@tonic-gate 	    FATTR4_CHANGE_MASK |
9017c478bd9Sstevel@tonic-gate 	    FATTR4_SIZE_MASK |
9027c478bd9Sstevel@tonic-gate 	    FATTR4_LINK_SUPPORT_MASK |
9037c478bd9Sstevel@tonic-gate 	    FATTR4_SYMLINK_SUPPORT_MASK |
9047c478bd9Sstevel@tonic-gate 	    FATTR4_NAMED_ATTR_MASK)) {
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 		if (resbmap & FATTR4_SUPPORTED_ATTRS_MASK) {
9077c478bd9Sstevel@tonic-gate 			if (!xdr_bitmap4(xdrs, &gesp->n4g_suppattrs))
9087c478bd9Sstevel@tonic-gate 				return (FALSE);
9097c478bd9Sstevel@tonic-gate 		}
9107c478bd9Sstevel@tonic-gate 		if (resbmap & FATTR4_TYPE_MASK) {
9117c478bd9Sstevel@tonic-gate 			if (!XDR_GETINT32(xdrs, (int *)&vap->va_type))
9127c478bd9Sstevel@tonic-gate 				return (FALSE);
9137c478bd9Sstevel@tonic-gate 
9142c2d21e9SRichard Lowe 			if ((nfs_ftype4)vap->va_type < NF4REG ||
9152c2d21e9SRichard Lowe 			    (nfs_ftype4)vap->va_type > NF4NAMEDATTR)
9167c478bd9Sstevel@tonic-gate 				vap->va_type = VBAD;
9177c478bd9Sstevel@tonic-gate 			else
9187c478bd9Sstevel@tonic-gate 				vap->va_type = nf4_to_vt[vap->va_type];
9197c478bd9Sstevel@tonic-gate 			if (vap->va_type == VBLK)
9207c478bd9Sstevel@tonic-gate 				vap->va_blksize = DEV_BSIZE;
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 			vap->va_mask |= AT_TYPE;
9237c478bd9Sstevel@tonic-gate 		}
9247c478bd9Sstevel@tonic-gate 		if (resbmap & FATTR4_FH_EXPIRE_TYPE_MASK) {
9257c478bd9Sstevel@tonic-gate 			if (!XDR_GETINT32(xdrs, (int *)&gesp->n4g_fet))
9267c478bd9Sstevel@tonic-gate 				return (FALSE);
9277c478bd9Sstevel@tonic-gate 		}
9287c478bd9Sstevel@tonic-gate 		if (resbmap & FATTR4_CHANGE_MASK) {
9297c478bd9Sstevel@tonic-gate 			if (!xdr_u_longlong_t(xdrs,
9300a701b1eSRobert Gordon 			    (u_longlong_t *)&garp->n4g_change))
9317c478bd9Sstevel@tonic-gate 				return (FALSE);
9327c478bd9Sstevel@tonic-gate 			garp->n4g_change_valid = 1;
9337c478bd9Sstevel@tonic-gate 		}
9347c478bd9Sstevel@tonic-gate 		if (resbmap & FATTR4_SIZE_MASK) {
9357c478bd9Sstevel@tonic-gate 			if (!xdr_u_longlong_t(xdrs,
9360a701b1eSRobert Gordon 			    (u_longlong_t *)&vap->va_size))
9377c478bd9Sstevel@tonic-gate 				return (FALSE);
9387c478bd9Sstevel@tonic-gate 			if (!NFS4_SIZE_OK(vap->va_size)) {
9397c478bd9Sstevel@tonic-gate 				garp->n4g_attrerr = EFBIG;
9407c478bd9Sstevel@tonic-gate 				garp->n4g_attrwhy = NFS4_GETATTR_ATSIZE_ERR;
9417c478bd9Sstevel@tonic-gate 			} else {
9427c478bd9Sstevel@tonic-gate 				vap->va_mask |= AT_SIZE;
9437c478bd9Sstevel@tonic-gate 			}
9447c478bd9Sstevel@tonic-gate 		}
9457c478bd9Sstevel@tonic-gate 		if (resbmap & FATTR4_LINK_SUPPORT_MASK) {
9467c478bd9Sstevel@tonic-gate 			if (!XDR_GETINT32(xdrs, (int *)&truefalse))
9477c478bd9Sstevel@tonic-gate 				return (FALSE);
9487c478bd9Sstevel@tonic-gate 			gesp->n4g_pc4.pc4_link_support =
9490a701b1eSRobert Gordon 			    (truefalse ? TRUE : FALSE);
9507c478bd9Sstevel@tonic-gate 		}
9517c478bd9Sstevel@tonic-gate 		if (resbmap & FATTR4_SYMLINK_SUPPORT_MASK) {
9527c478bd9Sstevel@tonic-gate 			if (!XDR_GETINT32(xdrs, (int *)&truefalse))
9537c478bd9Sstevel@tonic-gate 				return (FALSE);
9547c478bd9Sstevel@tonic-gate 			gesp->n4g_pc4.pc4_symlink_support =
9550a701b1eSRobert Gordon 			    (truefalse ? TRUE : FALSE);
9567c478bd9Sstevel@tonic-gate 		}
9577c478bd9Sstevel@tonic-gate 		if (resbmap & FATTR4_NAMED_ATTR_MASK) {
9587c478bd9Sstevel@tonic-gate 			if (!XDR_GETINT32(xdrs, (int *)&truefalse))
9597c478bd9Sstevel@tonic-gate 				return (FALSE);
9607c478bd9Sstevel@tonic-gate 			gesp->n4g_pc4.pc4_xattr_exists = TRUE;
9617c478bd9Sstevel@tonic-gate 			gesp->n4g_pc4.pc4_xattr_exists =
9620a701b1eSRobert Gordon 			    (truefalse ? TRUE : FALSE);
9637c478bd9Sstevel@tonic-gate 		}
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 	if (resbmap &
9667c478bd9Sstevel@tonic-gate 	    (FATTR4_FSID_MASK |
9677c478bd9Sstevel@tonic-gate 	    FATTR4_UNIQUE_HANDLES_MASK |
9687c478bd9Sstevel@tonic-gate 	    FATTR4_LEASE_TIME_MASK |
9697c478bd9Sstevel@tonic-gate 	    FATTR4_RDATTR_ERROR_MASK)) {
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 		if (resbmap & FATTR4_FSID_MASK) {
9720a701b1eSRobert Gordon 			if ((!xdr_u_longlong_t(xdrs,
9730a701b1eSRobert Gordon 			    (u_longlong_t *)&garp->n4g_fsid.major)) ||
9740a701b1eSRobert Gordon 			    (!xdr_u_longlong_t(xdrs,
9750a701b1eSRobert Gordon 			    (u_longlong_t *)&garp->n4g_fsid.minor)))
9767c478bd9Sstevel@tonic-gate 				return (FALSE);
9770a701b1eSRobert Gordon 			garp->n4g_fsid_valid = 1;
9787c478bd9Sstevel@tonic-gate 		}
9797c478bd9