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