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