Home | History | Annotate | Line # | Download | only in common
nfs_commonsubs.c revision 1.1.1.1.12.1
      1 /*	$NetBSD: nfs_commonsubs.c,v 1.1.1.1.12.1 2016/12/05 10:55:25 skrll Exp $	*/
      2 /*-
      3  * Copyright (c) 1989, 1993
      4  *	The Regents of the University of California.  All rights reserved.
      5  *
      6  * This code is derived from software contributed to Berkeley by
      7  * Rick Macklem at The University of Guelph.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  *
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 /* __FBSDID("FreeBSD: head/sys/fs/nfs/nfs_commonsubs.c 308708 2016-11-16 01:11:49Z cperciva "); */
     37 __RCSID("$NetBSD: nfs_commonsubs.c,v 1.1.1.1.12.1 2016/12/05 10:55:25 skrll Exp $");
     38 
     39 /*
     40  * These functions support the macros and help fiddle mbuf chains for
     41  * the nfs op functions. They do things like create the rpc header and
     42  * copy data between mbuf chains and uio lists.
     43  */
     44 #ifndef APPLEKEXT
     45 #include "opt_inet6.h"
     46 
     47 #include <fs/nfs/nfsport.h>
     48 
     49 #include <security/mac/mac_framework.h>
     50 
     51 /*
     52  * Data items converted to xdr at startup, since they are constant
     53  * This is kinda hokey, but may save a little time doing byte swaps
     54  */
     55 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
     56 
     57 /* And other global data */
     58 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
     59 		      NFFIFO, NFNON };
     60 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
     61 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
     62 struct timeval nfsboottime;	/* Copy boottime once, so it never changes */
     63 int nfscl_ticks;
     64 int nfsrv_useacl = 1;
     65 struct nfssockreq nfsrv_nfsuserdsock;
     66 int nfsrv_nfsuserd = 0;
     67 struct nfsreqhead nfsd_reqq;
     68 uid_t nfsrv_defaultuid;
     69 gid_t nfsrv_defaultgid;
     70 int nfsrv_lease = NFSRV_LEASE;
     71 int ncl_mbuf_mlen = MLEN;
     72 int nfsd_enable_stringtouid = 0;
     73 NFSNAMEIDMUTEX;
     74 NFSSOCKMUTEX;
     75 extern int nfsrv_lughashsize;
     76 
     77 /*
     78  * This array of structures indicates, for V4:
     79  * retfh - which of 3 types of calling args are used
     80  *	0 - doesn't change cfh or use a sfh
     81  *	1 - replaces cfh with a new one (unless it returns an error status)
     82  *	2 - uses cfh and sfh
     83  * needscfh - if the op wants a cfh and premtime
     84  *	0 - doesn't use a cfh
     85  *	1 - uses a cfh, but doesn't want pre-op attributes
     86  *	2 - uses a cfh and wants pre-op attributes
     87  * savereply - indicates a non-idempotent Op
     88  *	0 - not non-idempotent
     89  *	1 - non-idempotent
     90  * Ops that are ordered via seqid# are handled separately from these
     91  * non-idempotent Ops.
     92  * Define it here, since it is used by both the client and server.
     93  */
     94 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
     95 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* undef */
     96 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* undef */
     97 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* undef */
     98 	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* Access */
     99 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Close */
    100 	{ 0, 2, 0, 1, LK_EXCLUSIVE, 1 },		/* Commit */
    101 	{ 1, 2, 1, 1, LK_EXCLUSIVE, 1 },		/* Create */
    102 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Delegpurge */
    103 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Delegreturn */
    104 	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* Getattr */
    105 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* GetFH */
    106 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1 },		/* Link */
    107 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Lock */
    108 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* LockT */
    109 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* LockU */
    110 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1 },		/* Lookup */
    111 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1 },		/* Lookupp */
    112 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* NVerify */
    113 	{ 1, 1, 0, 1, LK_EXCLUSIVE, 1 },		/* Open */
    114 	{ 1, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* OpenAttr */
    115 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* OpenConfirm */
    116 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* OpenDowngrade */
    117 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* PutFH */
    118 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* PutPubFH */
    119 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* PutRootFH */
    120 	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* Read */
    121 	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* Readdir */
    122 	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* ReadLink */
    123 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1 },		/* Remove */
    124 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1 },		/* Rename */
    125 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Renew */
    126 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* RestoreFH */
    127 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* SaveFH */
    128 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* SecInfo */
    129 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1 },		/* Setattr */
    130 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* SetClientID */
    131 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* SetClientIDConfirm */
    132 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Verify */
    133 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1 },		/* Write */
    134 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* ReleaseLockOwner */
    135 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Backchannel Ctrl */
    136 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Bind Conn to Sess */
    137 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0 },		/* Exchange ID */
    138 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0 },		/* Create Session */
    139 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0 },		/* Destroy Session */
    140 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Free StateID */
    141 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Get Dir Deleg */
    142 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Get Device Info */
    143 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Get Device List */
    144 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Layout Commit */
    145 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Layout Get */
    146 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Layout Return */
    147 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Secinfo No name */
    148 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Sequence */
    149 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Set SSV */
    150 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Test StateID */
    151 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Want Delegation */
    152 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0 },		/* Destroy ClientID */
    153 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Reclaim Complete */
    154 };
    155 #endif	/* !APPLEKEXT */
    156 
    157 static int ncl_mbuf_mhlen = MHLEN;
    158 static int nfsrv_usercnt = 0;
    159 static int nfsrv_dnsnamelen;
    160 static u_char *nfsrv_dnsname = NULL;
    161 static int nfsrv_usermax = 999999999;
    162 struct nfsrv_lughash {
    163 	struct mtx		mtx;
    164 	struct nfsuserhashhead	lughead;
    165 };
    166 static struct nfsrv_lughash	*nfsuserhash;
    167 static struct nfsrv_lughash	*nfsusernamehash;
    168 static struct nfsrv_lughash	*nfsgrouphash;
    169 static struct nfsrv_lughash	*nfsgroupnamehash;
    170 
    171 /*
    172  * This static array indicates whether or not the RPC generates a large
    173  * reply. This is used by nfs_reply() to decide whether or not an mbuf
    174  * cluster should be allocated. (If a cluster is required by an RPC
    175  * marked 0 in this array, the code will still work, just not quite as
    176  * efficiently.)
    177  */
    178 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
    179     0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    180     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
    181 
    182 /* local functions */
    183 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
    184 static void nfsv4_wanted(struct nfsv4lock *lp);
    185 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
    186 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
    187     NFSPROC_T *p);
    188 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
    189 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
    190     int *, int *);
    191 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
    192 
    193 
    194 #ifndef APPLE
    195 /*
    196  * copies mbuf chain to the uio scatter/gather list
    197  */
    198 int
    199 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
    200 {
    201 	char *mbufcp, *uiocp;
    202 	int xfer, left, len;
    203 	mbuf_t mp;
    204 	long uiosiz, rem;
    205 	int error = 0;
    206 
    207 	mp = nd->nd_md;
    208 	mbufcp = nd->nd_dpos;
    209 	len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
    210 	rem = NFSM_RNDUP(siz) - siz;
    211 	while (siz > 0) {
    212 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
    213 			error = EBADRPC;
    214 			goto out;
    215 		}
    216 		left = uiop->uio_iov->iov_len;
    217 		uiocp = uiop->uio_iov->iov_base;
    218 		if (left > siz)
    219 			left = siz;
    220 		uiosiz = left;
    221 		while (left > 0) {
    222 			while (len == 0) {
    223 				mp = mbuf_next(mp);
    224 				if (mp == NULL) {
    225 					error = EBADRPC;
    226 					goto out;
    227 				}
    228 				mbufcp = NFSMTOD(mp, caddr_t);
    229 				len = mbuf_len(mp);
    230 				KASSERT(len >= 0,
    231 				    ("len %d, corrupted mbuf?", len));
    232 			}
    233 			xfer = (left > len) ? len : left;
    234 #ifdef notdef
    235 			/* Not Yet.. */
    236 			if (uiop->uio_iov->iov_op != NULL)
    237 				(*(uiop->uio_iov->iov_op))
    238 				(mbufcp, uiocp, xfer);
    239 			else
    240 #endif
    241 			if (uiop->uio_segflg == UIO_SYSSPACE)
    242 				NFSBCOPY(mbufcp, uiocp, xfer);
    243 			else
    244 				copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
    245 			left -= xfer;
    246 			len -= xfer;
    247 			mbufcp += xfer;
    248 			uiocp += xfer;
    249 			uiop->uio_offset += xfer;
    250 			uiop->uio_resid -= xfer;
    251 		}
    252 		if (uiop->uio_iov->iov_len <= siz) {
    253 			uiop->uio_iovcnt--;
    254 			uiop->uio_iov++;
    255 		} else {
    256 			uiop->uio_iov->iov_base = (void *)
    257 				((char *)uiop->uio_iov->iov_base + uiosiz);
    258 			uiop->uio_iov->iov_len -= uiosiz;
    259 		}
    260 		siz -= uiosiz;
    261 	}
    262 	nd->nd_dpos = mbufcp;
    263 	nd->nd_md = mp;
    264 	if (rem > 0) {
    265 		if (len < rem)
    266 			error = nfsm_advance(nd, rem, len);
    267 		else
    268 			nd->nd_dpos += rem;
    269 	}
    270 
    271 out:
    272 	NFSEXITCODE2(error, nd);
    273 	return (error);
    274 }
    275 #endif	/* !APPLE */
    276 
    277 /*
    278  * Help break down an mbuf chain by setting the first siz bytes contiguous
    279  * pointed to by returned val.
    280  * This is used by the macro NFSM_DISSECT for tough
    281  * cases.
    282  */
    283 APPLESTATIC void *
    284 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
    285 {
    286 	mbuf_t mp2;
    287 	int siz2, xfer;
    288 	caddr_t p;
    289 	int left;
    290 	caddr_t retp;
    291 
    292 	retp = NULL;
    293 	left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
    294 	while (left == 0) {
    295 		nd->nd_md = mbuf_next(nd->nd_md);
    296 		if (nd->nd_md == NULL)
    297 			return (retp);
    298 		left = mbuf_len(nd->nd_md);
    299 		nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
    300 	}
    301 	if (left >= siz) {
    302 		retp = nd->nd_dpos;
    303 		nd->nd_dpos += siz;
    304 	} else if (mbuf_next(nd->nd_md) == NULL) {
    305 		return (retp);
    306 	} else if (siz > ncl_mbuf_mhlen) {
    307 		panic("nfs S too big");
    308 	} else {
    309 		MGET(mp2, MT_DATA, how);
    310 		if (mp2 == NULL)
    311 			return (NULL);
    312 		mbuf_setnext(mp2, mbuf_next(nd->nd_md));
    313 		mbuf_setnext(nd->nd_md, mp2);
    314 		mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
    315 		nd->nd_md = mp2;
    316 		retp = p = NFSMTOD(mp2, caddr_t);
    317 		NFSBCOPY(nd->nd_dpos, p, left);	/* Copy what was left */
    318 		siz2 = siz - left;
    319 		p += left;
    320 		mp2 = mbuf_next(mp2);
    321 		/* Loop around copying up the siz2 bytes */
    322 		while (siz2 > 0) {
    323 			if (mp2 == NULL)
    324 				return (NULL);
    325 			xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
    326 			if (xfer > 0) {
    327 				NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
    328 				NFSM_DATAP(mp2, xfer);
    329 				mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
    330 				p += xfer;
    331 				siz2 -= xfer;
    332 			}
    333 			if (siz2 > 0)
    334 				mp2 = mbuf_next(mp2);
    335 		}
    336 		mbuf_setlen(nd->nd_md, siz);
    337 		nd->nd_md = mp2;
    338 		nd->nd_dpos = NFSMTOD(mp2, caddr_t);
    339 	}
    340 	return (retp);
    341 }
    342 
    343 /*
    344  * Advance the position in the mbuf chain.
    345  * If offs == 0, this is a no-op, but it is simpler to just return from
    346  * here than check for offs > 0 for all calls to nfsm_advance.
    347  * If left == -1, it should be calculated here.
    348  */
    349 APPLESTATIC int
    350 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
    351 {
    352 	int error = 0;
    353 
    354 	if (offs == 0)
    355 		goto out;
    356 	/*
    357 	 * A negative offs should be considered a serious problem.
    358 	 */
    359 	if (offs < 0)
    360 		panic("nfsrv_advance");
    361 
    362 	/*
    363 	 * If left == -1, calculate it here.
    364 	 */
    365 	if (left == -1)
    366 		left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
    367 		    nd->nd_dpos;
    368 
    369 	/*
    370 	 * Loop around, advancing over the mbuf data.
    371 	 */
    372 	while (offs > left) {
    373 		offs -= left;
    374 		nd->nd_md = mbuf_next(nd->nd_md);
    375 		if (nd->nd_md == NULL) {
    376 			error = EBADRPC;
    377 			goto out;
    378 		}
    379 		left = mbuf_len(nd->nd_md);
    380 		nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
    381 	}
    382 	nd->nd_dpos += offs;
    383 
    384 out:
    385 	NFSEXITCODE(error);
    386 	return (error);
    387 }
    388 
    389 /*
    390  * Copy a string into mbuf(s).
    391  * Return the number of bytes output, including XDR overheads.
    392  */
    393 APPLESTATIC int
    394 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
    395 {
    396 	mbuf_t m2;
    397 	int xfer, left;
    398 	mbuf_t m1;
    399 	int rem, bytesize;
    400 	u_int32_t *tl;
    401 	char *cp2;
    402 
    403 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    404 	*tl = txdr_unsigned(siz);
    405 	rem = NFSM_RNDUP(siz) - siz;
    406 	bytesize = NFSX_UNSIGNED + siz + rem;
    407 	m2 = nd->nd_mb;
    408 	cp2 = nd->nd_bpos;
    409 	left = M_TRAILINGSPACE(m2);
    410 
    411 	/*
    412 	 * Loop around copying the string to mbuf(s).
    413 	 */
    414 	while (siz > 0) {
    415 		if (left == 0) {
    416 			if (siz > ncl_mbuf_mlen)
    417 				NFSMCLGET(m1, M_WAITOK);
    418 			else
    419 				NFSMGET(m1);
    420 			mbuf_setlen(m1, 0);
    421 			mbuf_setnext(m2, m1);
    422 			m2 = m1;
    423 			cp2 = NFSMTOD(m2, caddr_t);
    424 			left = M_TRAILINGSPACE(m2);
    425 		}
    426 		if (left >= siz)
    427 			xfer = siz;
    428 		else
    429 			xfer = left;
    430 		NFSBCOPY(cp, cp2, xfer);
    431 		cp += xfer;
    432 		mbuf_setlen(m2, mbuf_len(m2) + xfer);
    433 		siz -= xfer;
    434 		left -= xfer;
    435 		if (siz == 0 && rem) {
    436 			if (left < rem)
    437 				panic("nfsm_strtom");
    438 			NFSBZERO(cp2 + xfer, rem);
    439 			mbuf_setlen(m2, mbuf_len(m2) + rem);
    440 		}
    441 	}
    442 	nd->nd_mb = m2;
    443 	nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
    444 	return (bytesize);
    445 }
    446 
    447 /*
    448  * Called once to initialize data structures...
    449  */
    450 APPLESTATIC void
    451 newnfs_init(void)
    452 {
    453 	static int nfs_inited = 0;
    454 
    455 	if (nfs_inited)
    456 		return;
    457 	nfs_inited = 1;
    458 
    459 	newnfs_true = txdr_unsigned(TRUE);
    460 	newnfs_false = txdr_unsigned(FALSE);
    461 	newnfs_xdrneg1 = txdr_unsigned(-1);
    462 	nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
    463 	if (nfscl_ticks < 1)
    464 		nfscl_ticks = 1;
    465 	NFSSETBOOTTIME(nfsboottime);
    466 
    467 	/*
    468 	 * Initialize reply list and start timer
    469 	 */
    470 	TAILQ_INIT(&nfsd_reqq);
    471 	NFS_TIMERINIT;
    472 }
    473 
    474 /*
    475  * Put a file handle in an mbuf list.
    476  * If the size argument == 0, just use the default size.
    477  * set_true == 1 if there should be an newnfs_true prepended on the file handle.
    478  * Return the number of bytes output, including XDR overhead.
    479  */
    480 APPLESTATIC int
    481 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
    482 {
    483 	u_int32_t *tl;
    484 	u_int8_t *cp;
    485 	int fullsiz, rem, bytesize = 0;
    486 
    487 	if (size == 0)
    488 		size = NFSX_MYFH;
    489 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
    490 	case ND_NFSV2:
    491 		if (size > NFSX_V2FH)
    492 			panic("fh size > NFSX_V2FH for NFSv2");
    493 		NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
    494 		NFSBCOPY(fhp, cp, size);
    495 		if (size < NFSX_V2FH)
    496 			NFSBZERO(cp + size, NFSX_V2FH - size);
    497 		bytesize = NFSX_V2FH;
    498 		break;
    499 	case ND_NFSV3:
    500 	case ND_NFSV4:
    501 		fullsiz = NFSM_RNDUP(size);
    502 		rem = fullsiz - size;
    503 		if (set_true) {
    504 		    bytesize = 2 * NFSX_UNSIGNED + fullsiz;
    505 		    NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    506 		    *tl = newnfs_true;
    507 		} else {
    508 		    bytesize = NFSX_UNSIGNED + fullsiz;
    509 		}
    510 		(void) nfsm_strtom(nd, fhp, size);
    511 		break;
    512 	}
    513 	return (bytesize);
    514 }
    515 
    516 /*
    517  * This function compares two net addresses by family and returns TRUE
    518  * if they are the same host.
    519  * If there is any doubt, return FALSE.
    520  * The AF_INET family is handled as a special case so that address mbufs
    521  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
    522  */
    523 APPLESTATIC int
    524 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
    525 {
    526 	struct sockaddr_in *inetaddr;
    527 
    528 	switch (family) {
    529 	case AF_INET:
    530 		inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
    531 		if (inetaddr->sin_family == AF_INET &&
    532 		    inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
    533 			return (1);
    534 		break;
    535 #ifdef INET6
    536 	case AF_INET6:
    537 		{
    538 		struct sockaddr_in6 *inetaddr6;
    539 
    540 		inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
    541 		/* XXX - should test sin6_scope_id ? */
    542 		if (inetaddr6->sin6_family == AF_INET6 &&
    543 		    IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
    544 			  &haddr->had_inet6))
    545 			return (1);
    546 		}
    547 		break;
    548 #endif
    549 	}
    550 	return (0);
    551 }
    552 
    553 /*
    554  * Similar to the above, but takes to NFSSOCKADDR_T args.
    555  */
    556 APPLESTATIC int
    557 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
    558 {
    559 	struct sockaddr_in *addr1, *addr2;
    560 	struct sockaddr *inaddr;
    561 
    562 	inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
    563 	switch (inaddr->sa_family) {
    564 	case AF_INET:
    565 		addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
    566 		addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
    567 		if (addr2->sin_family == AF_INET &&
    568 		    addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
    569 			return (1);
    570 		break;
    571 #ifdef INET6
    572 	case AF_INET6:
    573 		{
    574 		struct sockaddr_in6 *inet6addr1, *inet6addr2;
    575 
    576 		inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
    577 		inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
    578 		/* XXX - should test sin6_scope_id ? */
    579 		if (inet6addr2->sin6_family == AF_INET6 &&
    580 		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
    581 			  &inet6addr2->sin6_addr))
    582 			return (1);
    583 		}
    584 		break;
    585 #endif
    586 	}
    587 	return (0);
    588 }
    589 
    590 
    591 /*
    592  * Trim the stuff already dissected off the mbuf list.
    593  */
    594 APPLESTATIC void
    595 newnfs_trimleading(nd)
    596 	struct nfsrv_descript *nd;
    597 {
    598 	mbuf_t m, n;
    599 	int offs;
    600 
    601 	/*
    602 	 * First, free up leading mbufs.
    603 	 */
    604 	if (nd->nd_mrep != nd->nd_md) {
    605 		m = nd->nd_mrep;
    606 		while (mbuf_next(m) != nd->nd_md) {
    607 			if (mbuf_next(m) == NULL)
    608 				panic("nfsm trim leading");
    609 			m = mbuf_next(m);
    610 		}
    611 		mbuf_setnext(m, NULL);
    612 		mbuf_freem(nd->nd_mrep);
    613 	}
    614 	m = nd->nd_md;
    615 
    616 	/*
    617 	 * Now, adjust this mbuf, based on nd_dpos.
    618 	 */
    619 	offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
    620 	if (offs == mbuf_len(m)) {
    621 		n = m;
    622 		m = mbuf_next(m);
    623 		if (m == NULL)
    624 			panic("nfsm trim leading2");
    625 		mbuf_setnext(n, NULL);
    626 		mbuf_freem(n);
    627 	} else if (offs > 0) {
    628 		mbuf_setlen(m, mbuf_len(m) - offs);
    629 		NFSM_DATAP(m, offs);
    630 	} else if (offs < 0)
    631 		panic("nfsm trimleading offs");
    632 	nd->nd_mrep = m;
    633 	nd->nd_md = m;
    634 	nd->nd_dpos = NFSMTOD(m, caddr_t);
    635 }
    636 
    637 /*
    638  * Trim trailing data off the mbuf list being built.
    639  */
    640 APPLESTATIC void
    641 newnfs_trimtrailing(nd, mb, bpos)
    642 	struct nfsrv_descript *nd;
    643 	mbuf_t mb;
    644 	caddr_t bpos;
    645 {
    646 
    647 	if (mbuf_next(mb)) {
    648 		mbuf_freem(mbuf_next(mb));
    649 		mbuf_setnext(mb, NULL);
    650 	}
    651 	mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
    652 	nd->nd_mb = mb;
    653 	nd->nd_bpos = bpos;
    654 }
    655 
    656 /*
    657  * Dissect a file handle on the client.
    658  */
    659 APPLESTATIC int
    660 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
    661 {
    662 	u_int32_t *tl;
    663 	struct nfsfh *nfhp;
    664 	int error, len;
    665 
    666 	*nfhpp = NULL;
    667 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
    668 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    669 		if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
    670 			len > NFSX_FHMAX) {
    671 			error = EBADRPC;
    672 			goto nfsmout;
    673 		}
    674 	} else
    675 		len = NFSX_V2FH;
    676 	MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
    677 	    M_NFSFH, M_WAITOK);
    678 	error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
    679 	if (error) {
    680 		FREE((caddr_t)nfhp, M_NFSFH);
    681 		goto nfsmout;
    682 	}
    683 	nfhp->nfh_len = len;
    684 	*nfhpp = nfhp;
    685 nfsmout:
    686 	NFSEXITCODE2(error, nd);
    687 	return (error);
    688 }
    689 
    690 /*
    691  * Break down the nfsv4 acl.
    692  * If the aclp == NULL or won't fit in an acl, just discard the acl info.
    693  */
    694 APPLESTATIC int
    695 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
    696     int *aclsizep, __unused NFSPROC_T *p)
    697 {
    698 	u_int32_t *tl;
    699 	int i, aclsize;
    700 	int acecnt, error = 0, aceerr = 0, acesize;
    701 
    702 	*aclerrp = 0;
    703 	if (aclp)
    704 		aclp->acl_cnt = 0;
    705 	/*
    706 	 * Parse out the ace entries and expect them to conform to
    707 	 * what can be supported by R/W/X bits.
    708 	 */
    709 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    710 	aclsize = NFSX_UNSIGNED;
    711 	acecnt = fxdr_unsigned(int, *tl);
    712 	if (acecnt > ACL_MAX_ENTRIES)
    713 		aceerr = NFSERR_ATTRNOTSUPP;
    714 	if (nfsrv_useacl == 0)
    715 		aceerr = NFSERR_ATTRNOTSUPP;
    716 	for (i = 0; i < acecnt; i++) {
    717 		if (aclp && !aceerr)
    718 			error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
    719 			    &aceerr, &acesize, p);
    720 		else
    721 			error = nfsrv_skipace(nd, &acesize);
    722 		if (error)
    723 			goto nfsmout;
    724 		aclsize += acesize;
    725 	}
    726 	if (aclp && !aceerr)
    727 		aclp->acl_cnt = acecnt;
    728 	if (aceerr)
    729 		*aclerrp = aceerr;
    730 	if (aclsizep)
    731 		*aclsizep = aclsize;
    732 nfsmout:
    733 	NFSEXITCODE2(error, nd);
    734 	return (error);
    735 }
    736 
    737 /*
    738  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
    739  */
    740 static int
    741 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
    742 {
    743 	u_int32_t *tl;
    744 	int error, len = 0;
    745 
    746 	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
    747 	len = fxdr_unsigned(int, *(tl + 3));
    748 	error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
    749 nfsmout:
    750 	*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
    751 	NFSEXITCODE2(error, nd);
    752 	return (error);
    753 }
    754 
    755 /*
    756  * Get attribute bits from an mbuf list.
    757  * Returns EBADRPC for a parsing error, 0 otherwise.
    758  * If the clearinvalid flag is set, clear the bits not supported.
    759  */
    760 APPLESTATIC int
    761 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
    762     int *retnotsupp)
    763 {
    764 	u_int32_t *tl;
    765 	int cnt, i, outcnt;
    766 	int error = 0;
    767 
    768 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    769 	cnt = fxdr_unsigned(int, *tl);
    770 	if (cnt < 0) {
    771 		error = NFSERR_BADXDR;
    772 		goto nfsmout;
    773 	}
    774 	if (cnt > NFSATTRBIT_MAXWORDS)
    775 		outcnt = NFSATTRBIT_MAXWORDS;
    776 	else
    777 		outcnt = cnt;
    778 	NFSZERO_ATTRBIT(attrbitp);
    779 	if (outcnt > 0) {
    780 		NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
    781 		for (i = 0; i < outcnt; i++)
    782 			attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
    783 	}
    784 	for (i = 0; i < (cnt - outcnt); i++) {
    785 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    786 		if (retnotsupp != NULL && *tl != 0)
    787 			*retnotsupp = NFSERR_ATTRNOTSUPP;
    788 	}
    789 	if (cntp)
    790 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
    791 nfsmout:
    792 	NFSEXITCODE2(error, nd);
    793 	return (error);
    794 }
    795 
    796 /*
    797  * Get the attributes for V4.
    798  * If the compare flag is true, test for any attribute changes,
    799  * otherwise return the attribute values.
    800  * These attributes cover fields in "struct vattr", "struct statfs",
    801  * "struct nfsfsinfo", the file handle and the lease duration.
    802  * The value of retcmpp is set to 1 if all attributes are the same,
    803  * and 0 otherwise.
    804  * Returns EBADRPC if it can't be parsed, 0 otherwise.
    805  */
    806 APPLESTATIC int
    807 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
    808     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
    809     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
    810     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
    811     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
    812 {
    813 	u_int32_t *tl;
    814 	int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
    815 	int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
    816 	u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
    817 	nfsattrbit_t attrbits, retattrbits, checkattrbits;
    818 	struct nfsfh *tnfhp;
    819 	struct nfsreferral *refp;
    820 	u_quad_t tquad;
    821 	nfsquad_t tnfsquad;
    822 	struct timespec temptime;
    823 	uid_t uid;
    824 	gid_t gid;
    825 	long fid;
    826 	u_int32_t freenum = 0, tuint;
    827 	u_int64_t uquad = 0, thyp, thyp2;
    828 #ifdef QUOTA
    829 	struct dqblk dqb;
    830 	uid_t savuid;
    831 #endif
    832 	static struct timeval last64fileid;
    833 	static size_t count64fileid;
    834 	static struct timeval last64mountfileid;
    835 	static size_t count64mountfileid;
    836 	static struct timeval warninterval = { 60, 0 };
    837 
    838 	if (compare) {
    839 		retnotsup = 0;
    840 		error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
    841 	} else {
    842 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
    843 	}
    844 	if (error)
    845 		goto nfsmout;
    846 
    847 	if (compare) {
    848 		*retcmpp = retnotsup;
    849 	} else {
    850 		/*
    851 		 * Just set default values to some of the important ones.
    852 		 */
    853 		if (nap != NULL) {
    854 			nap->na_type = VREG;
    855 			nap->na_mode = 0;
    856 			nap->na_rdev = (NFSDEV_T)0;
    857 			nap->na_mtime.tv_sec = 0;
    858 			nap->na_mtime.tv_nsec = 0;
    859 			nap->na_gen = 0;
    860 			nap->na_flags = 0;
    861 			nap->na_blocksize = NFS_FABLKSIZE;
    862 		}
    863 		if (sbp != NULL) {
    864 			sbp->f_bsize = NFS_FABLKSIZE;
    865 			sbp->f_blocks = 0;
    866 			sbp->f_bfree = 0;
    867 			sbp->f_bavail = 0;
    868 			sbp->f_files = 0;
    869 			sbp->f_ffree = 0;
    870 		}
    871 		if (fsp != NULL) {
    872 			fsp->fs_rtmax = 8192;
    873 			fsp->fs_rtpref = 8192;
    874 			fsp->fs_maxname = NFS_MAXNAMLEN;
    875 			fsp->fs_wtmax = 8192;
    876 			fsp->fs_wtpref = 8192;
    877 			fsp->fs_wtmult = NFS_FABLKSIZE;
    878 			fsp->fs_dtpref = 8192;
    879 			fsp->fs_maxfilesize = 0xffffffffffffffffull;
    880 			fsp->fs_timedelta.tv_sec = 0;
    881 			fsp->fs_timedelta.tv_nsec = 1;
    882 			fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
    883 				NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
    884 		}
    885 		if (pc != NULL) {
    886 			pc->pc_linkmax = LINK_MAX;
    887 			pc->pc_namemax = NAME_MAX;
    888 			pc->pc_notrunc = 0;
    889 			pc->pc_chownrestricted = 0;
    890 			pc->pc_caseinsensitive = 0;
    891 			pc->pc_casepreserving = 1;
    892 		}
    893 	}
    894 
    895 	/*
    896 	 * Loop around getting the attributes.
    897 	 */
    898 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    899 	attrsize = fxdr_unsigned(int, *tl);
    900 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
    901 	    if (attrsum > attrsize) {
    902 		error = NFSERR_BADXDR;
    903 		goto nfsmout;
    904 	    }
    905 	    if (NFSISSET_ATTRBIT(&attrbits, bitpos))
    906 		switch (bitpos) {
    907 		case NFSATTRBIT_SUPPORTEDATTRS:
    908 			retnotsup = 0;
    909 			if (compare || nap == NULL)
    910 			    error = nfsrv_getattrbits(nd, &retattrbits,
    911 				&cnt, &retnotsup);
    912 			else
    913 			    error = nfsrv_getattrbits(nd, &nap->na_suppattr,
    914 				&cnt, &retnotsup);
    915 			if (error)
    916 			    goto nfsmout;
    917 			if (compare && !(*retcmpp)) {
    918 			   NFSSETSUPP_ATTRBIT(&checkattrbits);
    919 
    920 			   /* Some filesystem do not support NFSv4ACL   */
    921 			   if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
    922 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
    923 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
    924 		   	   }
    925 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
    926 			       || retnotsup)
    927 				*retcmpp = NFSERR_NOTSAME;
    928 			}
    929 			attrsum += cnt;
    930 			break;
    931 		case NFSATTRBIT_TYPE:
    932 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    933 			if (compare) {
    934 				if (!(*retcmpp)) {
    935 				    if (nap->na_type != nfsv34tov_type(*tl))
    936 					*retcmpp = NFSERR_NOTSAME;
    937 				}
    938 			} else if (nap != NULL) {
    939 				nap->na_type = nfsv34tov_type(*tl);
    940 			}
    941 			attrsum += NFSX_UNSIGNED;
    942 			break;
    943 		case NFSATTRBIT_FHEXPIRETYPE:
    944 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    945 			if (compare && !(*retcmpp)) {
    946 				if (fxdr_unsigned(int, *tl) !=
    947 					NFSV4FHTYPE_PERSISTENT)
    948 					*retcmpp = NFSERR_NOTSAME;
    949 			}
    950 			attrsum += NFSX_UNSIGNED;
    951 			break;
    952 		case NFSATTRBIT_CHANGE:
    953 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
    954 			if (compare) {
    955 				if (!(*retcmpp)) {
    956 				    if (nap->na_filerev != fxdr_hyper(tl))
    957 					*retcmpp = NFSERR_NOTSAME;
    958 				}
    959 			} else if (nap != NULL) {
    960 				nap->na_filerev = fxdr_hyper(tl);
    961 			}
    962 			attrsum += NFSX_HYPER;
    963 			break;
    964 		case NFSATTRBIT_SIZE:
    965 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
    966 			if (compare) {
    967 				if (!(*retcmpp)) {
    968 				    if (nap->na_size != fxdr_hyper(tl))
    969 					*retcmpp = NFSERR_NOTSAME;
    970 				}
    971 			} else if (nap != NULL) {
    972 				nap->na_size = fxdr_hyper(tl);
    973 			}
    974 			attrsum += NFSX_HYPER;
    975 			break;
    976 		case NFSATTRBIT_LINKSUPPORT:
    977 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    978 			if (compare) {
    979 				if (!(*retcmpp)) {
    980 				    if (fsp->fs_properties & NFSV3_FSFLINK) {
    981 					if (*tl == newnfs_false)
    982 						*retcmpp = NFSERR_NOTSAME;
    983 				    } else {
    984 					if (*tl == newnfs_true)
    985 						*retcmpp = NFSERR_NOTSAME;
    986 				    }
    987 				}
    988 			} else if (fsp != NULL) {
    989 				if (*tl == newnfs_true)
    990 					fsp->fs_properties |= NFSV3_FSFLINK;
    991 				else
    992 					fsp->fs_properties &= ~NFSV3_FSFLINK;
    993 			}
    994 			attrsum += NFSX_UNSIGNED;
    995 			break;
    996 		case NFSATTRBIT_SYMLINKSUPPORT:
    997 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    998 			if (compare) {
    999 				if (!(*retcmpp)) {
   1000 				    if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
   1001 					if (*tl == newnfs_false)
   1002 						*retcmpp = NFSERR_NOTSAME;
   1003 				    } else {
   1004 					if (*tl == newnfs_true)
   1005 						*retcmpp = NFSERR_NOTSAME;
   1006 				    }
   1007 				}
   1008 			} else if (fsp != NULL) {
   1009 				if (*tl == newnfs_true)
   1010 					fsp->fs_properties |= NFSV3_FSFSYMLINK;
   1011 				else
   1012 					fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
   1013 			}
   1014 			attrsum += NFSX_UNSIGNED;
   1015 			break;
   1016 		case NFSATTRBIT_NAMEDATTR:
   1017 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1018 			if (compare && !(*retcmpp)) {
   1019 				if (*tl != newnfs_false)
   1020 					*retcmpp = NFSERR_NOTSAME;
   1021 			}
   1022 			attrsum += NFSX_UNSIGNED;
   1023 			break;
   1024 		case NFSATTRBIT_FSID:
   1025 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
   1026 			thyp = fxdr_hyper(tl);
   1027 			tl += 2;
   1028 			thyp2 = fxdr_hyper(tl);
   1029 			if (compare) {
   1030 			    if (*retcmpp == 0) {
   1031 				if (thyp != (u_int64_t)
   1032 				    vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
   1033 				    thyp2 != (u_int64_t)
   1034 				    vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
   1035 					*retcmpp = NFSERR_NOTSAME;
   1036 			    }
   1037 			} else if (nap != NULL) {
   1038 				nap->na_filesid[0] = thyp;
   1039 				nap->na_filesid[1] = thyp2;
   1040 			}
   1041 			attrsum += (4 * NFSX_UNSIGNED);
   1042 			break;
   1043 		case NFSATTRBIT_UNIQUEHANDLES:
   1044 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1045 			if (compare && !(*retcmpp)) {
   1046 				if (*tl != newnfs_true)
   1047 					*retcmpp = NFSERR_NOTSAME;
   1048 			}
   1049 			attrsum += NFSX_UNSIGNED;
   1050 			break;
   1051 		case NFSATTRBIT_LEASETIME:
   1052 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1053 			if (compare) {
   1054 				if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
   1055 				    !(*retcmpp))
   1056 					*retcmpp = NFSERR_NOTSAME;
   1057 			} else if (leasep != NULL) {
   1058 				*leasep = fxdr_unsigned(u_int32_t, *tl);
   1059 			}
   1060 			attrsum += NFSX_UNSIGNED;
   1061 			break;
   1062 		case NFSATTRBIT_RDATTRERROR:
   1063 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1064 			if (compare) {
   1065 				 if (!(*retcmpp))
   1066 					*retcmpp = NFSERR_INVAL;
   1067 			} else if (rderrp != NULL) {
   1068 				*rderrp = fxdr_unsigned(u_int32_t, *tl);
   1069 			}
   1070 			attrsum += NFSX_UNSIGNED;
   1071 			break;
   1072 		case NFSATTRBIT_ACL:
   1073 			if (compare) {
   1074 			  if (!(*retcmpp)) {
   1075 			    if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
   1076 				NFSACL_T *naclp;
   1077 
   1078 				naclp = acl_alloc(M_WAITOK);
   1079 				error = nfsrv_dissectacl(nd, naclp, &aceerr,
   1080 				    &cnt, p);
   1081 				if (error) {
   1082 				    acl_free(naclp);
   1083 				    goto nfsmout;
   1084 				}
   1085 				if (aceerr || aclp == NULL ||
   1086 				    nfsrv_compareacl(aclp, naclp))
   1087 				    *retcmpp = NFSERR_NOTSAME;
   1088 				acl_free(naclp);
   1089 			    } else {
   1090 				error = nfsrv_dissectacl(nd, NULL, &aceerr,
   1091 				    &cnt, p);
   1092 				*retcmpp = NFSERR_ATTRNOTSUPP;
   1093 			    }
   1094 			  }
   1095 			} else {
   1096 				if (vp != NULL && aclp != NULL)
   1097 				    error = nfsrv_dissectacl(nd, aclp, &aceerr,
   1098 					&cnt, p);
   1099 				else
   1100 				    error = nfsrv_dissectacl(nd, NULL, &aceerr,
   1101 					&cnt, p);
   1102 				if (error)
   1103 				    goto nfsmout;
   1104 			}
   1105 
   1106 			attrsum += cnt;
   1107 			break;
   1108 		case NFSATTRBIT_ACLSUPPORT:
   1109 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1110 			if (compare && !(*retcmpp)) {
   1111 				if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
   1112 					if (fxdr_unsigned(u_int32_t, *tl) !=
   1113 					    NFSV4ACE_SUPTYPES)
   1114 						*retcmpp = NFSERR_NOTSAME;
   1115 				} else {
   1116 					*retcmpp = NFSERR_ATTRNOTSUPP;
   1117 				}
   1118 			}
   1119 			attrsum += NFSX_UNSIGNED;
   1120 			break;
   1121 		case NFSATTRBIT_ARCHIVE:
   1122 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1123 			if (compare && !(*retcmpp))
   1124 				*retcmpp = NFSERR_ATTRNOTSUPP;
   1125 			attrsum += NFSX_UNSIGNED;
   1126 			break;
   1127 		case NFSATTRBIT_CANSETTIME:
   1128 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1129 			if (compare) {
   1130 				if (!(*retcmpp)) {
   1131 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
   1132 					if (*tl == newnfs_false)
   1133 						*retcmpp = NFSERR_NOTSAME;
   1134 				    } else {
   1135 					if (*tl == newnfs_true)
   1136 						*retcmpp = NFSERR_NOTSAME;
   1137 				    }
   1138 				}
   1139 			} else if (fsp != NULL) {
   1140 				if (*tl == newnfs_true)
   1141 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
   1142 				else
   1143 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
   1144 			}
   1145 			attrsum += NFSX_UNSIGNED;
   1146 			break;
   1147 		case NFSATTRBIT_CASEINSENSITIVE:
   1148 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1149 			if (compare) {
   1150 				if (!(*retcmpp)) {
   1151 				    if (*tl != newnfs_false)
   1152 					*retcmpp = NFSERR_NOTSAME;
   1153 				}
   1154 			} else if (pc != NULL) {
   1155 				pc->pc_caseinsensitive =
   1156 				    fxdr_unsigned(u_int32_t, *tl);
   1157 			}
   1158 			attrsum += NFSX_UNSIGNED;
   1159 			break;
   1160 		case NFSATTRBIT_CASEPRESERVING:
   1161 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1162 			if (compare) {
   1163 				if (!(*retcmpp)) {
   1164 				    if (*tl != newnfs_true)
   1165 					*retcmpp = NFSERR_NOTSAME;
   1166 				}
   1167 			} else if (pc != NULL) {
   1168 				pc->pc_casepreserving =
   1169 				    fxdr_unsigned(u_int32_t, *tl);
   1170 			}
   1171 			attrsum += NFSX_UNSIGNED;
   1172 			break;
   1173 		case NFSATTRBIT_CHOWNRESTRICTED:
   1174 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1175 			if (compare) {
   1176 				if (!(*retcmpp)) {
   1177 				    if (*tl != newnfs_true)
   1178 					*retcmpp = NFSERR_NOTSAME;
   1179 				}
   1180 			} else if (pc != NULL) {
   1181 				pc->pc_chownrestricted =
   1182 				    fxdr_unsigned(u_int32_t, *tl);
   1183 			}
   1184 			attrsum += NFSX_UNSIGNED;
   1185 			break;
   1186 		case NFSATTRBIT_FILEHANDLE:
   1187 			error = nfsm_getfh(nd, &tnfhp);
   1188 			if (error)
   1189 				goto nfsmout;
   1190 			tfhsize = tnfhp->nfh_len;
   1191 			if (compare) {
   1192 				if (!(*retcmpp) &&
   1193 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
   1194 				     fhp, fhsize))
   1195 					*retcmpp = NFSERR_NOTSAME;
   1196 				FREE((caddr_t)tnfhp, M_NFSFH);
   1197 			} else if (nfhpp != NULL) {
   1198 				*nfhpp = tnfhp;
   1199 			} else {
   1200 				FREE((caddr_t)tnfhp, M_NFSFH);
   1201 			}
   1202 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
   1203 			break;
   1204 		case NFSATTRBIT_FILEID:
   1205 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1206 			thyp = fxdr_hyper(tl);
   1207 			if (compare) {
   1208 				if (!(*retcmpp)) {
   1209 				    if ((u_int64_t)nap->na_fileid != thyp)
   1210 					*retcmpp = NFSERR_NOTSAME;
   1211 				}
   1212 			} else if (nap != NULL) {
   1213 				if (*tl++) {
   1214 					count64fileid++;
   1215 					if (ratecheck(&last64fileid, &warninterval)) {
   1216 						printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
   1217 						    count64fileid);
   1218 						count64fileid = 0;
   1219 					}
   1220 				}
   1221 				nap->na_fileid = thyp;
   1222 			}
   1223 			attrsum += NFSX_HYPER;
   1224 			break;
   1225 		case NFSATTRBIT_FILESAVAIL:
   1226 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1227 			if (compare) {
   1228 				if (!(*retcmpp) &&
   1229 				    sfp->sf_afiles != fxdr_hyper(tl))
   1230 					*retcmpp = NFSERR_NOTSAME;
   1231 			} else if (sfp != NULL) {
   1232 				sfp->sf_afiles = fxdr_hyper(tl);
   1233 			}
   1234 			attrsum += NFSX_HYPER;
   1235 			break;
   1236 		case NFSATTRBIT_FILESFREE:
   1237 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1238 			if (compare) {
   1239 				if (!(*retcmpp) &&
   1240 				    sfp->sf_ffiles != fxdr_hyper(tl))
   1241 					*retcmpp = NFSERR_NOTSAME;
   1242 			} else if (sfp != NULL) {
   1243 				sfp->sf_ffiles = fxdr_hyper(tl);
   1244 			}
   1245 			attrsum += NFSX_HYPER;
   1246 			break;
   1247 		case NFSATTRBIT_FILESTOTAL:
   1248 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1249 			if (compare) {
   1250 				if (!(*retcmpp) &&
   1251 				    sfp->sf_tfiles != fxdr_hyper(tl))
   1252 					*retcmpp = NFSERR_NOTSAME;
   1253 			} else if (sfp != NULL) {
   1254 				sfp->sf_tfiles = fxdr_hyper(tl);
   1255 			}
   1256 			attrsum += NFSX_HYPER;
   1257 			break;
   1258 		case NFSATTRBIT_FSLOCATIONS:
   1259 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
   1260 			if (error)
   1261 				goto nfsmout;
   1262 			attrsum += l;
   1263 			if (compare && !(*retcmpp)) {
   1264 				refp = nfsv4root_getreferral(vp, NULL, 0);
   1265 				if (refp != NULL) {
   1266 					if (cp == NULL || cp2 == NULL ||
   1267 					    strcmp(cp, "/") ||
   1268 					    strcmp(cp2, refp->nfr_srvlist))
   1269 						*retcmpp = NFSERR_NOTSAME;
   1270 				} else if (m == 0) {
   1271 					*retcmpp = NFSERR_NOTSAME;
   1272 				}
   1273 			}
   1274 			if (cp != NULL)
   1275 				free(cp, M_NFSSTRING);
   1276 			if (cp2 != NULL)
   1277 				free(cp2, M_NFSSTRING);
   1278 			break;
   1279 		case NFSATTRBIT_HIDDEN:
   1280 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1281 			if (compare && !(*retcmpp))
   1282 				*retcmpp = NFSERR_ATTRNOTSUPP;
   1283 			attrsum += NFSX_UNSIGNED;
   1284 			break;
   1285 		case NFSATTRBIT_HOMOGENEOUS:
   1286 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1287 			if (compare) {
   1288 				if (!(*retcmpp)) {
   1289 				    if (fsp->fs_properties &
   1290 					NFSV3_FSFHOMOGENEOUS) {
   1291 					if (*tl == newnfs_false)
   1292 						*retcmpp = NFSERR_NOTSAME;
   1293 				    } else {
   1294 					if (*tl == newnfs_true)
   1295 						*retcmpp = NFSERR_NOTSAME;
   1296 				    }
   1297 				}
   1298 			} else if (fsp != NULL) {
   1299 				if (*tl == newnfs_true)
   1300 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
   1301 				else
   1302 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
   1303 			}
   1304 			attrsum += NFSX_UNSIGNED;
   1305 			break;
   1306 		case NFSATTRBIT_MAXFILESIZE:
   1307 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1308 			tnfsquad.qval = fxdr_hyper(tl);
   1309 			if (compare) {
   1310 				if (!(*retcmpp)) {
   1311 					tquad = NFSRV_MAXFILESIZE;
   1312 					if (tquad != tnfsquad.qval)
   1313 						*retcmpp = NFSERR_NOTSAME;
   1314 				}
   1315 			} else if (fsp != NULL) {
   1316 				fsp->fs_maxfilesize = tnfsquad.qval;
   1317 			}
   1318 			attrsum += NFSX_HYPER;
   1319 			break;
   1320 		case NFSATTRBIT_MAXLINK:
   1321 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1322 			if (compare) {
   1323 				if (!(*retcmpp)) {
   1324 				    if (fxdr_unsigned(int, *tl) != LINK_MAX)
   1325 					*retcmpp = NFSERR_NOTSAME;
   1326 				}
   1327 			} else if (pc != NULL) {
   1328 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
   1329 			}
   1330 			attrsum += NFSX_UNSIGNED;
   1331 			break;
   1332 		case NFSATTRBIT_MAXNAME:
   1333 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1334 			if (compare) {
   1335 				if (!(*retcmpp)) {
   1336 				    if (fsp->fs_maxname !=
   1337 					fxdr_unsigned(u_int32_t, *tl))
   1338 						*retcmpp = NFSERR_NOTSAME;
   1339 				}
   1340 			} else {
   1341 				tuint = fxdr_unsigned(u_int32_t, *tl);
   1342 				/*
   1343 				 * Some Linux NFSv4 servers report this
   1344 				 * as 0 or 4billion, so I'll set it to
   1345 				 * NFS_MAXNAMLEN. If a server actually creates
   1346 				 * a name longer than NFS_MAXNAMLEN, it will
   1347 				 * get an error back.
   1348 				 */
   1349 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
   1350 					tuint = NFS_MAXNAMLEN;
   1351 				if (fsp != NULL)
   1352 					fsp->fs_maxname = tuint;
   1353 				if (pc != NULL)
   1354 					pc->pc_namemax = tuint;
   1355 			}
   1356 			attrsum += NFSX_UNSIGNED;
   1357 			break;
   1358 		case NFSATTRBIT_MAXREAD:
   1359 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1360 			if (compare) {
   1361 				if (!(*retcmpp)) {
   1362 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
   1363 					*(tl + 1)) || *tl != 0)
   1364 					*retcmpp = NFSERR_NOTSAME;
   1365 				}
   1366 			} else if (fsp != NULL) {
   1367 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
   1368 				fsp->fs_rtpref = fsp->fs_rtmax;
   1369 				fsp->fs_dtpref = fsp->fs_rtpref;
   1370 			}
   1371 			attrsum += NFSX_HYPER;
   1372 			break;
   1373 		case NFSATTRBIT_MAXWRITE:
   1374 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1375 			if (compare) {
   1376 				if (!(*retcmpp)) {
   1377 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
   1378 					*(tl + 1)) || *tl != 0)
   1379 					*retcmpp = NFSERR_NOTSAME;
   1380 				}
   1381 			} else if (fsp != NULL) {
   1382 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
   1383 				fsp->fs_wtpref = fsp->fs_wtmax;
   1384 			}
   1385 			attrsum += NFSX_HYPER;
   1386 			break;
   1387 		case NFSATTRBIT_MIMETYPE:
   1388 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1389 			i = fxdr_unsigned(int, *tl);
   1390 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
   1391 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
   1392 			if (error)
   1393 				goto nfsmout;
   1394 			if (compare && !(*retcmpp))
   1395 				*retcmpp = NFSERR_ATTRNOTSUPP;
   1396 			break;
   1397 		case NFSATTRBIT_MODE:
   1398 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1399 			if (compare) {
   1400 				if (!(*retcmpp)) {
   1401 				    if (nap->na_mode != nfstov_mode(*tl))
   1402 					*retcmpp = NFSERR_NOTSAME;
   1403 				}
   1404 			} else if (nap != NULL) {
   1405 				nap->na_mode = nfstov_mode(*tl);
   1406 			}
   1407 			attrsum += NFSX_UNSIGNED;
   1408 			break;
   1409 		case NFSATTRBIT_NOTRUNC:
   1410 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1411 			if (compare) {
   1412 				if (!(*retcmpp)) {
   1413 				    if (*tl != newnfs_true)
   1414 					*retcmpp = NFSERR_NOTSAME;
   1415 				}
   1416 			} else if (pc != NULL) {
   1417 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
   1418 			}
   1419 			attrsum += NFSX_UNSIGNED;
   1420 			break;
   1421 		case NFSATTRBIT_NUMLINKS:
   1422 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1423 			tuint = fxdr_unsigned(u_int32_t, *tl);
   1424 			if (compare) {
   1425 			    if (!(*retcmpp)) {
   1426 				if ((u_int32_t)nap->na_nlink != tuint)
   1427 					*retcmpp = NFSERR_NOTSAME;
   1428 			    }
   1429 			} else if (nap != NULL) {
   1430 				nap->na_nlink = tuint;
   1431 			}
   1432 			attrsum += NFSX_UNSIGNED;
   1433 			break;
   1434 		case NFSATTRBIT_OWNER:
   1435 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1436 			j = fxdr_unsigned(int, *tl);
   1437 			if (j < 0) {
   1438 				error = NFSERR_BADXDR;
   1439 				goto nfsmout;
   1440 			}
   1441 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
   1442 			if (j > NFSV4_SMALLSTR)
   1443 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
   1444 			else
   1445 				cp = namestr;
   1446 			error = nfsrv_mtostr(nd, cp, j);
   1447 			if (error) {
   1448 				if (j > NFSV4_SMALLSTR)
   1449 					free(cp, M_NFSSTRING);
   1450 				goto nfsmout;
   1451 			}
   1452 			if (compare) {
   1453 			    if (!(*retcmpp)) {
   1454 				if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
   1455 				    nap->na_uid != uid)
   1456 				    *retcmpp = NFSERR_NOTSAME;
   1457 			    }
   1458 			} else if (nap != NULL) {
   1459 				if (nfsv4_strtouid(nd, cp, j, &uid, p))
   1460 					nap->na_uid = nfsrv_defaultuid;
   1461 				else
   1462 					nap->na_uid = uid;
   1463 			}
   1464 			if (j > NFSV4_SMALLSTR)
   1465 				free(cp, M_NFSSTRING);
   1466 			break;
   1467 		case NFSATTRBIT_OWNERGROUP:
   1468 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1469 			j = fxdr_unsigned(int, *tl);
   1470 			if (j < 0) {
   1471 				error =  NFSERR_BADXDR;
   1472 				goto nfsmout;
   1473 			}
   1474 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
   1475 			if (j > NFSV4_SMALLSTR)
   1476 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
   1477 			else
   1478 				cp = namestr;
   1479 			error = nfsrv_mtostr(nd, cp, j);
   1480 			if (error) {
   1481 				if (j > NFSV4_SMALLSTR)
   1482 					free(cp, M_NFSSTRING);
   1483 				goto nfsmout;
   1484 			}
   1485 			if (compare) {
   1486 			    if (!(*retcmpp)) {
   1487 				if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
   1488 				    nap->na_gid != gid)
   1489 				    *retcmpp = NFSERR_NOTSAME;
   1490 			    }
   1491 			} else if (nap != NULL) {
   1492 				if (nfsv4_strtogid(nd, cp, j, &gid, p))
   1493 					nap->na_gid = nfsrv_defaultgid;
   1494 				else
   1495 					nap->na_gid = gid;
   1496 			}
   1497 			if (j > NFSV4_SMALLSTR)
   1498 				free(cp, M_NFSSTRING);
   1499 			break;
   1500 		case NFSATTRBIT_QUOTAHARD:
   1501 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1502 			if (sbp != NULL) {
   1503 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
   1504 				freenum = sbp->f_bfree;
   1505 			    else
   1506 				freenum = sbp->f_bavail;
   1507 #ifdef QUOTA
   1508 			    /*
   1509 			     * ufs_quotactl() insists that the uid argument
   1510 			     * equal p_ruid for non-root quota access, so
   1511 			     * we'll just make sure that's the case.
   1512 			     */
   1513 			    savuid = p->p_cred->p_ruid;
   1514 			    p->p_cred->p_ruid = cred->cr_uid;
   1515 			    if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
   1516 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
   1517 				freenum = min(dqb.dqb_bhardlimit, freenum);
   1518 			    p->p_cred->p_ruid = savuid;
   1519 #endif	/* QUOTA */
   1520 			    uquad = (u_int64_t)freenum;
   1521 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
   1522 			}
   1523 			if (compare && !(*retcmpp)) {
   1524 				if (uquad != fxdr_hyper(tl))
   1525 					*retcmpp = NFSERR_NOTSAME;
   1526 			}
   1527 			attrsum += NFSX_HYPER;
   1528 			break;
   1529 		case NFSATTRBIT_QUOTASOFT:
   1530 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1531 			if (sbp != NULL) {
   1532 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
   1533 				freenum = sbp->f_bfree;
   1534 			    else
   1535 				freenum = sbp->f_bavail;
   1536 #ifdef QUOTA
   1537 			    /*
   1538 			     * ufs_quotactl() insists that the uid argument
   1539 			     * equal p_ruid for non-root quota access, so
   1540 			     * we'll just make sure that's the case.
   1541 			     */
   1542 			    savuid = p->p_cred->p_ruid;
   1543 			    p->p_cred->p_ruid = cred->cr_uid;
   1544 			    if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
   1545 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
   1546 				freenum = min(dqb.dqb_bsoftlimit, freenum);
   1547 			    p->p_cred->p_ruid = savuid;
   1548 #endif	/* QUOTA */
   1549 			    uquad = (u_int64_t)freenum;
   1550 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
   1551 			}
   1552 			if (compare && !(*retcmpp)) {
   1553 				if (uquad != fxdr_hyper(tl))
   1554 					*retcmpp = NFSERR_NOTSAME;
   1555 			}
   1556 			attrsum += NFSX_HYPER;
   1557 			break;
   1558 		case NFSATTRBIT_QUOTAUSED:
   1559 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1560 			if (sbp != NULL) {
   1561 			    freenum = 0;
   1562 #ifdef QUOTA
   1563 			    /*
   1564 			     * ufs_quotactl() insists that the uid argument
   1565 			     * equal p_ruid for non-root quota access, so
   1566 			     * we'll just make sure that's the case.
   1567 			     */
   1568 			    savuid = p->p_cred->p_ruid;
   1569 			    p->p_cred->p_ruid = cred->cr_uid;
   1570 			    if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
   1571 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
   1572 				freenum = dqb.dqb_curblocks;
   1573 			    p->p_cred->p_ruid = savuid;
   1574 #endif	/* QUOTA */
   1575 			    uquad = (u_int64_t)freenum;
   1576 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
   1577 			}
   1578 			if (compare && !(*retcmpp)) {
   1579 				if (uquad != fxdr_hyper(tl))
   1580 					*retcmpp = NFSERR_NOTSAME;
   1581 			}
   1582 			attrsum += NFSX_HYPER;
   1583 			break;
   1584 		case NFSATTRBIT_RAWDEV:
   1585 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
   1586 			j = fxdr_unsigned(int, *tl++);
   1587 			k = fxdr_unsigned(int, *tl);
   1588 			if (compare) {
   1589 			    if (!(*retcmpp)) {
   1590 				if (nap->na_rdev != NFSMAKEDEV(j, k))
   1591 					*retcmpp = NFSERR_NOTSAME;
   1592 			    }
   1593 			} else if (nap != NULL) {
   1594 				nap->na_rdev = NFSMAKEDEV(j, k);
   1595 			}
   1596 			attrsum += NFSX_V4SPECDATA;
   1597 			break;
   1598 		case NFSATTRBIT_SPACEAVAIL:
   1599 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1600 			if (compare) {
   1601 				if (!(*retcmpp) &&
   1602 				    sfp->sf_abytes != fxdr_hyper(tl))
   1603 					*retcmpp = NFSERR_NOTSAME;
   1604 			} else if (sfp != NULL) {
   1605 				sfp->sf_abytes = fxdr_hyper(tl);
   1606 			}
   1607 			attrsum += NFSX_HYPER;
   1608 			break;
   1609 		case NFSATTRBIT_SPACEFREE:
   1610 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1611 			if (compare) {
   1612 				if (!(*retcmpp) &&
   1613 				    sfp->sf_fbytes != fxdr_hyper(tl))
   1614 					*retcmpp = NFSERR_NOTSAME;
   1615 			} else if (sfp != NULL) {
   1616 				sfp->sf_fbytes = fxdr_hyper(tl);
   1617 			}
   1618 			attrsum += NFSX_HYPER;
   1619 			break;
   1620 		case NFSATTRBIT_SPACETOTAL:
   1621 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1622 			if (compare) {
   1623 				if (!(*retcmpp) &&
   1624 				    sfp->sf_tbytes != fxdr_hyper(tl))
   1625 					*retcmpp = NFSERR_NOTSAME;
   1626 			} else if (sfp != NULL) {
   1627 				sfp->sf_tbytes = fxdr_hyper(tl);
   1628 			}
   1629 			attrsum += NFSX_HYPER;
   1630 			break;
   1631 		case NFSATTRBIT_SPACEUSED:
   1632 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1633 			thyp = fxdr_hyper(tl);
   1634 			if (compare) {
   1635 			    if (!(*retcmpp)) {
   1636 				if ((u_int64_t)nap->na_bytes != thyp)
   1637 					*retcmpp = NFSERR_NOTSAME;
   1638 			    }
   1639 			} else if (nap != NULL) {
   1640 				nap->na_bytes = thyp;
   1641 			}
   1642 			attrsum += NFSX_HYPER;
   1643 			break;
   1644 		case NFSATTRBIT_SYSTEM:
   1645 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1646 			if (compare && !(*retcmpp))
   1647 				*retcmpp = NFSERR_ATTRNOTSUPP;
   1648 			attrsum += NFSX_UNSIGNED;
   1649 			break;
   1650 		case NFSATTRBIT_TIMEACCESS:
   1651 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   1652 			fxdr_nfsv4time(tl, &temptime);
   1653 			if (compare) {
   1654 			    if (!(*retcmpp)) {
   1655 				if (!NFS_CMPTIME(temptime, nap->na_atime))
   1656 					*retcmpp = NFSERR_NOTSAME;
   1657 			    }
   1658 			} else if (nap != NULL) {
   1659 				nap->na_atime = temptime;
   1660 			}
   1661 			attrsum += NFSX_V4TIME;
   1662 			break;
   1663 		case NFSATTRBIT_TIMEACCESSSET:
   1664 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1665 			attrsum += NFSX_UNSIGNED;
   1666 			i = fxdr_unsigned(int, *tl);
   1667 			if (i == NFSV4SATTRTIME_TOCLIENT) {
   1668 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   1669 				attrsum += NFSX_V4TIME;
   1670 			}
   1671 			if (compare && !(*retcmpp))
   1672 				*retcmpp = NFSERR_INVAL;
   1673 			break;
   1674 		case NFSATTRBIT_TIMEBACKUP:
   1675 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   1676 			if (compare && !(*retcmpp))
   1677 				*retcmpp = NFSERR_ATTRNOTSUPP;
   1678 			attrsum += NFSX_V4TIME;
   1679 			break;
   1680 		case NFSATTRBIT_TIMECREATE:
   1681 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   1682 			if (compare && !(*retcmpp))
   1683 				*retcmpp = NFSERR_ATTRNOTSUPP;
   1684 			attrsum += NFSX_V4TIME;
   1685 			break;
   1686 		case NFSATTRBIT_TIMEDELTA:
   1687 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   1688 			if (fsp != NULL) {
   1689 			    if (compare) {
   1690 				if (!(*retcmpp)) {
   1691 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
   1692 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
   1693 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
   1694 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
   1695 					 1000000000) ||
   1696 					*tl != 0)
   1697 					    *retcmpp = NFSERR_NOTSAME;
   1698 				}
   1699 			    } else {
   1700 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
   1701 			    }
   1702 			}
   1703 			attrsum += NFSX_V4TIME;
   1704 			break;
   1705 		case NFSATTRBIT_TIMEMETADATA:
   1706 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   1707 			fxdr_nfsv4time(tl, &temptime);
   1708 			if (compare) {
   1709 			    if (!(*retcmpp)) {
   1710 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
   1711 					*retcmpp = NFSERR_NOTSAME;
   1712 			    }
   1713 			} else if (nap != NULL) {
   1714 				nap->na_ctime = temptime;
   1715 			}
   1716 			attrsum += NFSX_V4TIME;
   1717 			break;
   1718 		case NFSATTRBIT_TIMEMODIFY:
   1719 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   1720 			fxdr_nfsv4time(tl, &temptime);
   1721 			if (compare) {
   1722 			    if (!(*retcmpp)) {
   1723 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
   1724 					*retcmpp = NFSERR_NOTSAME;
   1725 			    }
   1726 			} else if (nap != NULL) {
   1727 				nap->na_mtime = temptime;
   1728 			}
   1729 			attrsum += NFSX_V4TIME;
   1730 			break;
   1731 		case NFSATTRBIT_TIMEMODIFYSET:
   1732 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1733 			attrsum += NFSX_UNSIGNED;
   1734 			i = fxdr_unsigned(int, *tl);
   1735 			if (i == NFSV4SATTRTIME_TOCLIENT) {
   1736 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   1737 				attrsum += NFSX_V4TIME;
   1738 			}
   1739 			if (compare && !(*retcmpp))
   1740 				*retcmpp = NFSERR_INVAL;
   1741 			break;
   1742 		case NFSATTRBIT_MOUNTEDONFILEID:
   1743 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   1744 			thyp = fxdr_hyper(tl);
   1745 			if (compare) {
   1746 			    if (!(*retcmpp)) {
   1747 				if (*tl++) {
   1748 					*retcmpp = NFSERR_NOTSAME;
   1749 				} else {
   1750 					if (!vp || !nfsrv_atroot(vp, &fid))
   1751 						fid = nap->na_fileid;
   1752 					if ((u_int64_t)fid != thyp)
   1753 						*retcmpp = NFSERR_NOTSAME;
   1754 				}
   1755 			    }
   1756 			} else if (nap != NULL) {
   1757 			    if (*tl++) {
   1758 				count64mountfileid++;
   1759 				if (ratecheck(&last64mountfileid, &warninterval)) {
   1760 					printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
   1761 					    count64mountfileid);
   1762 					count64mountfileid = 0;
   1763 				}
   1764 			    }
   1765 			    nap->na_mntonfileno = thyp;
   1766 			}
   1767 			attrsum += NFSX_HYPER;
   1768 			break;
   1769 		case NFSATTRBIT_SUPPATTREXCLCREAT:
   1770 			retnotsup = 0;
   1771 			error = nfsrv_getattrbits(nd, &retattrbits,
   1772 			    &cnt, &retnotsup);
   1773 			if (error)
   1774 			    goto nfsmout;
   1775 			if (compare && !(*retcmpp)) {
   1776 			   NFSSETSUPP_ATTRBIT(&checkattrbits);
   1777 			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
   1778 			   NFSCLRBIT_ATTRBIT(&checkattrbits,
   1779 				NFSATTRBIT_TIMEACCESSSET);
   1780 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
   1781 			       || retnotsup)
   1782 				*retcmpp = NFSERR_NOTSAME;
   1783 			}
   1784 			attrsum += cnt;
   1785 			break;
   1786 		default:
   1787 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
   1788 				bitpos);
   1789 			if (compare && !(*retcmpp))
   1790 				*retcmpp = NFSERR_ATTRNOTSUPP;
   1791 			/*
   1792 			 * and get out of the loop, since we can't parse
   1793 			 * the unknown attrbute data.
   1794 			 */
   1795 			bitpos = NFSATTRBIT_MAX;
   1796 			break;
   1797 		}
   1798 	}
   1799 
   1800 	/*
   1801 	 * some clients pad the attrlist, so we need to skip over the
   1802 	 * padding.
   1803 	 */
   1804 	if (attrsum > attrsize) {
   1805 		error = NFSERR_BADXDR;
   1806 	} else {
   1807 		attrsize = NFSM_RNDUP(attrsize);
   1808 		if (attrsum < attrsize)
   1809 			error = nfsm_advance(nd, attrsize - attrsum, -1);
   1810 	}
   1811 nfsmout:
   1812 	NFSEXITCODE2(error, nd);
   1813 	return (error);
   1814 }
   1815 
   1816 /*
   1817  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
   1818  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
   1819  * The first argument is a pointer to an nfsv4lock structure.
   1820  * The second argument is 1 iff a blocking lock is wanted.
   1821  * If this argument is 0, the call waits until no thread either wants nor
   1822  * holds an exclusive lock.
   1823  * It returns 1 if the lock was acquired, 0 otherwise.
   1824  * If several processes call this function concurrently wanting the exclusive
   1825  * lock, one will get the lock and the rest will return without getting the
   1826  * lock. (If the caller must have the lock, it simply calls this function in a
   1827  *  loop until the function returns 1 to indicate the lock was acquired.)
   1828  * Any usecnt must be decremented by calling nfsv4_relref() before
   1829  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
   1830  * be called in a loop.
   1831  * The isleptp argument is set to indicate if the call slept, iff not NULL
   1832  * and the mp argument indicates to check for a forced dismount, iff not
   1833  * NULL.
   1834  */
   1835 APPLESTATIC int
   1836 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
   1837     void *mutex, struct mount *mp)
   1838 {
   1839 
   1840 	if (isleptp)
   1841 		*isleptp = 0;
   1842 	/*
   1843 	 * If a lock is wanted, loop around until the lock is acquired by
   1844 	 * someone and then released. If I want the lock, try to acquire it.
   1845 	 * For a lock to be issued, no lock must be in force and the usecnt
   1846 	 * must be zero.
   1847 	 */
   1848 	if (iwantlock) {
   1849 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
   1850 		lp->nfslock_usecnt == 0) {
   1851 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
   1852 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
   1853 		return (1);
   1854 	    }
   1855 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
   1856 	}
   1857 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
   1858 		if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
   1859 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
   1860 			return (0);
   1861 		}
   1862 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
   1863 		if (isleptp)
   1864 			*isleptp = 1;
   1865 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
   1866 		    PZERO - 1, "nfsv4lck", NULL);
   1867 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
   1868 		    lp->nfslock_usecnt == 0) {
   1869 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
   1870 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
   1871 			return (1);
   1872 		}
   1873 	}
   1874 	return (0);
   1875 }
   1876 
   1877 /*
   1878  * Release the lock acquired by nfsv4_lock().
   1879  * The second argument is set to 1 to indicate the nfslock_usecnt should be
   1880  * incremented, as well.
   1881  */
   1882 APPLESTATIC void
   1883 nfsv4_unlock(struct nfsv4lock *lp, int incref)
   1884 {
   1885 
   1886 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
   1887 	if (incref)
   1888 		lp->nfslock_usecnt++;
   1889 	nfsv4_wanted(lp);
   1890 }
   1891 
   1892 /*
   1893  * Release a reference cnt.
   1894  */
   1895 APPLESTATIC void
   1896 nfsv4_relref(struct nfsv4lock *lp)
   1897 {
   1898 
   1899 	if (lp->nfslock_usecnt <= 0)
   1900 		panic("nfsv4root ref cnt");
   1901 	lp->nfslock_usecnt--;
   1902 	if (lp->nfslock_usecnt == 0)
   1903 		nfsv4_wanted(lp);
   1904 }
   1905 
   1906 /*
   1907  * Get a reference cnt.
   1908  * This function will wait for any exclusive lock to be released, but will
   1909  * not wait for threads that want the exclusive lock. If priority needs
   1910  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
   1911  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
   1912  * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
   1913  * return without getting a refcnt for that case.
   1914  */
   1915 APPLESTATIC void
   1916 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
   1917     struct mount *mp)
   1918 {
   1919 
   1920 	if (isleptp)
   1921 		*isleptp = 0;
   1922 
   1923 	/*
   1924 	 * Wait for a lock held.
   1925 	 */
   1926 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
   1927 		if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
   1928 			return;
   1929 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
   1930 		if (isleptp)
   1931 			*isleptp = 1;
   1932 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
   1933 		    PZERO - 1, "nfsv4gr", NULL);
   1934 	}
   1935 	if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
   1936 		return;
   1937 
   1938 	lp->nfslock_usecnt++;
   1939 }
   1940 
   1941 /*
   1942  * Get a reference as above, but return failure instead of sleeping if
   1943  * an exclusive lock is held.
   1944  */
   1945 APPLESTATIC int
   1946 nfsv4_getref_nonblock(struct nfsv4lock *lp)
   1947 {
   1948 
   1949 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
   1950 		return (0);
   1951 
   1952 	lp->nfslock_usecnt++;
   1953 	return (1);
   1954 }
   1955 
   1956 /*
   1957  * Test for a lock. Return 1 if locked, 0 otherwise.
   1958  */
   1959 APPLESTATIC int
   1960 nfsv4_testlock(struct nfsv4lock *lp)
   1961 {
   1962 
   1963 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
   1964 	    lp->nfslock_usecnt == 0)
   1965 		return (0);
   1966 	return (1);
   1967 }
   1968 
   1969 /*
   1970  * Wake up anyone sleeping, waiting for this lock.
   1971  */
   1972 static void
   1973 nfsv4_wanted(struct nfsv4lock *lp)
   1974 {
   1975 
   1976 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
   1977 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
   1978 		wakeup((caddr_t)&lp->nfslock_lock);
   1979 	}
   1980 }
   1981 
   1982 /*
   1983  * Copy a string from an mbuf list into a character array.
   1984  * Return EBADRPC if there is an mbuf error,
   1985  * 0 otherwise.
   1986  */
   1987 APPLESTATIC int
   1988 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
   1989 {
   1990 	char *cp;
   1991 	int xfer, len;
   1992 	mbuf_t mp;
   1993 	int rem, error = 0;
   1994 
   1995 	mp = nd->nd_md;
   1996 	cp = nd->nd_dpos;
   1997 	len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
   1998 	rem = NFSM_RNDUP(siz) - siz;
   1999 	while (siz > 0) {
   2000 		if (len > siz)
   2001 			xfer = siz;
   2002 		else
   2003 			xfer = len;
   2004 		NFSBCOPY(cp, str, xfer);
   2005 		str += xfer;
   2006 		siz -= xfer;
   2007 		if (siz > 0) {
   2008 			mp = mbuf_next(mp);
   2009 			if (mp == NULL) {
   2010 				error = EBADRPC;
   2011 				goto out;
   2012 			}
   2013 			cp = NFSMTOD(mp, caddr_t);
   2014 			len = mbuf_len(mp);
   2015 		} else {
   2016 			cp += xfer;
   2017 			len -= xfer;
   2018 		}
   2019 	}
   2020 	*str = '\0';
   2021 	nd->nd_dpos = cp;
   2022 	nd->nd_md = mp;
   2023 	if (rem > 0) {
   2024 		if (len < rem)
   2025 			error = nfsm_advance(nd, rem, len);
   2026 		else
   2027 			nd->nd_dpos += rem;
   2028 	}
   2029 
   2030 out:
   2031 	NFSEXITCODE2(error, nd);
   2032 	return (error);
   2033 }
   2034 
   2035 /*
   2036  * Fill in the attributes as marked by the bitmap (V4).
   2037  */
   2038 APPLESTATIC int
   2039 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
   2040     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
   2041     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
   2042     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
   2043 {
   2044 	int bitpos, retnum = 0;
   2045 	u_int32_t *tl;
   2046 	int siz, prefixnum, error;
   2047 	u_char *cp, namestr[NFSV4_SMALLSTR];
   2048 	nfsattrbit_t attrbits, retbits;
   2049 	nfsattrbit_t *retbitp = &retbits;
   2050 	u_int32_t freenum, *retnump;
   2051 	u_int64_t uquad;
   2052 	struct statfs fs;
   2053 	struct nfsfsinfo fsinf;
   2054 	struct timespec temptime;
   2055 	NFSACL_T *aclp, *naclp = NULL;
   2056 #ifdef QUOTA
   2057 	struct dqblk dqb;
   2058 	uid_t savuid;
   2059 #endif
   2060 
   2061 	/*
   2062 	 * First, set the bits that can be filled and get fsinfo.
   2063 	 */
   2064 	NFSSET_ATTRBIT(retbitp, attrbitp);
   2065 	/*
   2066 	 * If both p and cred are NULL, it is a client side setattr call.
   2067 	 * If both p and cred are not NULL, it is a server side reply call.
   2068 	 * If p is not NULL and cred is NULL, it is a client side callback
   2069 	 * reply call.
   2070 	 */
   2071 	if (p == NULL && cred == NULL) {
   2072 		NFSCLRNOTSETABLE_ATTRBIT(retbitp);
   2073 		aclp = saclp;
   2074 	} else {
   2075 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
   2076 		naclp = acl_alloc(M_WAITOK);
   2077 		aclp = naclp;
   2078 	}
   2079 	nfsvno_getfs(&fsinf, isdgram);
   2080 #ifndef APPLE
   2081 	/*
   2082 	 * Get the VFS_STATFS(), since some attributes need them.
   2083 	 */
   2084 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
   2085 		error = VFS_STATFS(mp, &fs);
   2086 		if (error != 0) {
   2087 			if (reterr) {
   2088 				nd->nd_repstat = NFSERR_ACCES;
   2089 				return (0);
   2090 			}
   2091 			NFSCLRSTATFS_ATTRBIT(retbitp);
   2092 		}
   2093 	}
   2094 #endif
   2095 
   2096 	/*
   2097 	 * And the NFSv4 ACL...
   2098 	 */
   2099 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
   2100 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
   2101 		supports_nfsv4acls == 0))) {
   2102 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
   2103 	}
   2104 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
   2105 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
   2106 		    supports_nfsv4acls == 0)) {
   2107 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
   2108 		} else if (naclp != NULL) {
   2109 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
   2110 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
   2111 				if (error == 0)
   2112 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
   2113 					    naclp, cred, p);
   2114 				NFSVOPUNLOCK(vp, 0);
   2115 			} else
   2116 				error = NFSERR_PERM;
   2117 			if (error != 0) {
   2118 				if (reterr) {
   2119 					nd->nd_repstat = NFSERR_ACCES;
   2120 					return (0);
   2121 				}
   2122 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
   2123 			}
   2124 		}
   2125 	}
   2126 
   2127 	/*
   2128 	 * Put out the attribute bitmap for the ones being filled in
   2129 	 * and get the field for the number of attributes returned.
   2130 	 */
   2131 	prefixnum = nfsrv_putattrbit(nd, retbitp);
   2132 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
   2133 	prefixnum += NFSX_UNSIGNED;
   2134 
   2135 	/*
   2136 	 * Now, loop around filling in the attributes for each bit set.
   2137 	 */
   2138 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
   2139 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
   2140 		switch (bitpos) {
   2141 		case NFSATTRBIT_SUPPORTEDATTRS:
   2142 			NFSSETSUPP_ATTRBIT(&attrbits);
   2143 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
   2144 			    && supports_nfsv4acls == 0)) {
   2145 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
   2146 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
   2147 			}
   2148 			retnum += nfsrv_putattrbit(nd, &attrbits);
   2149 			break;
   2150 		case NFSATTRBIT_TYPE:
   2151 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2152 			*tl = vtonfsv34_type(vap->va_type);
   2153 			retnum += NFSX_UNSIGNED;
   2154 			break;
   2155 		case NFSATTRBIT_FHEXPIRETYPE:
   2156 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2157 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
   2158 			retnum += NFSX_UNSIGNED;
   2159 			break;
   2160 		case NFSATTRBIT_CHANGE:
   2161 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2162 			txdr_hyper(vap->va_filerev, tl);
   2163 			retnum += NFSX_HYPER;
   2164 			break;
   2165 		case NFSATTRBIT_SIZE:
   2166 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2167 			txdr_hyper(vap->va_size, tl);
   2168 			retnum += NFSX_HYPER;
   2169 			break;
   2170 		case NFSATTRBIT_LINKSUPPORT:
   2171 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2172 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
   2173 				*tl = newnfs_true;
   2174 			else
   2175 				*tl = newnfs_false;
   2176 			retnum += NFSX_UNSIGNED;
   2177 			break;
   2178 		case NFSATTRBIT_SYMLINKSUPPORT:
   2179 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2180 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
   2181 				*tl = newnfs_true;
   2182 			else
   2183 				*tl = newnfs_false;
   2184 			retnum += NFSX_UNSIGNED;
   2185 			break;
   2186 		case NFSATTRBIT_NAMEDATTR:
   2187 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2188 			*tl = newnfs_false;
   2189 			retnum += NFSX_UNSIGNED;
   2190 			break;
   2191 		case NFSATTRBIT_FSID:
   2192 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
   2193 			*tl++ = 0;
   2194 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
   2195 			*tl++ = 0;
   2196 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
   2197 			retnum += NFSX_V4FSID;
   2198 			break;
   2199 		case NFSATTRBIT_UNIQUEHANDLES:
   2200 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2201 			*tl = newnfs_true;
   2202 			retnum += NFSX_UNSIGNED;
   2203 			break;
   2204 		case NFSATTRBIT_LEASETIME:
   2205 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2206 			*tl = txdr_unsigned(nfsrv_lease);
   2207 			retnum += NFSX_UNSIGNED;
   2208 			break;
   2209 		case NFSATTRBIT_RDATTRERROR:
   2210 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2211 			*tl = txdr_unsigned(rderror);
   2212 			retnum += NFSX_UNSIGNED;
   2213 			break;
   2214 		/*
   2215 		 * Recommended Attributes. (Only the supported ones.)
   2216 		 */
   2217 		case NFSATTRBIT_ACL:
   2218 			retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
   2219 			break;
   2220 		case NFSATTRBIT_ACLSUPPORT:
   2221 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2222 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
   2223 			retnum += NFSX_UNSIGNED;
   2224 			break;
   2225 		case NFSATTRBIT_CANSETTIME:
   2226 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2227 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
   2228 				*tl = newnfs_true;
   2229 			else
   2230 				*tl = newnfs_false;
   2231 			retnum += NFSX_UNSIGNED;
   2232 			break;
   2233 		case NFSATTRBIT_CASEINSENSITIVE:
   2234 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2235 			*tl = newnfs_false;
   2236 			retnum += NFSX_UNSIGNED;
   2237 			break;
   2238 		case NFSATTRBIT_CASEPRESERVING:
   2239 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2240 			*tl = newnfs_true;
   2241 			retnum += NFSX_UNSIGNED;
   2242 			break;
   2243 		case NFSATTRBIT_CHOWNRESTRICTED:
   2244 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2245 			*tl = newnfs_true;
   2246 			retnum += NFSX_UNSIGNED;
   2247 			break;
   2248 		case NFSATTRBIT_FILEHANDLE:
   2249 			retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
   2250 			break;
   2251 		case NFSATTRBIT_FILEID:
   2252 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2253 			*tl++ = 0;
   2254 			*tl = txdr_unsigned(vap->va_fileid);
   2255 			retnum += NFSX_HYPER;
   2256 			break;
   2257 		case NFSATTRBIT_FILESAVAIL:
   2258 			/*
   2259 			 * Check quota and use min(quota, f_ffree).
   2260 			 */
   2261 			freenum = fs.f_ffree;
   2262 #ifdef QUOTA
   2263 			/*
   2264 			 * ufs_quotactl() insists that the uid argument
   2265 			 * equal p_ruid for non-root quota access, so
   2266 			 * we'll just make sure that's the case.
   2267 			 */
   2268 			savuid = p->p_cred->p_ruid;
   2269 			p->p_cred->p_ruid = cred->cr_uid;
   2270 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
   2271 			    cred->cr_uid, (caddr_t)&dqb))
   2272 			    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
   2273 				freenum);
   2274 			p->p_cred->p_ruid = savuid;
   2275 #endif	/* QUOTA */
   2276 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2277 			*tl++ = 0;
   2278 			*tl = txdr_unsigned(freenum);
   2279 			retnum += NFSX_HYPER;
   2280 			break;
   2281 		case NFSATTRBIT_FILESFREE:
   2282 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2283 			*tl++ = 0;
   2284 			*tl = txdr_unsigned(fs.f_ffree);
   2285 			retnum += NFSX_HYPER;
   2286 			break;
   2287 		case NFSATTRBIT_FILESTOTAL:
   2288 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2289 			*tl++ = 0;
   2290 			*tl = txdr_unsigned(fs.f_files);
   2291 			retnum += NFSX_HYPER;
   2292 			break;
   2293 		case NFSATTRBIT_FSLOCATIONS:
   2294 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2295 			*tl++ = 0;
   2296 			*tl = 0;
   2297 			retnum += 2 * NFSX_UNSIGNED;
   2298 			break;
   2299 		case NFSATTRBIT_HOMOGENEOUS:
   2300 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2301 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
   2302 				*tl = newnfs_true;
   2303 			else
   2304 				*tl = newnfs_false;
   2305 			retnum += NFSX_UNSIGNED;
   2306 			break;
   2307 		case NFSATTRBIT_MAXFILESIZE:
   2308 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2309 			uquad = NFSRV_MAXFILESIZE;
   2310 			txdr_hyper(uquad, tl);
   2311 			retnum += NFSX_HYPER;
   2312 			break;
   2313 		case NFSATTRBIT_MAXLINK:
   2314 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2315 			*tl = txdr_unsigned(LINK_MAX);
   2316 			retnum += NFSX_UNSIGNED;
   2317 			break;
   2318 		case NFSATTRBIT_MAXNAME:
   2319 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2320 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
   2321 			retnum += NFSX_UNSIGNED;
   2322 			break;
   2323 		case NFSATTRBIT_MAXREAD:
   2324 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2325 			*tl++ = 0;
   2326 			*tl = txdr_unsigned(fsinf.fs_rtmax);
   2327 			retnum += NFSX_HYPER;
   2328 			break;
   2329 		case NFSATTRBIT_MAXWRITE:
   2330 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2331 			*tl++ = 0;
   2332 			*tl = txdr_unsigned(fsinf.fs_wtmax);
   2333 			retnum += NFSX_HYPER;
   2334 			break;
   2335 		case NFSATTRBIT_MODE:
   2336 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2337 			*tl = vtonfsv34_mode(vap->va_mode);
   2338 			retnum += NFSX_UNSIGNED;
   2339 			break;
   2340 		case NFSATTRBIT_NOTRUNC:
   2341 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2342 			*tl = newnfs_true;
   2343 			retnum += NFSX_UNSIGNED;
   2344 			break;
   2345 		case NFSATTRBIT_NUMLINKS:
   2346 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2347 			*tl = txdr_unsigned(vap->va_nlink);
   2348 			retnum += NFSX_UNSIGNED;
   2349 			break;
   2350 		case NFSATTRBIT_OWNER:
   2351 			cp = namestr;
   2352 			nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
   2353 			retnum += nfsm_strtom(nd, cp, siz);
   2354 			if (cp != namestr)
   2355 				free(cp, M_NFSSTRING);
   2356 			break;
   2357 		case NFSATTRBIT_OWNERGROUP:
   2358 			cp = namestr;
   2359 			nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
   2360 			retnum += nfsm_strtom(nd, cp, siz);
   2361 			if (cp != namestr)
   2362 				free(cp, M_NFSSTRING);
   2363 			break;
   2364 		case NFSATTRBIT_QUOTAHARD:
   2365 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
   2366 				freenum = fs.f_bfree;
   2367 			else
   2368 				freenum = fs.f_bavail;
   2369 #ifdef QUOTA
   2370 			/*
   2371 			 * ufs_quotactl() insists that the uid argument
   2372 			 * equal p_ruid for non-root quota access, so
   2373 			 * we'll just make sure that's the case.
   2374 			 */
   2375 			savuid = p->p_cred->p_ruid;
   2376 			p->p_cred->p_ruid = cred->cr_uid;
   2377 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
   2378 			    cred->cr_uid, (caddr_t)&dqb))
   2379 			    freenum = min(dqb.dqb_bhardlimit, freenum);
   2380 			p->p_cred->p_ruid = savuid;
   2381 #endif	/* QUOTA */
   2382 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2383 			uquad = (u_int64_t)freenum;
   2384 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
   2385 			txdr_hyper(uquad, tl);
   2386 			retnum += NFSX_HYPER;
   2387 			break;
   2388 		case NFSATTRBIT_QUOTASOFT:
   2389 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
   2390 				freenum = fs.f_bfree;
   2391 			else
   2392 				freenum = fs.f_bavail;
   2393 #ifdef QUOTA
   2394 			/*
   2395 			 * ufs_quotactl() insists that the uid argument
   2396 			 * equal p_ruid for non-root quota access, so
   2397 			 * we'll just make sure that's the case.
   2398 			 */
   2399 			savuid = p->p_cred->p_ruid;
   2400 			p->p_cred->p_ruid = cred->cr_uid;
   2401 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
   2402 			    cred->cr_uid, (caddr_t)&dqb))
   2403 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
   2404 			p->p_cred->p_ruid = savuid;
   2405 #endif	/* QUOTA */
   2406 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2407 			uquad = (u_int64_t)freenum;
   2408 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
   2409 			txdr_hyper(uquad, tl);
   2410 			retnum += NFSX_HYPER;
   2411 			break;
   2412 		case NFSATTRBIT_QUOTAUSED:
   2413 			freenum = 0;
   2414 #ifdef QUOTA
   2415 			/*
   2416 			 * ufs_quotactl() insists that the uid argument
   2417 			 * equal p_ruid for non-root quota access, so
   2418 			 * we'll just make sure that's the case.
   2419 			 */
   2420 			savuid = p->p_cred->p_ruid;
   2421 			p->p_cred->p_ruid = cred->cr_uid;
   2422 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
   2423 			    cred->cr_uid, (caddr_t)&dqb))
   2424 			    freenum = dqb.dqb_curblocks;
   2425 			p->p_cred->p_ruid = savuid;
   2426 #endif	/* QUOTA */
   2427 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2428 			uquad = (u_int64_t)freenum;
   2429 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
   2430 			txdr_hyper(uquad, tl);
   2431 			retnum += NFSX_HYPER;
   2432 			break;
   2433 		case NFSATTRBIT_RAWDEV:
   2434 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
   2435 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
   2436 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
   2437 			retnum += NFSX_V4SPECDATA;
   2438 			break;
   2439 		case NFSATTRBIT_SPACEAVAIL:
   2440 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2441 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
   2442 				uquad = (u_int64_t)fs.f_bfree;
   2443 			else
   2444 				uquad = (u_int64_t)fs.f_bavail;
   2445 			uquad *= fs.f_bsize;
   2446 			txdr_hyper(uquad, tl);
   2447 			retnum += NFSX_HYPER;
   2448 			break;
   2449 		case NFSATTRBIT_SPACEFREE:
   2450 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2451 			uquad = (u_int64_t)fs.f_bfree;
   2452 			uquad *= fs.f_bsize;
   2453 			txdr_hyper(uquad, tl);
   2454 			retnum += NFSX_HYPER;
   2455 			break;
   2456 		case NFSATTRBIT_SPACETOTAL:
   2457 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2458 			uquad = (u_int64_t)fs.f_blocks;
   2459 			uquad *= fs.f_bsize;
   2460 			txdr_hyper(uquad, tl);
   2461 			retnum += NFSX_HYPER;
   2462 			break;
   2463 		case NFSATTRBIT_SPACEUSED:
   2464 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2465 			txdr_hyper(vap->va_bytes, tl);
   2466 			retnum += NFSX_HYPER;
   2467 			break;
   2468 		case NFSATTRBIT_TIMEACCESS:
   2469 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
   2470 			txdr_nfsv4time(&vap->va_atime, tl);
   2471 			retnum += NFSX_V4TIME;
   2472 			break;
   2473 		case NFSATTRBIT_TIMEACCESSSET:
   2474 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
   2475 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
   2476 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
   2477 				txdr_nfsv4time(&vap->va_atime, tl);
   2478 				retnum += NFSX_V4SETTIME;
   2479 			} else {
   2480 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2481 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
   2482 				retnum += NFSX_UNSIGNED;
   2483 			}
   2484 			break;
   2485 		case NFSATTRBIT_TIMEDELTA:
   2486 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
   2487 			temptime.tv_sec = 0;
   2488 			temptime.tv_nsec = 1000000000 / hz;
   2489 			txdr_nfsv4time(&temptime, tl);
   2490 			retnum += NFSX_V4TIME;
   2491 			break;
   2492 		case NFSATTRBIT_TIMEMETADATA:
   2493 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
   2494 			txdr_nfsv4time(&vap->va_ctime, tl);
   2495 			retnum += NFSX_V4TIME;
   2496 			break;
   2497 		case NFSATTRBIT_TIMEMODIFY:
   2498 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
   2499 			txdr_nfsv4time(&vap->va_mtime, tl);
   2500 			retnum += NFSX_V4TIME;
   2501 			break;
   2502 		case NFSATTRBIT_TIMEMODIFYSET:
   2503 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
   2504 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
   2505 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
   2506 				txdr_nfsv4time(&vap->va_mtime, tl);
   2507 				retnum += NFSX_V4SETTIME;
   2508 			} else {
   2509 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2510 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
   2511 				retnum += NFSX_UNSIGNED;
   2512 			}
   2513 			break;
   2514 		case NFSATTRBIT_MOUNTEDONFILEID:
   2515 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
   2516 			if (at_root != 0)
   2517 				uquad = mounted_on_fileno;
   2518 			else
   2519 				uquad = (u_int64_t)vap->va_fileid;
   2520 			txdr_hyper(uquad, tl);
   2521 			retnum += NFSX_HYPER;
   2522 			break;
   2523 		case NFSATTRBIT_SUPPATTREXCLCREAT:
   2524 			NFSSETSUPP_ATTRBIT(&attrbits);
   2525 			NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
   2526 			NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
   2527 			retnum += nfsrv_putattrbit(nd, &attrbits);
   2528 			break;
   2529 		default:
   2530 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
   2531 		}
   2532 	    }
   2533 	}
   2534 	if (naclp != NULL)
   2535 		acl_free(naclp);
   2536 	*retnump = txdr_unsigned(retnum);
   2537 	return (retnum + prefixnum);
   2538 }
   2539 
   2540 /*
   2541  * Put the attribute bits onto an mbuf list.
   2542  * Return the number of bytes of output generated.
   2543  */
   2544 APPLESTATIC int
   2545 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
   2546 {
   2547 	u_int32_t *tl;
   2548 	int cnt, i, bytesize;
   2549 
   2550 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
   2551 		if (attrbitp->bits[cnt - 1])
   2552 			break;
   2553 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
   2554 	NFSM_BUILD(tl, u_int32_t *, bytesize);
   2555 	*tl++ = txdr_unsigned(cnt);
   2556 	for (i = 0; i < cnt; i++)
   2557 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
   2558 	return (bytesize);
   2559 }
   2560 
   2561 /*
   2562  * Convert a uid to a string.
   2563  * If the lookup fails, just output the digits.
   2564  * uid - the user id
   2565  * cpp - points to a buffer of size NFSV4_SMALLSTR
   2566  *       (malloc a larger one, as required)
   2567  * retlenp - pointer to length to be returned
   2568  */
   2569 APPLESTATIC void
   2570 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
   2571 {
   2572 	int i;
   2573 	struct nfsusrgrp *usrp;
   2574 	u_char *cp = *cpp;
   2575 	uid_t tmp;
   2576 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
   2577 	struct nfsrv_lughash *hp;
   2578 
   2579 	cnt = 0;
   2580 tryagain:
   2581 	if (nfsrv_dnsnamelen > 0) {
   2582 		/*
   2583 		 * Always map nfsrv_defaultuid to "nobody".
   2584 		 */
   2585 		if (uid == nfsrv_defaultuid) {
   2586 			i = nfsrv_dnsnamelen + 7;
   2587 			if (i > len) {
   2588 				if (len > NFSV4_SMALLSTR)
   2589 					free(cp, M_NFSSTRING);
   2590 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
   2591 				*cpp = cp;
   2592 				len = i;
   2593 				goto tryagain;
   2594 			}
   2595 			*retlenp = i;
   2596 			NFSBCOPY("nobody@", cp, 7);
   2597 			cp += 7;
   2598 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
   2599 			return;
   2600 		}
   2601 		hasampersand = 0;
   2602 		hp = NFSUSERHASH(uid);
   2603 		mtx_lock(&hp->mtx);
   2604 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
   2605 			if (usrp->lug_uid == uid) {
   2606 				if (usrp->lug_expiry < NFSD_MONOSEC)
   2607 					break;
   2608 				/*
   2609 				 * If the name doesn't already have an '@'
   2610 				 * in it, append @domainname to it.
   2611 				 */
   2612 				for (i = 0; i < usrp->lug_namelen; i++) {
   2613 					if (usrp->lug_name[i] == '@') {
   2614 						hasampersand = 1;
   2615 						break;
   2616 					}
   2617 				}
   2618 				if (hasampersand)
   2619 					i = usrp->lug_namelen;
   2620 				else
   2621 					i = usrp->lug_namelen +
   2622 					    nfsrv_dnsnamelen + 1;
   2623 				if (i > len) {
   2624 					mtx_unlock(&hp->mtx);
   2625 					if (len > NFSV4_SMALLSTR)
   2626 						free(cp, M_NFSSTRING);
   2627 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
   2628 					*cpp = cp;
   2629 					len = i;
   2630 					goto tryagain;
   2631 				}
   2632 				*retlenp = i;
   2633 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
   2634 				if (!hasampersand) {
   2635 					cp += usrp->lug_namelen;
   2636 					*cp++ = '@';
   2637 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
   2638 				}
   2639 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
   2640 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
   2641 				    lug_numhash);
   2642 				mtx_unlock(&hp->mtx);
   2643 				return;
   2644 			}
   2645 		}
   2646 		mtx_unlock(&hp->mtx);
   2647 		cnt++;
   2648 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
   2649 		    NULL, p);
   2650 		if (ret == 0 && cnt < 2)
   2651 			goto tryagain;
   2652 	}
   2653 
   2654 	/*
   2655 	 * No match, just return a string of digits.
   2656 	 */
   2657 	tmp = uid;
   2658 	i = 0;
   2659 	while (tmp || i == 0) {
   2660 		tmp /= 10;
   2661 		i++;
   2662 	}
   2663 	len = (i > len) ? len : i;
   2664 	*retlenp = len;
   2665 	cp += (len - 1);
   2666 	tmp = uid;
   2667 	for (i = 0; i < len; i++) {
   2668 		*cp-- = '0' + (tmp % 10);
   2669 		tmp /= 10;
   2670 	}
   2671 	return;
   2672 }
   2673 
   2674 /*
   2675  * Get a credential for the uid with the server's group list.
   2676  * If none is found, just return the credential passed in after
   2677  * logging a warning message.
   2678  */
   2679 struct ucred *
   2680 nfsrv_getgrpscred(struct ucred *oldcred)
   2681 {
   2682 	struct nfsusrgrp *usrp;
   2683 	struct ucred *newcred;
   2684 	int cnt, ret;
   2685 	uid_t uid;
   2686 	struct nfsrv_lughash *hp;
   2687 
   2688 	cnt = 0;
   2689 	uid = oldcred->cr_uid;
   2690 tryagain:
   2691 	if (nfsrv_dnsnamelen > 0) {
   2692 		hp = NFSUSERHASH(uid);
   2693 		mtx_lock(&hp->mtx);
   2694 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
   2695 			if (usrp->lug_uid == uid) {
   2696 				if (usrp->lug_expiry < NFSD_MONOSEC)
   2697 					break;
   2698 				if (usrp->lug_cred != NULL) {
   2699 					newcred = crhold(usrp->lug_cred);
   2700 					crfree(oldcred);
   2701 				} else
   2702 					newcred = oldcred;
   2703 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
   2704 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
   2705 				    lug_numhash);
   2706 				mtx_unlock(&hp->mtx);
   2707 				return (newcred);
   2708 			}
   2709 		}
   2710 		mtx_unlock(&hp->mtx);
   2711 		cnt++;
   2712 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
   2713 		    NULL, curthread);
   2714 		if (ret == 0 && cnt < 2)
   2715 			goto tryagain;
   2716 	}
   2717 	return (oldcred);
   2718 }
   2719 
   2720 /*
   2721  * Convert a string to a uid.
   2722  * If no conversion is possible return NFSERR_BADOWNER, otherwise
   2723  * return 0.
   2724  * If this is called from a client side mount using AUTH_SYS and the
   2725  * string is made up entirely of digits, just convert the string to
   2726  * a number.
   2727  */
   2728 APPLESTATIC int
   2729 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
   2730     NFSPROC_T *p)
   2731 {
   2732 	int i;
   2733 	char *cp, *endstr, *str0;
   2734 	struct nfsusrgrp *usrp;
   2735 	int cnt, ret;
   2736 	int error = 0;
   2737 	uid_t tuid;
   2738 	struct nfsrv_lughash *hp, *hp2;
   2739 
   2740 	if (len == 0) {
   2741 		error = NFSERR_BADOWNER;
   2742 		goto out;
   2743 	}
   2744 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
   2745 	str0 = str;
   2746 	tuid = (uid_t)strtoul(str0, &endstr, 10);
   2747 	if ((endstr - str0) == len) {
   2748 		/* A numeric string. */
   2749 		if ((nd->nd_flag & ND_KERBV) == 0 &&
   2750 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
   2751 		      nfsd_enable_stringtouid != 0))
   2752 			*uidp = tuid;
   2753 		else
   2754 			error = NFSERR_BADOWNER;
   2755 		goto out;
   2756 	}
   2757 	/*
   2758 	 * Look for an '@'.
   2759 	 */
   2760 	cp = strchr(str0, '@');
   2761 	if (cp != NULL)
   2762 		i = (int)(cp++ - str0);
   2763 	else
   2764 		i = len;
   2765 
   2766 	cnt = 0;
   2767 tryagain:
   2768 	if (nfsrv_dnsnamelen > 0) {
   2769 		/*
   2770 		 * If an '@' is found and the domain name matches, search for
   2771 		 * the name with dns stripped off.
   2772 		 * Mixed case alpahbetics will match for the domain name, but
   2773 		 * all upper case will not.
   2774 		 */
   2775 		if (cnt == 0 && i < len && i > 0 &&
   2776 		    (len - 1 - i) == nfsrv_dnsnamelen &&
   2777 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
   2778 			len -= (nfsrv_dnsnamelen + 1);
   2779 			*(cp - 1) = '\0';
   2780 		}
   2781 
   2782 		/*
   2783 		 * Check for the special case of "nobody".
   2784 		 */
   2785 		if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
   2786 			*uidp = nfsrv_defaultuid;
   2787 			error = 0;
   2788 			goto out;
   2789 		}
   2790 
   2791 		hp = NFSUSERNAMEHASH(str, len);
   2792 		mtx_lock(&hp->mtx);
   2793 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
   2794 			if (usrp->lug_namelen == len &&
   2795 			    !NFSBCMP(usrp->lug_name, str, len)) {
   2796 				if (usrp->lug_expiry < NFSD_MONOSEC)
   2797 					break;
   2798 				hp2 = NFSUSERHASH(usrp->lug_uid);
   2799 				mtx_lock(&hp2->mtx);
   2800 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
   2801 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
   2802 				    lug_numhash);
   2803 				*uidp = usrp->lug_uid;
   2804 				mtx_unlock(&hp2->mtx);
   2805 				mtx_unlock(&hp->mtx);
   2806 				error = 0;
   2807 				goto out;
   2808 			}
   2809 		}
   2810 		mtx_unlock(&hp->mtx);
   2811 		cnt++;
   2812 		ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
   2813 		    str, p);
   2814 		if (ret == 0 && cnt < 2)
   2815 			goto tryagain;
   2816 	}
   2817 	error = NFSERR_BADOWNER;
   2818 
   2819 out:
   2820 	NFSEXITCODE(error);
   2821 	return (error);
   2822 }
   2823 
   2824 /*
   2825  * Convert a gid to a string.
   2826  * gid - the group id
   2827  * cpp - points to a buffer of size NFSV4_SMALLSTR
   2828  *       (malloc a larger one, as required)
   2829  * retlenp - pointer to length to be returned
   2830  */
   2831 APPLESTATIC void
   2832 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
   2833 {
   2834 	int i;
   2835 	struct nfsusrgrp *usrp;
   2836 	u_char *cp = *cpp;
   2837 	gid_t tmp;
   2838 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
   2839 	struct nfsrv_lughash *hp;
   2840 
   2841 	cnt = 0;
   2842 tryagain:
   2843 	if (nfsrv_dnsnamelen > 0) {
   2844 		/*
   2845 		 * Always map nfsrv_defaultgid to "nogroup".
   2846 		 */
   2847 		if (gid == nfsrv_defaultgid) {
   2848 			i = nfsrv_dnsnamelen + 8;
   2849 			if (i > len) {
   2850 				if (len > NFSV4_SMALLSTR)
   2851 					free(cp, M_NFSSTRING);
   2852 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
   2853 				*cpp = cp;
   2854 				len = i;
   2855 				goto tryagain;
   2856 			}
   2857 			*retlenp = i;
   2858 			NFSBCOPY("nogroup@", cp, 8);
   2859 			cp += 8;
   2860 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
   2861 			return;
   2862 		}
   2863 		hasampersand = 0;
   2864 		hp = NFSGROUPHASH(gid);
   2865 		mtx_lock(&hp->mtx);
   2866 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
   2867 			if (usrp->lug_gid == gid) {
   2868 				if (usrp->lug_expiry < NFSD_MONOSEC)
   2869 					break;
   2870 				/*
   2871 				 * If the name doesn't already have an '@'
   2872 				 * in it, append @domainname to it.
   2873 				 */
   2874 				for (i = 0; i < usrp->lug_namelen; i++) {
   2875 					if (usrp->lug_name[i] == '@') {
   2876 						hasampersand = 1;
   2877 						break;
   2878 					}
   2879 				}
   2880 				if (hasampersand)
   2881 					i = usrp->lug_namelen;
   2882 				else
   2883 					i = usrp->lug_namelen +
   2884 					    nfsrv_dnsnamelen + 1;
   2885 				if (i > len) {
   2886 					mtx_unlock(&hp->mtx);
   2887 					if (len > NFSV4_SMALLSTR)
   2888 						free(cp, M_NFSSTRING);
   2889 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
   2890 					*cpp = cp;
   2891 					len = i;
   2892 					goto tryagain;
   2893 				}
   2894 				*retlenp = i;
   2895 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
   2896 				if (!hasampersand) {
   2897 					cp += usrp->lug_namelen;
   2898 					*cp++ = '@';
   2899 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
   2900 				}
   2901 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
   2902 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
   2903 				    lug_numhash);
   2904 				mtx_unlock(&hp->mtx);
   2905 				return;
   2906 			}
   2907 		}
   2908 		mtx_unlock(&hp->mtx);
   2909 		cnt++;
   2910 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
   2911 		    NULL, p);
   2912 		if (ret == 0 && cnt < 2)
   2913 			goto tryagain;
   2914 	}
   2915 
   2916 	/*
   2917 	 * No match, just return a string of digits.
   2918 	 */
   2919 	tmp = gid;
   2920 	i = 0;
   2921 	while (tmp || i == 0) {
   2922 		tmp /= 10;
   2923 		i++;
   2924 	}
   2925 	len = (i > len) ? len : i;
   2926 	*retlenp = len;
   2927 	cp += (len - 1);
   2928 	tmp = gid;
   2929 	for (i = 0; i < len; i++) {
   2930 		*cp-- = '0' + (tmp % 10);
   2931 		tmp /= 10;
   2932 	}
   2933 	return;
   2934 }
   2935 
   2936 /*
   2937  * Convert a string to a gid.
   2938  * If no conversion is possible return NFSERR_BADOWNER, otherwise
   2939  * return 0.
   2940  * If this is called from a client side mount using AUTH_SYS and the
   2941  * string is made up entirely of digits, just convert the string to
   2942  * a number.
   2943  */
   2944 APPLESTATIC int
   2945 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
   2946     NFSPROC_T *p)
   2947 {
   2948 	int i;
   2949 	char *cp, *endstr, *str0;
   2950 	struct nfsusrgrp *usrp;
   2951 	int cnt, ret;
   2952 	int error = 0;
   2953 	gid_t tgid;
   2954 	struct nfsrv_lughash *hp, *hp2;
   2955 
   2956 	if (len == 0) {
   2957 		error =  NFSERR_BADOWNER;
   2958 		goto out;
   2959 	}
   2960 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
   2961 	str0 = str;
   2962 	tgid = (gid_t)strtoul(str0, &endstr, 10);
   2963 	if ((endstr - str0) == len) {
   2964 		/* A numeric string. */
   2965 		if ((nd->nd_flag & ND_KERBV) == 0 &&
   2966 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
   2967 		      nfsd_enable_stringtouid != 0))
   2968 			*gidp = tgid;
   2969 		else
   2970 			error = NFSERR_BADOWNER;
   2971 		goto out;
   2972 	}
   2973 	/*
   2974 	 * Look for an '@'.
   2975 	 */
   2976 	cp = strchr(str0, '@');
   2977 	if (cp != NULL)
   2978 		i = (int)(cp++ - str0);
   2979 	else
   2980 		i = len;
   2981 
   2982 	cnt = 0;
   2983 tryagain:
   2984 	if (nfsrv_dnsnamelen > 0) {
   2985 		/*
   2986 		 * If an '@' is found and the dns name matches, search for the
   2987 		 * name with the dns stripped off.
   2988 		 */
   2989 		if (cnt == 0 && i < len && i > 0 &&
   2990 		    (len - 1 - i) == nfsrv_dnsnamelen &&
   2991 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
   2992 			len -= (nfsrv_dnsnamelen + 1);
   2993 			*(cp - 1) = '\0';
   2994 		}
   2995 
   2996 		/*
   2997 		 * Check for the special case of "nogroup".
   2998 		 */
   2999 		if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
   3000 			*gidp = nfsrv_defaultgid;
   3001 			error = 0;
   3002 			goto out;
   3003 		}
   3004 
   3005 		hp = NFSGROUPNAMEHASH(str, len);
   3006 		mtx_lock(&hp->mtx);
   3007 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
   3008 			if (usrp->lug_namelen == len &&
   3009 			    !NFSBCMP(usrp->lug_name, str, len)) {
   3010 				if (usrp->lug_expiry < NFSD_MONOSEC)
   3011 					break;
   3012 				hp2 = NFSGROUPHASH(usrp->lug_gid);
   3013 				mtx_lock(&hp2->mtx);
   3014 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
   3015 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
   3016 				    lug_numhash);
   3017 				*gidp = usrp->lug_gid;
   3018 				mtx_unlock(&hp2->mtx);
   3019 				mtx_unlock(&hp->mtx);
   3020 				error = 0;
   3021 				goto out;
   3022 			}
   3023 		}
   3024 		mtx_unlock(&hp->mtx);
   3025 		cnt++;
   3026 		ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
   3027 		    str, p);
   3028 		if (ret == 0 && cnt < 2)
   3029 			goto tryagain;
   3030 	}
   3031 	error = NFSERR_BADOWNER;
   3032 
   3033 out:
   3034 	NFSEXITCODE(error);
   3035 	return (error);
   3036 }
   3037 
   3038 /*
   3039  * Cmp len chars, allowing mixed case in the first argument to match lower
   3040  * case in the second, but not if the first argument is all upper case.
   3041  * Return 0 for a match, 1 otherwise.
   3042  */
   3043 static int
   3044 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
   3045 {
   3046 	int i;
   3047 	u_char tmp;
   3048 	int fndlower = 0;
   3049 
   3050 	for (i = 0; i < len; i++) {
   3051 		if (*cp >= 'A' && *cp <= 'Z') {
   3052 			tmp = *cp++ + ('a' - 'A');
   3053 		} else {
   3054 			tmp = *cp++;
   3055 			if (tmp >= 'a' && tmp <= 'z')
   3056 				fndlower = 1;
   3057 		}
   3058 		if (tmp != *cp2++)
   3059 			return (1);
   3060 	}
   3061 	if (fndlower)
   3062 		return (0);
   3063 	else
   3064 		return (1);
   3065 }
   3066 
   3067 /*
   3068  * Set the port for the nfsuserd.
   3069  */
   3070 APPLESTATIC int
   3071 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
   3072 {
   3073 	struct nfssockreq *rp;
   3074 	struct sockaddr_in *ad;
   3075 	int error;
   3076 
   3077 	NFSLOCKNAMEID();
   3078 	if (nfsrv_nfsuserd) {
   3079 		NFSUNLOCKNAMEID();
   3080 		error = EPERM;
   3081 		goto out;
   3082 	}
   3083 	nfsrv_nfsuserd = 1;
   3084 	NFSUNLOCKNAMEID();
   3085 	/*
   3086 	 * Set up the socket record and connect.
   3087 	 */
   3088 	rp = &nfsrv_nfsuserdsock;
   3089 	rp->nr_client = NULL;
   3090 	rp->nr_sotype = SOCK_DGRAM;
   3091 	rp->nr_soproto = IPPROTO_UDP;
   3092 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
   3093 	rp->nr_cred = NULL;
   3094 	NFSSOCKADDRALLOC(rp->nr_nam);
   3095 	NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
   3096 	ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
   3097 	ad->sin_family = AF_INET;
   3098 	ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);	/* 127.0.0.1 */
   3099 	ad->sin_port = port;
   3100 	rp->nr_prog = RPCPROG_NFSUSERD;
   3101 	rp->nr_vers = RPCNFSUSERD_VERS;
   3102 	error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
   3103 	if (error) {
   3104 		NFSSOCKADDRFREE(rp->nr_nam);
   3105 		nfsrv_nfsuserd = 0;
   3106 	}
   3107 out:
   3108 	NFSEXITCODE(error);
   3109 	return (error);
   3110 }
   3111 
   3112 /*
   3113  * Delete the nfsuserd port.
   3114  */
   3115 APPLESTATIC void
   3116 nfsrv_nfsuserddelport(void)
   3117 {
   3118 
   3119 	NFSLOCKNAMEID();
   3120 	if (nfsrv_nfsuserd == 0) {
   3121 		NFSUNLOCKNAMEID();
   3122 		return;
   3123 	}
   3124 	nfsrv_nfsuserd = 0;
   3125 	NFSUNLOCKNAMEID();
   3126 	newnfs_disconnect(&nfsrv_nfsuserdsock);
   3127 	NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
   3128 }
   3129 
   3130 /*
   3131  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
   3132  * name<-->id cache.
   3133  * Returns 0 upon success, non-zero otherwise.
   3134  */
   3135 static int
   3136 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
   3137 {
   3138 	u_int32_t *tl;
   3139 	struct nfsrv_descript *nd;
   3140 	int len;
   3141 	struct nfsrv_descript nfsd;
   3142 	struct ucred *cred;
   3143 	int error;
   3144 
   3145 	NFSLOCKNAMEID();
   3146 	if (nfsrv_nfsuserd == 0) {
   3147 		NFSUNLOCKNAMEID();
   3148 		error = EPERM;
   3149 		goto out;
   3150 	}
   3151 	NFSUNLOCKNAMEID();
   3152 	nd = &nfsd;
   3153 	cred = newnfs_getcred();
   3154 	nd->nd_flag = ND_GSSINITREPLY;
   3155 	nfsrvd_rephead(nd);
   3156 
   3157 	nd->nd_procnum = procnum;
   3158 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
   3159 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3160 		if (procnum == RPCNFSUSERD_GETUID)
   3161 			*tl = txdr_unsigned(uid);
   3162 		else
   3163 			*tl = txdr_unsigned(gid);
   3164 	} else {
   3165 		len = strlen(name);
   3166 		(void) nfsm_strtom(nd, name, len);
   3167 	}
   3168 	error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
   3169 		cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
   3170 	NFSFREECRED(cred);
   3171 	if (!error) {
   3172 		mbuf_freem(nd->nd_mrep);
   3173 		error = nd->nd_repstat;
   3174 	}
   3175 out:
   3176 	NFSEXITCODE(error);
   3177 	return (error);
   3178 }
   3179 
   3180 /*
   3181  * This function is called from the nfssvc(2) system call, to update the
   3182  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
   3183  */
   3184 APPLESTATIC int
   3185 nfssvc_idname(struct nfsd_idargs *nidp)
   3186 {
   3187 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
   3188 	struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
   3189 	int i, group_locked, groupname_locked, user_locked, username_locked;
   3190 	int error = 0;
   3191 	u_char *cp;
   3192 	gid_t *grps;
   3193 	struct ucred *cr;
   3194 	static int onethread = 0;
   3195 	static time_t lasttime = 0;
   3196 
   3197 	if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
   3198 		error = EINVAL;
   3199 		goto out;
   3200 	}
   3201 	if (nidp->nid_flag & NFSID_INITIALIZE) {
   3202 		cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
   3203 		error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
   3204 		    nidp->nid_namelen);
   3205 		if (error != 0) {
   3206 			free(cp, M_NFSSTRING);
   3207 			goto out;
   3208 		}
   3209 		if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
   3210 			/*
   3211 			 * Free up all the old stuff and reinitialize hash
   3212 			 * lists.  All mutexes for both lists must be locked,
   3213 			 * with the user/group name ones before the uid/gid
   3214 			 * ones, to avoid a LOR.
   3215 			 */
   3216 			for (i = 0; i < nfsrv_lughashsize; i++)
   3217 				mtx_lock(&nfsusernamehash[i].mtx);
   3218 			for (i = 0; i < nfsrv_lughashsize; i++)
   3219 				mtx_lock(&nfsuserhash[i].mtx);
   3220 			for (i = 0; i < nfsrv_lughashsize; i++)
   3221 				TAILQ_FOREACH_SAFE(usrp,
   3222 				    &nfsuserhash[i].lughead, lug_numhash, nusrp)
   3223 					nfsrv_removeuser(usrp, 1);
   3224 			for (i = 0; i < nfsrv_lughashsize; i++)
   3225 				mtx_unlock(&nfsuserhash[i].mtx);
   3226 			for (i = 0; i < nfsrv_lughashsize; i++)
   3227 				mtx_unlock(&nfsusernamehash[i].mtx);
   3228 			for (i = 0; i < nfsrv_lughashsize; i++)
   3229 				mtx_lock(&nfsgroupnamehash[i].mtx);
   3230 			for (i = 0; i < nfsrv_lughashsize; i++)
   3231 				mtx_lock(&nfsgrouphash[i].mtx);
   3232 			for (i = 0; i < nfsrv_lughashsize; i++)
   3233 				TAILQ_FOREACH_SAFE(usrp,
   3234 				    &nfsgrouphash[i].lughead, lug_numhash,
   3235 				    nusrp)
   3236 					nfsrv_removeuser(usrp, 0);
   3237 			for (i = 0; i < nfsrv_lughashsize; i++)
   3238 				mtx_unlock(&nfsgrouphash[i].mtx);
   3239 			for (i = 0; i < nfsrv_lughashsize; i++)
   3240 				mtx_unlock(&nfsgroupnamehash[i].mtx);
   3241 			free(nfsrv_dnsname, M_NFSSTRING);
   3242 			nfsrv_dnsname = NULL;
   3243 		}
   3244 		if (nfsuserhash == NULL) {
   3245 			/* Allocate the hash tables. */
   3246 			nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
   3247 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
   3248 			    M_ZERO);
   3249 			for (i = 0; i < nfsrv_lughashsize; i++)
   3250 				mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
   3251 				    NULL, MTX_DEF | MTX_DUPOK);
   3252 			nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
   3253 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
   3254 			    M_ZERO);
   3255 			for (i = 0; i < nfsrv_lughashsize; i++)
   3256 				mtx_init(&nfsusernamehash[i].mtx,
   3257 				    "nfsusrhash", NULL, MTX_DEF |
   3258 				    MTX_DUPOK);
   3259 			nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
   3260 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
   3261 			    M_ZERO);
   3262 			for (i = 0; i < nfsrv_lughashsize; i++)
   3263 				mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
   3264 				    NULL, MTX_DEF | MTX_DUPOK);
   3265 			nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
   3266 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
   3267 			    M_ZERO);
   3268 			for (i = 0; i < nfsrv_lughashsize; i++)
   3269 			    mtx_init(&nfsgroupnamehash[i].mtx,
   3270 			    "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
   3271 		}
   3272 		/* (Re)initialize the list heads. */
   3273 		for (i = 0; i < nfsrv_lughashsize; i++)
   3274 			TAILQ_INIT(&nfsuserhash[i].lughead);
   3275 		for (i = 0; i < nfsrv_lughashsize; i++)
   3276 			TAILQ_INIT(&nfsusernamehash[i].lughead);
   3277 		for (i = 0; i < nfsrv_lughashsize; i++)
   3278 			TAILQ_INIT(&nfsgrouphash[i].lughead);
   3279 		for (i = 0; i < nfsrv_lughashsize; i++)
   3280 			TAILQ_INIT(&nfsgroupnamehash[i].lughead);
   3281 
   3282 		/*
   3283 		 * Put name in "DNS" string.
   3284 		 */
   3285 		nfsrv_dnsname = cp;
   3286 		nfsrv_defaultuid = nidp->nid_uid;
   3287 		nfsrv_defaultgid = nidp->nid_gid;
   3288 		nfsrv_usercnt = 0;
   3289 		nfsrv_usermax = nidp->nid_usermax;
   3290 		atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
   3291 		goto out;
   3292 	}
   3293 
   3294 	/*
   3295 	 * malloc the new one now, so any potential sleep occurs before
   3296 	 * manipulation of the lists.
   3297 	 */
   3298 	newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
   3299 	    M_NFSUSERGROUP, M_WAITOK | M_ZERO);
   3300 	error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
   3301 	    nidp->nid_namelen);
   3302 	if (error == 0 && nidp->nid_ngroup > 0 &&
   3303 	    (nidp->nid_flag & NFSID_ADDUID) != 0) {
   3304 		grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
   3305 		    M_WAITOK);
   3306 		error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
   3307 		    sizeof(gid_t) * nidp->nid_ngroup);
   3308 		if (error == 0) {
   3309 			/*
   3310 			 * Create a credential just like svc_getcred(),
   3311 			 * but using the group list provided.
   3312 			 */
   3313 			cr = crget();
   3314 			cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
   3315 			crsetgroups(cr, nidp->nid_ngroup, grps);
   3316 			cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
   3317 			cr->cr_prison = &prison0;
   3318 			prison_hold(cr->cr_prison);
   3319 #ifdef MAC
   3320 			mac_cred_associate_nfsd(cr);
   3321 #endif
   3322 			newusrp->lug_cred = cr;
   3323 		}
   3324 		free(grps, M_TEMP);
   3325 	}
   3326 	if (error) {
   3327 		free(newusrp, M_NFSUSERGROUP);
   3328 		goto out;
   3329 	}
   3330 	newusrp->lug_namelen = nidp->nid_namelen;
   3331 
   3332 	/*
   3333 	 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
   3334 	 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
   3335 	 * The flags user_locked, username_locked, group_locked and
   3336 	 * groupname_locked are set to indicate all of those hash lists are
   3337 	 * locked. hp_name != NULL  and hp_idnum != NULL indicates that
   3338 	 * the respective one mutex is locked.
   3339 	 */
   3340 	user_locked = username_locked = group_locked = groupname_locked = 0;
   3341 	hp_name = hp_idnum = NULL;
   3342 
   3343 	/*
   3344 	 * Delete old entries, as required.
   3345 	 */
   3346 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
   3347 		/* Must lock all username hash lists first, to avoid a LOR. */
   3348 		for (i = 0; i < nfsrv_lughashsize; i++)
   3349 			mtx_lock(&nfsusernamehash[i].mtx);
   3350 		username_locked = 1;
   3351 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
   3352 		mtx_lock(&hp_idnum->mtx);
   3353 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
   3354 		    nusrp) {
   3355 			if (usrp->lug_uid == nidp->nid_uid)
   3356 				nfsrv_removeuser(usrp, 1);
   3357 		}
   3358 	} else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
   3359 		hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
   3360 		    newusrp->lug_namelen);
   3361 		mtx_lock(&hp_name->mtx);
   3362 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
   3363 		    nusrp) {
   3364 			if (usrp->lug_namelen == newusrp->lug_namelen &&
   3365 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
   3366 			    usrp->lug_namelen)) {
   3367 				thp = NFSUSERHASH(usrp->lug_uid);
   3368 				mtx_lock(&thp->mtx);
   3369 				nfsrv_removeuser(usrp, 1);
   3370 				mtx_unlock(&thp->mtx);
   3371 			}
   3372 		}
   3373 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
   3374 		mtx_lock(&hp_idnum->mtx);
   3375 	} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
   3376 		/* Must lock all groupname hash lists first, to avoid a LOR. */
   3377 		for (i = 0; i < nfsrv_lughashsize; i++)
   3378 			mtx_lock(&nfsgroupnamehash[i].mtx);
   3379 		groupname_locked = 1;
   3380 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
   3381 		mtx_lock(&hp_idnum->mtx);
   3382 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
   3383 		    nusrp) {
   3384 			if (usrp->lug_gid == nidp->nid_gid)
   3385 				nfsrv_removeuser(usrp, 0);
   3386 		}
   3387 	} else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
   3388 		hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
   3389 		    newusrp->lug_namelen);
   3390 		mtx_lock(&hp_name->mtx);
   3391 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
   3392 		    nusrp) {
   3393 			if (usrp->lug_namelen == newusrp->lug_namelen &&
   3394 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
   3395 			    usrp->lug_namelen)) {
   3396 				thp = NFSGROUPHASH(usrp->lug_gid);
   3397 				mtx_lock(&thp->mtx);
   3398 				nfsrv_removeuser(usrp, 0);
   3399 				mtx_unlock(&thp->mtx);
   3400 			}
   3401 		}
   3402 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
   3403 		mtx_lock(&hp_idnum->mtx);
   3404 	}
   3405 
   3406 	/*
   3407 	 * Now, we can add the new one.
   3408 	 */
   3409 	if (nidp->nid_usertimeout)
   3410 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
   3411 	else
   3412 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
   3413 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
   3414 		newusrp->lug_uid = nidp->nid_uid;
   3415 		thp = NFSUSERHASH(newusrp->lug_uid);
   3416 		mtx_assert(&thp->mtx, MA_OWNED);
   3417 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
   3418 		thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
   3419 		mtx_assert(&thp->mtx, MA_OWNED);
   3420 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
   3421 		atomic_add_int(&nfsrv_usercnt, 1);
   3422 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
   3423 		newusrp->lug_gid = nidp->nid_gid;
   3424 		thp = NFSGROUPHASH(newusrp->lug_gid);
   3425 		mtx_assert(&thp->mtx, MA_OWNED);
   3426 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
   3427 		thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
   3428 		mtx_assert(&thp->mtx, MA_OWNED);
   3429 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
   3430 		atomic_add_int(&nfsrv_usercnt, 1);
   3431 	} else {
   3432 		if (newusrp->lug_cred != NULL)
   3433 			crfree(newusrp->lug_cred);
   3434 		free(newusrp, M_NFSUSERGROUP);
   3435 	}
   3436 
   3437 	/*
   3438 	 * Once per second, allow one thread to trim the cache.
   3439 	 */
   3440 	if (lasttime < NFSD_MONOSEC &&
   3441 	    atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
   3442 		/*
   3443 		 * First, unlock the single mutexes, so that all entries
   3444 		 * can be locked and any LOR is avoided.
   3445 		 */
   3446 		if (hp_name != NULL) {
   3447 			mtx_unlock(&hp_name->mtx);
   3448 			hp_name = NULL;
   3449 		}
   3450 		if (hp_idnum != NULL) {
   3451 			mtx_unlock(&hp_idnum->mtx);
   3452 			hp_idnum = NULL;
   3453 		}
   3454 
   3455 		if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
   3456 		    NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
   3457 			if (username_locked == 0) {
   3458 				for (i = 0; i < nfsrv_lughashsize; i++)
   3459 					mtx_lock(&nfsusernamehash[i].mtx);
   3460 				username_locked = 1;
   3461 			}
   3462 			KASSERT(user_locked == 0,
   3463 			    ("nfssvc_idname: user_locked"));
   3464 			for (i = 0; i < nfsrv_lughashsize; i++)
   3465 				mtx_lock(&nfsuserhash[i].mtx);
   3466 			user_locked = 1;
   3467 			for (i = 0; i < nfsrv_lughashsize; i++) {
   3468 				TAILQ_FOREACH_SAFE(usrp,
   3469 				    &nfsuserhash[i].lughead, lug_numhash,
   3470 				    nusrp)
   3471 					if (usrp->lug_expiry < NFSD_MONOSEC)
   3472 						nfsrv_removeuser(usrp, 1);
   3473 			}
   3474 			for (i = 0; i < nfsrv_lughashsize; i++) {
   3475 				/*
   3476 				 * Trim the cache using an approximate LRU
   3477 				 * algorithm.  This code deletes the least
   3478 				 * recently used entry on each hash list.
   3479 				 */
   3480 				if (nfsrv_usercnt <= nfsrv_usermax)
   3481 					break;
   3482 				usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
   3483 				if (usrp != NULL)
   3484 					nfsrv_removeuser(usrp, 1);
   3485 			}
   3486 		} else {
   3487 			if (groupname_locked == 0) {
   3488 				for (i = 0; i < nfsrv_lughashsize; i++)
   3489 					mtx_lock(&nfsgroupnamehash[i].mtx);
   3490 				groupname_locked = 1;
   3491 			}
   3492 			KASSERT(group_locked == 0,
   3493 			    ("nfssvc_idname: group_locked"));
   3494 			for (i = 0; i < nfsrv_lughashsize; i++)
   3495 				mtx_lock(&nfsgrouphash[i].mtx);
   3496 			group_locked = 1;
   3497 			for (i = 0; i < nfsrv_lughashsize; i++) {
   3498 				TAILQ_FOREACH_SAFE(usrp,
   3499 				    &nfsgrouphash[i].lughead, lug_numhash,
   3500 				    nusrp)
   3501 					if (usrp->lug_expiry < NFSD_MONOSEC)
   3502 						nfsrv_removeuser(usrp, 0);
   3503 			}
   3504 			for (i = 0; i < nfsrv_lughashsize; i++) {
   3505 				/*
   3506 				 * Trim the cache using an approximate LRU
   3507 				 * algorithm.  This code deletes the least
   3508 				 * recently user entry on each hash list.
   3509 				 */
   3510 				if (nfsrv_usercnt <= nfsrv_usermax)
   3511 					break;
   3512 				usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
   3513 				if (usrp != NULL)
   3514 					nfsrv_removeuser(usrp, 0);
   3515 			}
   3516 		}
   3517 		lasttime = NFSD_MONOSEC;
   3518 		atomic_store_rel_int(&onethread, 0);
   3519 	}
   3520 
   3521 	/* Now, unlock all locked mutexes. */
   3522 	if (hp_idnum != NULL)
   3523 		mtx_unlock(&hp_idnum->mtx);
   3524 	if (hp_name != NULL)
   3525 		mtx_unlock(&hp_name->mtx);
   3526 	if (user_locked != 0)
   3527 		for (i = 0; i < nfsrv_lughashsize; i++)
   3528 			mtx_unlock(&nfsuserhash[i].mtx);
   3529 	if (username_locked != 0)
   3530 		for (i = 0; i < nfsrv_lughashsize; i++)
   3531 			mtx_unlock(&nfsusernamehash[i].mtx);
   3532 	if (group_locked != 0)
   3533 		for (i = 0; i < nfsrv_lughashsize; i++)
   3534 			mtx_unlock(&nfsgrouphash[i].mtx);
   3535 	if (groupname_locked != 0)
   3536 		for (i = 0; i < nfsrv_lughashsize; i++)
   3537 			mtx_unlock(&nfsgroupnamehash[i].mtx);
   3538 out:
   3539 	NFSEXITCODE(error);
   3540 	return (error);
   3541 }
   3542 
   3543 /*
   3544  * Remove a user/group name element.
   3545  */
   3546 static void
   3547 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
   3548 {
   3549 	struct nfsrv_lughash *hp;
   3550 
   3551 	if (isuser != 0) {
   3552 		hp = NFSUSERHASH(usrp->lug_uid);
   3553 		mtx_assert(&hp->mtx, MA_OWNED);
   3554 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
   3555 		hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
   3556 		mtx_assert(&hp->mtx, MA_OWNED);
   3557 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
   3558 	} else {
   3559 		hp = NFSGROUPHASH(usrp->lug_gid);
   3560 		mtx_assert(&hp->mtx, MA_OWNED);
   3561 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
   3562 		hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
   3563 		mtx_assert(&hp->mtx, MA_OWNED);
   3564 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
   3565 	}
   3566 	atomic_add_int(&nfsrv_usercnt, -1);
   3567 	if (usrp->lug_cred != NULL)
   3568 		crfree(usrp->lug_cred);
   3569 	free(usrp, M_NFSUSERGROUP);
   3570 }
   3571 
   3572 /*
   3573  * Free up all the allocations related to the name<-->id cache.
   3574  * This function should only be called when the nfsuserd daemon isn't
   3575  * running, since it doesn't do any locking.
   3576  * This function is meant to be used when the nfscommon module is unloaded.
   3577  */
   3578 APPLESTATIC void
   3579 nfsrv_cleanusergroup(void)
   3580 {
   3581 	struct nfsrv_lughash *hp, *hp2;
   3582 	struct nfsusrgrp *nusrp, *usrp;
   3583 	int i;
   3584 
   3585 	if (nfsuserhash == NULL)
   3586 		return;
   3587 
   3588 	for (i = 0; i < nfsrv_lughashsize; i++) {
   3589 		hp = &nfsuserhash[i];
   3590 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
   3591 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
   3592 			hp2 = NFSUSERNAMEHASH(usrp->lug_name,
   3593 			    usrp->lug_namelen);
   3594 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
   3595 			if (usrp->lug_cred != NULL)
   3596 				crfree(usrp->lug_cred);
   3597 			free(usrp, M_NFSUSERGROUP);
   3598 		}
   3599 		hp = &nfsgrouphash[i];
   3600 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
   3601 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
   3602 			hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
   3603 			    usrp->lug_namelen);
   3604 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
   3605 			if (usrp->lug_cred != NULL)
   3606 				crfree(usrp->lug_cred);
   3607 			free(usrp, M_NFSUSERGROUP);
   3608 		}
   3609 		mtx_destroy(&nfsuserhash[i].mtx);
   3610 		mtx_destroy(&nfsusernamehash[i].mtx);
   3611 		mtx_destroy(&nfsgroupnamehash[i].mtx);
   3612 		mtx_destroy(&nfsgrouphash[i].mtx);
   3613 	}
   3614 	free(nfsuserhash, M_NFSUSERGROUP);
   3615 	free(nfsusernamehash, M_NFSUSERGROUP);
   3616 	free(nfsgrouphash, M_NFSUSERGROUP);
   3617 	free(nfsgroupnamehash, M_NFSUSERGROUP);
   3618 	free(nfsrv_dnsname, M_NFSSTRING);
   3619 }
   3620 
   3621 /*
   3622  * This function scans a byte string and checks for UTF-8 compliance.
   3623  * It returns 0 if it conforms and NFSERR_INVAL if not.
   3624  */
   3625 APPLESTATIC int
   3626 nfsrv_checkutf8(u_int8_t *cp, int len)
   3627 {
   3628 	u_int32_t val = 0x0;
   3629 	int cnt = 0, gotd = 0, shift = 0;
   3630 	u_int8_t byte;
   3631 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
   3632 	int error = 0;
   3633 
   3634 	/*
   3635 	 * Here are what the variables are used for:
   3636 	 * val - the calculated value of a multibyte char, used to check
   3637 	 *       that it was coded with the correct range
   3638 	 * cnt - the number of 10xxxxxx bytes to follow
   3639 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
   3640 	 * shift - lower order bits of range (ie. "val >> shift" should
   3641 	 *       not be 0, in other words, dividing by the lower bound
   3642 	 *       of the range should get a non-zero value)
   3643 	 * byte - used to calculate cnt
   3644 	 */
   3645 	while (len > 0) {
   3646 		if (cnt > 0) {
   3647 			/* This handles the 10xxxxxx bytes */
   3648 			if ((*cp & 0xc0) != 0x80 ||
   3649 			    (gotd && (*cp & 0x20))) {
   3650 				error = NFSERR_INVAL;
   3651 				goto out;
   3652 			}
   3653 			gotd = 0;
   3654 			val <<= 6;
   3655 			val |= (*cp & 0x3f);
   3656 			cnt--;
   3657 			if (cnt == 0 && (val >> shift) == 0x0) {
   3658 				error = NFSERR_INVAL;
   3659 				goto out;
   3660 			}
   3661 		} else if (*cp & 0x80) {
   3662 			/* first byte of multi byte char */
   3663 			byte = *cp;
   3664 			while ((byte & 0x40) && cnt < 6) {
   3665 				cnt++;
   3666 				byte <<= 1;
   3667 			}
   3668 			if (cnt == 0 || cnt == 6) {
   3669 				error = NFSERR_INVAL;
   3670 				goto out;
   3671 			}
   3672 			val = (*cp & (0x3f >> cnt));
   3673 			shift = utf8_shift[cnt - 1];
   3674 			if (cnt == 2 && val == 0xd)
   3675 				/* Check for the 0xd800-0xdfff case */
   3676 				gotd = 1;
   3677 		}
   3678 		cp++;
   3679 		len--;
   3680 	}
   3681 	if (cnt > 0)
   3682 		error = NFSERR_INVAL;
   3683 
   3684 out:
   3685 	NFSEXITCODE(error);
   3686 	return (error);
   3687 }
   3688 
   3689 /*
   3690  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
   3691  * strings, one with the root path in it and the other with the list of
   3692  * locations. The list is in the same format as is found in nfr_refs.
   3693  * It is a "," separated list of entries, where each of them is of the
   3694  * form <server>:<rootpath>. For example
   3695  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
   3696  * The nilp argument is set to 1 for the special case of a null fs_root
   3697  * and an empty server list.
   3698  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
   3699  * number of xdr bytes parsed in sump.
   3700  */
   3701 static int
   3702 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
   3703     int *sump, int *nilp)
   3704 {
   3705 	u_int32_t *tl;
   3706 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
   3707 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
   3708 	struct list {
   3709 		SLIST_ENTRY(list) next;
   3710 		int len;
   3711 		u_char host[1];
   3712 	} *lsp, *nlsp;
   3713 	SLIST_HEAD(, list) head;
   3714 
   3715 	*fsrootp = NULL;
   3716 	*srvp = NULL;
   3717 	*nilp = 0;
   3718 
   3719 	/*
   3720 	 * Get the fs_root path and check for the special case of null path
   3721 	 * and 0 length server list.
   3722 	 */
   3723 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3724 	len = fxdr_unsigned(int, *tl);
   3725 	if (len < 0 || len > 10240) {
   3726 		error = NFSERR_BADXDR;
   3727 		goto nfsmout;
   3728 	}
   3729 	if (len == 0) {
   3730 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3731 		if (*tl != 0) {
   3732 			error = NFSERR_BADXDR;
   3733 			goto nfsmout;
   3734 		}
   3735 		*nilp = 1;
   3736 		*sump = 2 * NFSX_UNSIGNED;
   3737 		error = 0;
   3738 		goto nfsmout;
   3739 	}
   3740 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
   3741 	error = nfsrv_mtostr(nd, cp, len);
   3742 	if (!error) {
   3743 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3744 		cnt = fxdr_unsigned(int, *tl);
   3745 		if (cnt <= 0)
   3746 			error = NFSERR_BADXDR;
   3747 	}
   3748 	if (error)
   3749 		goto nfsmout;
   3750 
   3751 	/*
   3752 	 * Now, loop through the location list and make up the srvlist.
   3753 	 */
   3754 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
   3755 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
   3756 	slen = 1024;
   3757 	siz = 0;
   3758 	for (i = 0; i < cnt; i++) {
   3759 		SLIST_INIT(&head);
   3760 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3761 		nsrv = fxdr_unsigned(int, *tl);
   3762 		if (nsrv <= 0) {
   3763 			error = NFSERR_BADXDR;
   3764 			goto nfsmout;
   3765 		}
   3766 
   3767 		/*
   3768 		 * Handle the first server by putting it in the srvstr.
   3769 		 */
   3770 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3771 		len = fxdr_unsigned(int, *tl);
   3772 		if (len <= 0 || len > 1024) {
   3773 			error = NFSERR_BADXDR;
   3774 			goto nfsmout;
   3775 		}
   3776 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
   3777 		if (cp3 != cp2) {
   3778 			*cp3++ = ',';
   3779 			siz++;
   3780 		}
   3781 		error = nfsrv_mtostr(nd, cp3, len);
   3782 		if (error)
   3783 			goto nfsmout;
   3784 		cp3 += len;
   3785 		*cp3++ = ':';
   3786 		siz += (len + 1);
   3787 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
   3788 		for (j = 1; j < nsrv; j++) {
   3789 			/*
   3790 			 * Yuck, put them in an slist and process them later.
   3791 			 */
   3792 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3793 			len = fxdr_unsigned(int, *tl);
   3794 			if (len <= 0 || len > 1024) {
   3795 				error = NFSERR_BADXDR;
   3796 				goto nfsmout;
   3797 			}
   3798 			lsp = (struct list *)malloc(sizeof (struct list)
   3799 			    + len, M_TEMP, M_WAITOK);
   3800 			error = nfsrv_mtostr(nd, lsp->host, len);
   3801 			if (error)
   3802 				goto nfsmout;
   3803 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
   3804 			lsp->len = len;
   3805 			SLIST_INSERT_HEAD(&head, lsp, next);
   3806 		}
   3807 
   3808 		/*
   3809 		 * Finally, we can get the path.
   3810 		 */
   3811 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3812 		len = fxdr_unsigned(int, *tl);
   3813 		if (len <= 0 || len > 1024) {
   3814 			error = NFSERR_BADXDR;
   3815 			goto nfsmout;
   3816 		}
   3817 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
   3818 		error = nfsrv_mtostr(nd, cp3, len);
   3819 		if (error)
   3820 			goto nfsmout;
   3821 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
   3822 		str = cp3;
   3823 		stringlen = len;
   3824 		cp3 += len;
   3825 		siz += len;
   3826 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
   3827 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
   3828 			    &cp2, &cp3, &slen);
   3829 			*cp3++ = ',';
   3830 			NFSBCOPY(lsp->host, cp3, lsp->len);
   3831 			cp3 += lsp->len;
   3832 			*cp3++ = ':';
   3833 			NFSBCOPY(str, cp3, stringlen);
   3834 			cp3 += stringlen;
   3835 			*cp3 = '\0';
   3836 			siz += (lsp->len + stringlen + 2);
   3837 			free((caddr_t)lsp, M_TEMP);
   3838 		}
   3839 	}
   3840 	*fsrootp = cp;
   3841 	*srvp = cp2;
   3842 	*sump = xdrsum;
   3843 	NFSEXITCODE2(0, nd);
   3844 	return (0);
   3845 nfsmout:
   3846 	if (cp != NULL)
   3847 		free(cp, M_NFSSTRING);
   3848 	if (cp2 != NULL)
   3849 		free(cp2, M_NFSSTRING);
   3850 	NFSEXITCODE2(error, nd);
   3851 	return (error);
   3852 }
   3853 
   3854 /*
   3855  * Make the malloc'd space large enough. This is a pain, but the xdr
   3856  * doesn't set an upper bound on the side, so...
   3857  */
   3858 static void
   3859 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
   3860 {
   3861 	u_char *cp;
   3862 	int i;
   3863 
   3864 	if (siz <= *slenp)
   3865 		return;
   3866 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
   3867 	NFSBCOPY(*cpp, cp, *slenp);
   3868 	free(*cpp, M_NFSSTRING);
   3869 	i = *cpp2 - *cpp;
   3870 	*cpp = cp;
   3871 	*cpp2 = cp + i;
   3872 	*slenp = siz + 1024;
   3873 }
   3874 
   3875 /*
   3876  * Initialize the reply header data structures.
   3877  */
   3878 APPLESTATIC void
   3879 nfsrvd_rephead(struct nfsrv_descript *nd)
   3880 {
   3881 	mbuf_t mreq;
   3882 
   3883 	/*
   3884 	 * If this is a big reply, use a cluster.
   3885 	 */
   3886 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
   3887 	    nfs_bigreply[nd->nd_procnum]) {
   3888 		NFSMCLGET(mreq, M_WAITOK);
   3889 		nd->nd_mreq = mreq;
   3890 		nd->nd_mb = mreq;
   3891 	} else {
   3892 		NFSMGET(mreq);
   3893 		nd->nd_mreq = mreq;
   3894 		nd->nd_mb = mreq;
   3895 	}
   3896 	nd->nd_bpos = NFSMTOD(mreq, caddr_t);
   3897 	mbuf_setlen(mreq, 0);
   3898 
   3899 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
   3900 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
   3901 }
   3902 
   3903 /*
   3904  * Lock a socket against others.
   3905  * Currently used to serialize connect/disconnect attempts.
   3906  */
   3907 int
   3908 newnfs_sndlock(int *flagp)
   3909 {
   3910 	struct timespec ts;
   3911 
   3912 	NFSLOCKSOCK();
   3913 	while (*flagp & NFSR_SNDLOCK) {
   3914 		*flagp |= NFSR_WANTSND;
   3915 		ts.tv_sec = 0;
   3916 		ts.tv_nsec = 0;
   3917 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
   3918 		    PZERO - 1, "nfsndlck", &ts);
   3919 	}
   3920 	*flagp |= NFSR_SNDLOCK;
   3921 	NFSUNLOCKSOCK();
   3922 	return (0);
   3923 }
   3924 
   3925 /*
   3926  * Unlock the stream socket for others.
   3927  */
   3928 void
   3929 newnfs_sndunlock(int *flagp)
   3930 {
   3931 
   3932 	NFSLOCKSOCK();
   3933 	if ((*flagp & NFSR_SNDLOCK) == 0)
   3934 		panic("nfs sndunlock");
   3935 	*flagp &= ~NFSR_SNDLOCK;
   3936 	if (*flagp & NFSR_WANTSND) {
   3937 		*flagp &= ~NFSR_WANTSND;
   3938 		wakeup((caddr_t)flagp);
   3939 	}
   3940 	NFSUNLOCKSOCK();
   3941 }
   3942 
   3943 APPLESTATIC int
   3944 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
   3945     int *isudp)
   3946 {
   3947 	struct sockaddr_in *sad;
   3948 	struct sockaddr_in6 *sad6;
   3949 	struct in_addr saddr;
   3950 	uint32_t portnum, *tl;
   3951 	int af = 0, i, j, k;
   3952 	char addr[64], protocol[5], *cp;
   3953 	int cantparse = 0, error = 0;
   3954 	uint16_t portv;
   3955 
   3956 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3957 	i = fxdr_unsigned(int, *tl);
   3958 	if (i >= 3 && i <= 4) {
   3959 		error = nfsrv_mtostr(nd, protocol, i);
   3960 		if (error)
   3961 			goto nfsmout;
   3962 		if (strcmp(protocol, "tcp") == 0) {
   3963 			af = AF_INET;
   3964 			*isudp = 0;
   3965 		} else if (strcmp(protocol, "udp") == 0) {
   3966 			af = AF_INET;
   3967 			*isudp = 1;
   3968 		} else if (strcmp(protocol, "tcp6") == 0) {
   3969 			af = AF_INET6;
   3970 			*isudp = 0;
   3971 		} else if (strcmp(protocol, "udp6") == 0) {
   3972 			af = AF_INET6;
   3973 			*isudp = 1;
   3974 		} else
   3975 			cantparse = 1;
   3976 	} else {
   3977 		cantparse = 1;
   3978 		if (i > 0) {
   3979 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
   3980 			if (error)
   3981 				goto nfsmout;
   3982 		}
   3983 	}
   3984 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3985 	i = fxdr_unsigned(int, *tl);
   3986 	if (i < 0) {
   3987 		error = NFSERR_BADXDR;
   3988 		goto nfsmout;
   3989 	} else if (cantparse == 0 && i >= 11 && i < 64) {
   3990 		/*
   3991 		 * The shortest address is 11chars and the longest is < 64.
   3992 		 */
   3993 		error = nfsrv_mtostr(nd, addr, i);
   3994 		if (error)
   3995 			goto nfsmout;
   3996 
   3997 		/* Find the port# at the end and extract that. */
   3998 		i = strlen(addr);
   3999 		k = 0;
   4000 		cp = &addr[i - 1];
   4001 		/* Count back two '.'s from end to get port# field. */
   4002 		for (j = 0; j < i; j++) {
   4003 			if (*cp == '.') {
   4004 				k++;
   4005 				if (k == 2)
   4006 					break;
   4007 			}
   4008 			cp--;
   4009 		}
   4010 		if (k == 2) {
   4011 			/*
   4012 			 * The NFSv4 port# is appended as .N.N, where N is
   4013 			 * a decimal # in the range 0-255, just like an inet4
   4014 			 * address. Cheat and use inet_aton(), which will
   4015 			 * return a Class A address and then shift the high
   4016 			 * order 8bits over to convert it to the port#.
   4017 			 */
   4018 			*cp++ = '\0';
   4019 			if (inet_aton(cp, &saddr) == 1) {
   4020 				portnum = ntohl(saddr.s_addr);
   4021 				portv = (uint16_t)((portnum >> 16) |
   4022 				    (portnum & 0xff));
   4023 			} else
   4024 				cantparse = 1;
   4025 		} else
   4026 			cantparse = 1;
   4027 		if (cantparse == 0) {
   4028 			if (af == AF_INET) {
   4029 				sad = (struct sockaddr_in *)sa;
   4030 				if (inet_pton(af, addr, &sad->sin_addr) == 1) {
   4031 					sad->sin_len = sizeof(*sad);
   4032 					sad->sin_family = AF_INET;
   4033 					sad->sin_port = htons(portv);
   4034 					return (0);
   4035 				}
   4036 			} else {
   4037 				sad6 = (struct sockaddr_in6 *)sa;
   4038 				if (inet_pton(af, addr, &sad6->sin6_addr)
   4039 				    == 1) {
   4040 					sad6->sin6_len = sizeof(*sad6);
   4041 					sad6->sin6_family = AF_INET6;
   4042 					sad6->sin6_port = htons(portv);
   4043 					return (0);
   4044 				}
   4045 			}
   4046 		}
   4047 	} else {
   4048 		if (i > 0) {
   4049 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
   4050 			if (error)
   4051 				goto nfsmout;
   4052 		}
   4053 	}
   4054 	error = EPERM;
   4055 nfsmout:
   4056 	return (error);
   4057 }
   4058 
   4059 /*
   4060  * Handle an NFSv4.1 Sequence request for the session.
   4061  * If reply != NULL, use it to return the cached reply, as required.
   4062  * The client gets a cached reply via this call for callbacks, however the
   4063  * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
   4064  */
   4065 int
   4066 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
   4067     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
   4068 {
   4069 	int error;
   4070 
   4071 	error = 0;
   4072 	if (reply != NULL)
   4073 		*reply = NULL;
   4074 	if (slotid > maxslot)
   4075 		return (NFSERR_BADSLOT);
   4076 	if (seqid == slots[slotid].nfssl_seq) {
   4077 		/* A retry. */
   4078 		if (slots[slotid].nfssl_inprog != 0)
   4079 			error = NFSERR_DELAY;
   4080 		else if (slots[slotid].nfssl_reply != NULL) {
   4081 			if (reply != NULL) {
   4082 				*reply = slots[slotid].nfssl_reply;
   4083 				slots[slotid].nfssl_reply = NULL;
   4084 			}
   4085 			slots[slotid].nfssl_inprog = 1;
   4086 			error = NFSERR_REPLYFROMCACHE;
   4087 		} else
   4088 			/* No reply cached, so just do it. */
   4089 			slots[slotid].nfssl_inprog = 1;
   4090 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
   4091 		if (slots[slotid].nfssl_reply != NULL)
   4092 			m_freem(slots[slotid].nfssl_reply);
   4093 		slots[slotid].nfssl_reply = NULL;
   4094 		slots[slotid].nfssl_inprog = 1;
   4095 		slots[slotid].nfssl_seq++;
   4096 	} else
   4097 		error = NFSERR_SEQMISORDERED;
   4098 	return (error);
   4099 }
   4100 
   4101 /*
   4102  * Cache this reply for the slot.
   4103  * Use the "rep" argument to return the cached reply if repstat is set to
   4104  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
   4105  */
   4106 void
   4107 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
   4108    struct mbuf **rep)
   4109 {
   4110 
   4111 	if (repstat == NFSERR_REPLYFROMCACHE) {
   4112 		*rep = slots[slotid].nfssl_reply;
   4113 		slots[slotid].nfssl_reply = NULL;
   4114 	} else {
   4115 		if (slots[slotid].nfssl_reply != NULL)
   4116 			m_freem(slots[slotid].nfssl_reply);
   4117 		slots[slotid].nfssl_reply = *rep;
   4118 	}
   4119 	slots[slotid].nfssl_inprog = 0;
   4120 }
   4121 
   4122 /*
   4123  * Generate the xdr for an NFSv4.1 Sequence Operation.
   4124  */
   4125 APPLESTATIC void
   4126 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
   4127     struct nfsclsession *sep, int dont_replycache)
   4128 {
   4129 	uint32_t *tl, slotseq = 0;
   4130 	int error, maxslot, slotpos;
   4131 	uint8_t sessionid[NFSX_V4SESSIONID];
   4132 
   4133 	error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
   4134 	    sessionid);
   4135 	if (error != 0)
   4136 		return;
   4137 	KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
   4138 
   4139 	/* Build the Sequence arguments. */
   4140 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
   4141 	bcopy(sessionid, tl, NFSX_V4SESSIONID);
   4142 	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
   4143 	nd->nd_slotseq = tl;
   4144 	*tl++ = txdr_unsigned(slotseq);
   4145 	*tl++ = txdr_unsigned(slotpos);
   4146 	*tl++ = txdr_unsigned(maxslot);
   4147 	if (dont_replycache == 0)
   4148 		*tl = newnfs_true;
   4149 	else
   4150 		*tl = newnfs_false;
   4151 	nd->nd_flag |= ND_HASSEQUENCE;
   4152 }
   4153 
   4154 int
   4155 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
   4156     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
   4157 {
   4158 	int i, maxslot, slotpos;
   4159 	uint64_t bitval;
   4160 
   4161 	/* Find an unused slot. */
   4162 	slotpos = -1;
   4163 	maxslot = -1;
   4164 	mtx_lock(&sep->nfsess_mtx);
   4165 	do {
   4166 		bitval = 1;
   4167 		for (i = 0; i < sep->nfsess_foreslots; i++) {
   4168 			if ((bitval & sep->nfsess_slots) == 0) {
   4169 				slotpos = i;
   4170 				sep->nfsess_slots |= bitval;
   4171 				sep->nfsess_slotseq[i]++;
   4172 				*slotseqp = sep->nfsess_slotseq[i];
   4173 				break;
   4174 			}
   4175 			bitval <<= 1;
   4176 		}
   4177 		if (slotpos == -1) {
   4178 			/*
   4179 			 * If a forced dismount is in progress, just return.
   4180 			 * This RPC attempt will fail when it calls
   4181 			 * newnfs_request().
   4182 			 */
   4183 			if (nmp != NULL &&
   4184 			    (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
   4185 			    != 0) {
   4186 				mtx_unlock(&sep->nfsess_mtx);
   4187 				return (ESTALE);
   4188 			}
   4189 			/* Wake up once/sec, to check for a forced dismount. */
   4190 			(void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
   4191 			    PZERO, "nfsclseq", hz);
   4192 		}
   4193 	} while (slotpos == -1);
   4194 	/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
   4195 	bitval = 1;
   4196 	for (i = 0; i < 64; i++) {
   4197 		if ((bitval & sep->nfsess_slots) != 0)
   4198 			maxslot = i;
   4199 		bitval <<= 1;
   4200 	}
   4201 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
   4202 	mtx_unlock(&sep->nfsess_mtx);
   4203 	*slotposp = slotpos;
   4204 	*maxslotp = maxslot;
   4205 	return (0);
   4206 }
   4207 
   4208 /*
   4209  * Free a session slot.
   4210  */
   4211 APPLESTATIC void
   4212 nfsv4_freeslot(struct nfsclsession *sep, int slot)
   4213 {
   4214 	uint64_t bitval;
   4215 
   4216 	bitval = 1;
   4217 	if (slot > 0)
   4218 		bitval <<= slot;
   4219 	mtx_lock(&sep->nfsess_mtx);
   4220 	if ((bitval & sep->nfsess_slots) == 0)
   4221 		printf("freeing free slot!!\n");
   4222 	sep->nfsess_slots &= ~bitval;
   4223 	wakeup(&sep->nfsess_slots);
   4224 	mtx_unlock(&sep->nfsess_mtx);
   4225 }
   4226 
   4227