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