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