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