xref: /freebsd/sys/fs/nfsserver/nfs_nfsdserv.c (revision d8ffc21c5ca6f7d4f2d9a65dc6308699af0b6a01)
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 #include "opt_inet.h"
40 #include "opt_inet6.h"
41 /*
42  * nfs version 2, 3 and 4 server calls to vnode ops
43  * - these routines generally have 3 phases
44  *   1 - break down and validate rpc request in mbuf list
45  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
46  *       function in nfsd_port.c
47  *   3 - build the rpc reply in an mbuf list
48  * For nfsv4, these functions are called for each Op within the Compound RPC.
49  */
50 
51 #ifndef APPLEKEXT
52 #include <fs/nfs/nfsport.h>
53 #include <sys/extattr.h>
54 #include <sys/filio.h>
55 
56 /* Global vars */
57 extern u_int32_t newnfs_false, newnfs_true;
58 extern enum vtype nv34tov_type[8];
59 extern struct timeval nfsboottime;
60 extern int nfs_rootfhset;
61 extern int nfsrv_enable_crossmntpt;
62 extern int nfsrv_statehashsize;
63 extern int nfsrv_layouthashsize;
64 extern time_t nfsdev_time;
65 extern volatile int nfsrv_devidcnt;
66 extern int nfsd_debuglevel;
67 extern u_long sb_max_adj;
68 extern int nfsrv_pnfsatime;
69 extern int nfsrv_maxpnfsmirror;
70 extern int nfs_maxcopyrange;
71 #endif	/* !APPLEKEXT */
72 
73 static int	nfs_async = 0;
74 SYSCTL_DECL(_vfs_nfsd);
75 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
76     "Tell client that writes were synced even though they were not");
77 extern int	nfsrv_doflexfile;
78 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
79     &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
80 static int	nfsrv_linux42server = 1;
81 SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW,
82     &nfsrv_linux42server, 0,
83     "Enable Linux style NFSv4.2 server (non-RFC compliant)");
84 
85 /*
86  * This list defines the GSS mechanisms supported.
87  * (Don't ask me how you get these strings from the RFC stuff like
88  *  iso(1), org(3)... but someone did it, so I don't need to know.)
89  */
90 static struct nfsgss_mechlist nfsgss_mechlist[] = {
91 	{ 9, "\052\206\110\206\367\022\001\002\002", 11 },
92 	{ 0, "", 0 },
93 };
94 
95 /* local functions */
96 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
97     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
98     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
99     int *diraft_retp, nfsattrbit_t *attrbitp,
100     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
101     int pathlen);
102 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
103     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
104     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
105     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
106     NFSPROC_T *p, struct nfsexstuff *exp);
107 
108 /*
109  * nfs access service (not a part of NFS V2)
110  */
111 APPLESTATIC int
112 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
113     vnode_t vp, struct nfsexstuff *exp)
114 {
115 	u_int32_t *tl;
116 	int getret, error = 0;
117 	struct nfsvattr nva;
118 	u_int32_t testmode, nfsmode, supported = 0;
119 	accmode_t deletebit;
120 	struct thread *p = curthread;
121 
122 	if (nd->nd_repstat) {
123 		nfsrv_postopattr(nd, 1, &nva);
124 		goto out;
125 	}
126 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
127 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
128 	if ((nd->nd_flag & ND_NFSV4) &&
129 	    (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
130 	     NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
131 	     NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE |
132 	     NFSACCESS_XALIST))) {
133 		nd->nd_repstat = NFSERR_INVAL;
134 		vput(vp);
135 		goto out;
136 	}
137 	if (nfsmode & NFSACCESS_READ) {
138 		supported |= NFSACCESS_READ;
139 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
140 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
141 			nfsmode &= ~NFSACCESS_READ;
142 	}
143 	if (nfsmode & NFSACCESS_MODIFY) {
144 		supported |= NFSACCESS_MODIFY;
145 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
146 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
147 			nfsmode &= ~NFSACCESS_MODIFY;
148 	}
149 	if (nfsmode & NFSACCESS_EXTEND) {
150 		supported |= NFSACCESS_EXTEND;
151 		if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
152 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
153 			nfsmode &= ~NFSACCESS_EXTEND;
154 	}
155 	if (nfsmode & NFSACCESS_XAREAD) {
156 		supported |= NFSACCESS_XAREAD;
157 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
158 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
159 			nfsmode &= ~NFSACCESS_XAREAD;
160 	}
161 	if (nfsmode & NFSACCESS_XAWRITE) {
162 		supported |= NFSACCESS_XAWRITE;
163 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
164 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
165 			nfsmode &= ~NFSACCESS_XAWRITE;
166 	}
167 	if (nfsmode & NFSACCESS_XALIST) {
168 		supported |= NFSACCESS_XALIST;
169 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
170 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
171 			nfsmode &= ~NFSACCESS_XALIST;
172 	}
173 	if (nfsmode & NFSACCESS_DELETE) {
174 		supported |= NFSACCESS_DELETE;
175 		if (vp->v_type == VDIR)
176 			deletebit = VDELETE_CHILD;
177 		else
178 			deletebit = VDELETE;
179 		if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
180 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
181 			nfsmode &= ~NFSACCESS_DELETE;
182 	}
183 	if (vnode_vtype(vp) == VDIR)
184 		testmode = NFSACCESS_LOOKUP;
185 	else
186 		testmode = NFSACCESS_EXECUTE;
187 	if (nfsmode & testmode) {
188 		supported |= (nfsmode & testmode);
189 		if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
190 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
191 			nfsmode &= ~testmode;
192 	}
193 	nfsmode &= supported;
194 	if (nd->nd_flag & ND_NFSV3) {
195 		getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
196 		nfsrv_postopattr(nd, getret, &nva);
197 	}
198 	vput(vp);
199 	if (nd->nd_flag & ND_NFSV4) {
200 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
201 		*tl++ = txdr_unsigned(supported);
202 	} else
203 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
204 	*tl = txdr_unsigned(nfsmode);
205 
206 out:
207 	NFSEXITCODE2(0, nd);
208 	return (0);
209 nfsmout:
210 	vput(vp);
211 	NFSEXITCODE2(error, nd);
212 	return (error);
213 }
214 
215 /*
216  * nfs getattr service
217  */
218 APPLESTATIC int
219 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
220     vnode_t vp, __unused struct nfsexstuff *exp)
221 {
222 	struct nfsvattr nva;
223 	fhandle_t fh;
224 	int at_root = 0, error = 0, supports_nfsv4acls;
225 	struct nfsreferral *refp;
226 	nfsattrbit_t attrbits, tmpbits;
227 	struct mount *mp;
228 	struct vnode *tvp = NULL;
229 	struct vattr va;
230 	uint64_t mounted_on_fileno = 0;
231 	accmode_t accmode;
232 	struct thread *p = curthread;
233 
234 	if (nd->nd_repstat)
235 		goto out;
236 	if (nd->nd_flag & ND_NFSV4) {
237 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
238 		if (error) {
239 			vput(vp);
240 			goto out;
241 		}
242 
243 		/*
244 		 * Check for a referral.
245 		 */
246 		refp = nfsv4root_getreferral(vp, NULL, 0);
247 		if (refp != NULL) {
248 			(void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
249 			    &nd->nd_repstat);
250 			vput(vp);
251 			goto out;
252 		}
253 		if (nd->nd_repstat == 0) {
254 			accmode = 0;
255 			NFSSET_ATTRBIT(&tmpbits, &attrbits);
256 
257 			/*
258 			 * GETATTR with write-only attr time_access_set and time_modify_set
259 			 * should return NFS4ERR_INVAL.
260 			 */
261 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
262 					NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
263 				error = NFSERR_INVAL;
264 				vput(vp);
265 				goto out;
266 			}
267 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
268 				NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
269 				accmode |= VREAD_ACL;
270 			}
271 			if (NFSNONZERO_ATTRBIT(&tmpbits))
272 				accmode |= VREAD_ATTRIBUTES;
273 			if (accmode != 0)
274 				nd->nd_repstat = nfsvno_accchk(vp, accmode,
275 				    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
276 				    NFSACCCHK_VPISLOCKED, NULL);
277 		}
278 	}
279 	if (!nd->nd_repstat)
280 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
281 	if (!nd->nd_repstat) {
282 		if (nd->nd_flag & ND_NFSV4) {
283 			if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
284 				nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
285 			if (!nd->nd_repstat)
286 				nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
287 				    &nva, &attrbits, p);
288 			if (nd->nd_repstat == 0) {
289 				supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
290 				mp = vp->v_mount;
291 				if (nfsrv_enable_crossmntpt != 0 &&
292 				    vp->v_type == VDIR &&
293 				    (vp->v_vflag & VV_ROOT) != 0 &&
294 				    vp != rootvnode) {
295 					tvp = mp->mnt_vnodecovered;
296 					VREF(tvp);
297 					at_root = 1;
298 				} else
299 					at_root = 0;
300 				vfs_ref(mp);
301 				NFSVOPUNLOCK(vp);
302 				if (at_root != 0) {
303 					if ((nd->nd_repstat =
304 					     NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
305 						nd->nd_repstat = VOP_GETATTR(
306 						    tvp, &va, nd->nd_cred);
307 						vput(tvp);
308 					} else
309 						vrele(tvp);
310 					if (nd->nd_repstat == 0)
311 						mounted_on_fileno = (uint64_t)
312 						    va.va_fileid;
313 					else
314 						at_root = 0;
315 				}
316 				if (nd->nd_repstat == 0)
317 					nd->nd_repstat = vfs_busy(mp, 0);
318 				vfs_rel(mp);
319 				if (nd->nd_repstat == 0) {
320 					(void)nfsvno_fillattr(nd, mp, vp, &nva,
321 					    &fh, 0, &attrbits, nd->nd_cred, p,
322 					    isdgram, 1, supports_nfsv4acls,
323 					    at_root, mounted_on_fileno);
324 					vfs_unbusy(mp);
325 				}
326 				vrele(vp);
327 			} else
328 				vput(vp);
329 		} else {
330 			nfsrv_fillattr(nd, &nva);
331 			vput(vp);
332 		}
333 	} else {
334 		vput(vp);
335 	}
336 
337 out:
338 	NFSEXITCODE2(error, nd);
339 	return (error);
340 }
341 
342 /*
343  * nfs setattr service
344  */
345 APPLESTATIC int
346 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
347     vnode_t vp, struct nfsexstuff *exp)
348 {
349 	struct nfsvattr nva, nva2;
350 	u_int32_t *tl;
351 	int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
352 	int gotproxystateid;
353 	struct timespec guard = { 0, 0 };
354 	nfsattrbit_t attrbits, retbits;
355 	nfsv4stateid_t stateid;
356 	NFSACL_T *aclp = NULL;
357 	struct thread *p = curthread;
358 
359 	if (nd->nd_repstat) {
360 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
361 		goto out;
362 	}
363 #ifdef NFS4_ACL_EXTATTR_NAME
364 	aclp = acl_alloc(M_WAITOK);
365 	aclp->acl_cnt = 0;
366 #endif
367 	gotproxystateid = 0;
368 	NFSVNO_ATTRINIT(&nva);
369 	if (nd->nd_flag & ND_NFSV4) {
370 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
371 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
372 		stateid.other[0] = *tl++;
373 		stateid.other[1] = *tl++;
374 		stateid.other[2] = *tl;
375 		if (stateid.other[0] == 0x55555555 &&
376 		    stateid.other[1] == 0x55555555 &&
377 		    stateid.other[2] == 0x55555555 &&
378 		    stateid.seqid == 0xffffffff)
379 			gotproxystateid = 1;
380 	}
381 	error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
382 	if (error)
383 		goto nfsmout;
384 
385 	/* For NFSv4, only va_uid is used from nva2. */
386 	NFSZERO_ATTRBIT(&retbits);
387 	NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
388 	preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
389 	if (!nd->nd_repstat)
390 		nd->nd_repstat = preat_ret;
391 
392 	NFSZERO_ATTRBIT(&retbits);
393 	if (nd->nd_flag & ND_NFSV3) {
394 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
395 		gcheck = fxdr_unsigned(int, *tl);
396 		if (gcheck) {
397 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
398 			fxdr_nfsv3time(tl, &guard);
399 		}
400 		if (!nd->nd_repstat && gcheck &&
401 		    (nva2.na_ctime.tv_sec != guard.tv_sec ||
402 		     nva2.na_ctime.tv_nsec != guard.tv_nsec))
403 			nd->nd_repstat = NFSERR_NOT_SYNC;
404 		if (nd->nd_repstat) {
405 			vput(vp);
406 #ifdef NFS4_ACL_EXTATTR_NAME
407 			acl_free(aclp);
408 #endif
409 			nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
410 			goto out;
411 		}
412 	} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
413 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
414 
415 	/*
416 	 * Now that we have all the fields, lets do it.
417 	 * If the size is being changed write access is required, otherwise
418 	 * just check for a read only file system.
419 	 */
420 	if (!nd->nd_repstat) {
421 		if (NFSVNO_NOTSETSIZE(&nva)) {
422 			if (NFSVNO_EXRDONLY(exp) ||
423 			    (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
424 				nd->nd_repstat = EROFS;
425 		} else {
426 			if (vnode_vtype(vp) != VREG)
427 				nd->nd_repstat = EINVAL;
428 			else if (nva2.na_uid != nd->nd_cred->cr_uid ||
429 			    NFSVNO_EXSTRICTACCESS(exp))
430 				nd->nd_repstat = nfsvno_accchk(vp,
431 				    VWRITE, nd->nd_cred, exp, p,
432 				    NFSACCCHK_NOOVERRIDE,
433 				    NFSACCCHK_VPISLOCKED, NULL);
434 		}
435 	}
436 	/*
437 	 * Proxy operations from the MDS are allowed via the all 0s special
438 	 * stateid.
439 	 */
440 	if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
441 	    gotproxystateid == 0)
442 		nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
443 		    &nva, &attrbits, exp, p);
444 
445 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
446 	    /*
447 	     * For V4, try setting the attrbutes in sets, so that the
448 	     * reply bitmap will be correct for an error case.
449 	     */
450 	    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
451 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
452 		NFSVNO_ATTRINIT(&nva2);
453 		NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
454 		NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
455 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
456 		    exp);
457 		if (!nd->nd_repstat) {
458 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
459 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
460 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
461 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
462 		}
463 	    }
464 	    if (!nd->nd_repstat &&
465 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
466 		NFSVNO_ATTRINIT(&nva2);
467 		NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
468 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
469 		    exp);
470 		if (!nd->nd_repstat)
471 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
472 	    }
473 	    if (!nd->nd_repstat &&
474 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
475 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
476 		NFSVNO_ATTRINIT(&nva2);
477 		NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
478 		NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
479 		if (nva.na_vaflags & VA_UTIMES_NULL) {
480 			nva2.na_vaflags |= VA_UTIMES_NULL;
481 			NFSVNO_SETACTIVE(&nva2, vaflags);
482 		}
483 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
484 		    exp);
485 		if (!nd->nd_repstat) {
486 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
487 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
488 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
489 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
490 		}
491 	    }
492 	    if (!nd->nd_repstat &&
493 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
494 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
495 		NFSVNO_ATTRINIT(&nva2);
496 		NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
497 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
498 		    exp);
499 		if (!nd->nd_repstat) {
500 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
501 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
502 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
503 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
504 		}
505 	    }
506 
507 #ifdef NFS4_ACL_EXTATTR_NAME
508 	    if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
509 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
510 		nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
511 		if (!nd->nd_repstat)
512 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
513 	    }
514 #endif
515 	} else if (!nd->nd_repstat) {
516 		nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
517 		    exp);
518 	}
519 	if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
520 		postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
521 		if (!nd->nd_repstat)
522 			nd->nd_repstat = postat_ret;
523 	}
524 	vput(vp);
525 #ifdef NFS4_ACL_EXTATTR_NAME
526 	acl_free(aclp);
527 #endif
528 	if (nd->nd_flag & ND_NFSV3)
529 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
530 	else if (nd->nd_flag & ND_NFSV4)
531 		(void) nfsrv_putattrbit(nd, &retbits);
532 	else if (!nd->nd_repstat)
533 		nfsrv_fillattr(nd, &nva);
534 
535 out:
536 	NFSEXITCODE2(0, nd);
537 	return (0);
538 nfsmout:
539 	vput(vp);
540 #ifdef NFS4_ACL_EXTATTR_NAME
541 	acl_free(aclp);
542 #endif
543 	if (nd->nd_flag & ND_NFSV4) {
544 		/*
545 		 * For all nd_repstat, the V4 reply includes a bitmap,
546 		 * even NFSERR_BADXDR, which is what this will end up
547 		 * returning.
548 		 */
549 		(void) nfsrv_putattrbit(nd, &retbits);
550 	}
551 	NFSEXITCODE2(error, nd);
552 	return (error);
553 }
554 
555 /*
556  * nfs lookup rpc
557  * (Also performs lookup parent for v4)
558  */
559 APPLESTATIC int
560 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
561     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
562 {
563 	struct nameidata named;
564 	vnode_t vp, dirp = NULL;
565 	int error = 0, dattr_ret = 1;
566 	struct nfsvattr nva, dattr;
567 	char *bufp;
568 	u_long *hashp;
569 	struct thread *p = curthread;
570 
571 	if (nd->nd_repstat) {
572 		nfsrv_postopattr(nd, dattr_ret, &dattr);
573 		goto out;
574 	}
575 
576 	/*
577 	 * For some reason, if dp is a symlink, the error
578 	 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
579 	 */
580 	if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
581 		nd->nd_repstat = NFSERR_SYMLINK;
582 		vrele(dp);
583 		goto out;
584 	}
585 
586 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
587 	    LOCKLEAF | SAVESTART);
588 	nfsvno_setpathbuf(&named, &bufp, &hashp);
589 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
590 	if (error) {
591 		vrele(dp);
592 		nfsvno_relpathbuf(&named);
593 		goto out;
594 	}
595 	if (!nd->nd_repstat) {
596 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
597 	} else {
598 		vrele(dp);
599 		nfsvno_relpathbuf(&named);
600 	}
601 	if (nd->nd_repstat) {
602 		if (dirp) {
603 			if (nd->nd_flag & ND_NFSV3)
604 				dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
605 				    0, NULL);
606 			vrele(dirp);
607 		}
608 		if (nd->nd_flag & ND_NFSV3)
609 			nfsrv_postopattr(nd, dattr_ret, &dattr);
610 		goto out;
611 	}
612 	if (named.ni_startdir)
613 		vrele(named.ni_startdir);
614 	nfsvno_relpathbuf(&named);
615 	vp = named.ni_vp;
616 	if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
617 	    vp->v_type != VDIR && vp->v_type != VLNK)
618 		/*
619 		 * Only allow lookup of VDIR and VLNK for traversal of
620 		 * non-exported volumes during NFSv4 mounting.
621 		 */
622 		nd->nd_repstat = ENOENT;
623 	if (nd->nd_repstat == 0)
624 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
625 	if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
626 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
627 	if (vpp != NULL && nd->nd_repstat == 0)
628 		*vpp = vp;
629 	else
630 		vput(vp);
631 	if (dirp) {
632 		if (nd->nd_flag & ND_NFSV3)
633 			dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
634 			    NULL);
635 		vrele(dirp);
636 	}
637 	if (nd->nd_repstat) {
638 		if (nd->nd_flag & ND_NFSV3)
639 			nfsrv_postopattr(nd, dattr_ret, &dattr);
640 		goto out;
641 	}
642 	if (nd->nd_flag & ND_NFSV2) {
643 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
644 		nfsrv_fillattr(nd, &nva);
645 	} else if (nd->nd_flag & ND_NFSV3) {
646 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
647 		nfsrv_postopattr(nd, 0, &nva);
648 		nfsrv_postopattr(nd, dattr_ret, &dattr);
649 	}
650 
651 out:
652 	NFSEXITCODE2(error, nd);
653 	return (error);
654 }
655 
656 /*
657  * nfs readlink service
658  */
659 APPLESTATIC int
660 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
661     vnode_t vp, __unused struct nfsexstuff *exp)
662 {
663 	u_int32_t *tl;
664 	mbuf_t mp = NULL, mpend = NULL;
665 	int getret = 1, len;
666 	struct nfsvattr nva;
667 	struct thread *p = curthread;
668 
669 	if (nd->nd_repstat) {
670 		nfsrv_postopattr(nd, getret, &nva);
671 		goto out;
672 	}
673 	if (vnode_vtype(vp) != VLNK) {
674 		if (nd->nd_flag & ND_NFSV2)
675 			nd->nd_repstat = ENXIO;
676 		else
677 			nd->nd_repstat = EINVAL;
678 	}
679 	if (!nd->nd_repstat)
680 		nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
681 		    &mp, &mpend, &len);
682 	if (nd->nd_flag & ND_NFSV3)
683 		getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
684 	vput(vp);
685 	if (nd->nd_flag & ND_NFSV3)
686 		nfsrv_postopattr(nd, getret, &nva);
687 	if (nd->nd_repstat)
688 		goto out;
689 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
690 	*tl = txdr_unsigned(len);
691 	mbuf_setnext(nd->nd_mb, mp);
692 	nd->nd_mb = mpend;
693 	nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
694 
695 out:
696 	NFSEXITCODE2(0, nd);
697 	return (0);
698 }
699 
700 /*
701  * nfs read service
702  */
703 APPLESTATIC int
704 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
705     vnode_t vp, struct nfsexstuff *exp)
706 {
707 	u_int32_t *tl;
708 	int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
709 	mbuf_t m2, m3;
710 	struct nfsvattr nva;
711 	off_t off = 0x0;
712 	struct nfsstate st, *stp = &st;
713 	struct nfslock lo, *lop = &lo;
714 	nfsv4stateid_t stateid;
715 	nfsquad_t clientid;
716 	struct thread *p = curthread;
717 
718 	if (nd->nd_repstat) {
719 		nfsrv_postopattr(nd, getret, &nva);
720 		goto out;
721 	}
722 	if (nd->nd_flag & ND_NFSV2) {
723 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
724 		off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
725 		reqlen = fxdr_unsigned(int, *tl);
726 	} else if (nd->nd_flag & ND_NFSV3) {
727 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
728 		off = fxdr_hyper(tl);
729 		tl += 2;
730 		reqlen = fxdr_unsigned(int, *tl);
731 	} else {
732 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
733 		reqlen = fxdr_unsigned(int, *(tl + 6));
734 	}
735 	if (reqlen > NFS_SRVMAXDATA(nd)) {
736 		reqlen = NFS_SRVMAXDATA(nd);
737 	} else if (reqlen < 0) {
738 		error = EBADRPC;
739 		goto nfsmout;
740 	}
741 	gotproxystateid = 0;
742 	if (nd->nd_flag & ND_NFSV4) {
743 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
744 		lop->lo_flags = NFSLCK_READ;
745 		stp->ls_ownerlen = 0;
746 		stp->ls_op = NULL;
747 		stp->ls_uid = nd->nd_cred->cr_uid;
748 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
749 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
750 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
751 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
752 			if ((nd->nd_flag & ND_NFSV41) != 0)
753 				clientid.qval = nd->nd_clientid.qval;
754 			else if (nd->nd_clientid.qval != clientid.qval)
755 				printf("EEK1 multiple clids\n");
756 		} else {
757 			if ((nd->nd_flag & ND_NFSV41) != 0)
758 				printf("EEK! no clientid from session\n");
759 			nd->nd_flag |= ND_IMPLIEDCLID;
760 			nd->nd_clientid.qval = clientid.qval;
761 		}
762 		stp->ls_stateid.other[2] = *tl++;
763 		/*
764 		 * Don't allow the client to use a special stateid for a DS op.
765 		 */
766 		if ((nd->nd_flag & ND_DSSERVER) != 0 &&
767 		    ((stp->ls_stateid.other[0] == 0x0 &&
768 		    stp->ls_stateid.other[1] == 0x0 &&
769 		    stp->ls_stateid.other[2] == 0x0) ||
770 		    (stp->ls_stateid.other[0] == 0xffffffff &&
771 		    stp->ls_stateid.other[1] == 0xffffffff &&
772 		    stp->ls_stateid.other[2] == 0xffffffff) ||
773 		    stp->ls_stateid.seqid != 0))
774 			nd->nd_repstat = NFSERR_BADSTATEID;
775 		/* However, allow the proxy stateid. */
776 		if (stp->ls_stateid.seqid == 0xffffffff &&
777 		    stp->ls_stateid.other[0] == 0x55555555 &&
778 		    stp->ls_stateid.other[1] == 0x55555555 &&
779 		    stp->ls_stateid.other[2] == 0x55555555)
780 			gotproxystateid = 1;
781 		off = fxdr_hyper(tl);
782 		lop->lo_first = off;
783 		tl += 2;
784 		lop->lo_end = off + reqlen;
785 		/*
786 		 * Paranoia, just in case it wraps around.
787 		 */
788 		if (lop->lo_end < off)
789 			lop->lo_end = NFS64BITSSET;
790 	}
791 	if (vnode_vtype(vp) != VREG) {
792 		if (nd->nd_flag & ND_NFSV3)
793 			nd->nd_repstat = EINVAL;
794 		else
795 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
796 			    EINVAL;
797 	}
798 	getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
799 	if (!nd->nd_repstat)
800 		nd->nd_repstat = getret;
801 	if (!nd->nd_repstat &&
802 	    (nva.na_uid != nd->nd_cred->cr_uid ||
803 	     NFSVNO_EXSTRICTACCESS(exp))) {
804 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
805 		    nd->nd_cred, exp, p,
806 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
807 		if (nd->nd_repstat)
808 			nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
809 			    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
810 			    NFSACCCHK_VPISLOCKED, NULL);
811 	}
812 	/*
813 	 * DS reads are marked by ND_DSSERVER or use the proxy special
814 	 * stateid.
815 	 */
816 	if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
817 	    ND_NFSV4 && gotproxystateid == 0)
818 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
819 		    &stateid, exp, nd, p);
820 	if (nd->nd_repstat) {
821 		vput(vp);
822 		if (nd->nd_flag & ND_NFSV3)
823 			nfsrv_postopattr(nd, getret, &nva);
824 		goto out;
825 	}
826 	if (off >= nva.na_size) {
827 		cnt = 0;
828 		eof = 1;
829 	} else if (reqlen == 0)
830 		cnt = 0;
831 	else if ((off + reqlen) >= nva.na_size) {
832 		cnt = nva.na_size - off;
833 		eof = 1;
834 	} else
835 		cnt = reqlen;
836 	m3 = NULL;
837 	if (cnt > 0) {
838 		nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
839 		    &m3, &m2);
840 		if (!(nd->nd_flag & ND_NFSV4)) {
841 			getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
842 			if (!nd->nd_repstat)
843 				nd->nd_repstat = getret;
844 		}
845 		if (nd->nd_repstat) {
846 			vput(vp);
847 			if (m3)
848 				mbuf_freem(m3);
849 			if (nd->nd_flag & ND_NFSV3)
850 				nfsrv_postopattr(nd, getret, &nva);
851 			goto out;
852 		}
853 	}
854 	vput(vp);
855 	if (nd->nd_flag & ND_NFSV2) {
856 		nfsrv_fillattr(nd, &nva);
857 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
858 	} else {
859 		if (nd->nd_flag & ND_NFSV3) {
860 			nfsrv_postopattr(nd, getret, &nva);
861 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
862 			*tl++ = txdr_unsigned(cnt);
863 		} else
864 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
865 		if (eof)
866 			*tl++ = newnfs_true;
867 		else
868 			*tl++ = newnfs_false;
869 	}
870 	*tl = txdr_unsigned(cnt);
871 	if (m3) {
872 		mbuf_setnext(nd->nd_mb, m3);
873 		nd->nd_mb = m2;
874 		nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
875 	}
876 
877 out:
878 	NFSEXITCODE2(0, nd);
879 	return (0);
880 nfsmout:
881 	vput(vp);
882 	NFSEXITCODE2(error, nd);
883 	return (error);
884 }
885 
886 /*
887  * nfs write service
888  */
889 APPLESTATIC int
890 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
891     vnode_t vp, struct nfsexstuff *exp)
892 {
893 	u_int32_t *tl;
894 	struct nfsvattr nva, forat;
895 	int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
896 	int gotproxystateid, stable = NFSWRITE_FILESYNC;
897 	off_t off;
898 	struct nfsstate st, *stp = &st;
899 	struct nfslock lo, *lop = &lo;
900 	nfsv4stateid_t stateid;
901 	nfsquad_t clientid;
902 	nfsattrbit_t attrbits;
903 	struct thread *p = curthread;
904 
905 	if (nd->nd_repstat) {
906 		nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
907 		goto out;
908 	}
909 	gotproxystateid = 0;
910 	if (nd->nd_flag & ND_NFSV2) {
911 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
912 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
913 		tl += 2;
914 		retlen = len = fxdr_unsigned(int32_t, *tl);
915 	} else if (nd->nd_flag & ND_NFSV3) {
916 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
917 		off = fxdr_hyper(tl);
918 		tl += 3;
919 		stable = fxdr_unsigned(int, *tl++);
920 		retlen = len = fxdr_unsigned(int32_t, *tl);
921 	} else {
922 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
923 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
924 		lop->lo_flags = NFSLCK_WRITE;
925 		stp->ls_ownerlen = 0;
926 		stp->ls_op = NULL;
927 		stp->ls_uid = nd->nd_cred->cr_uid;
928 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
929 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
930 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
931 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
932 			if ((nd->nd_flag & ND_NFSV41) != 0)
933 				clientid.qval = nd->nd_clientid.qval;
934 			else if (nd->nd_clientid.qval != clientid.qval)
935 				printf("EEK2 multiple clids\n");
936 		} else {
937 			if ((nd->nd_flag & ND_NFSV41) != 0)
938 				printf("EEK! no clientid from session\n");
939 			nd->nd_flag |= ND_IMPLIEDCLID;
940 			nd->nd_clientid.qval = clientid.qval;
941 		}
942 		stp->ls_stateid.other[2] = *tl++;
943 		/*
944 		 * Don't allow the client to use a special stateid for a DS op.
945 		 */
946 		if ((nd->nd_flag & ND_DSSERVER) != 0 &&
947 		    ((stp->ls_stateid.other[0] == 0x0 &&
948 		    stp->ls_stateid.other[1] == 0x0 &&
949 		    stp->ls_stateid.other[2] == 0x0) ||
950 		    (stp->ls_stateid.other[0] == 0xffffffff &&
951 		    stp->ls_stateid.other[1] == 0xffffffff &&
952 		    stp->ls_stateid.other[2] == 0xffffffff) ||
953 		    stp->ls_stateid.seqid != 0))
954 			nd->nd_repstat = NFSERR_BADSTATEID;
955 		/* However, allow the proxy stateid. */
956 		if (stp->ls_stateid.seqid == 0xffffffff &&
957 		    stp->ls_stateid.other[0] == 0x55555555 &&
958 		    stp->ls_stateid.other[1] == 0x55555555 &&
959 		    stp->ls_stateid.other[2] == 0x55555555)
960 			gotproxystateid = 1;
961 		off = fxdr_hyper(tl);
962 		lop->lo_first = off;
963 		tl += 2;
964 		stable = fxdr_unsigned(int, *tl++);
965 		retlen = len = fxdr_unsigned(int32_t, *tl);
966 		lop->lo_end = off + len;
967 		/*
968 		 * Paranoia, just in case it wraps around, which shouldn't
969 		 * ever happen anyhow.
970 		 */
971 		if (lop->lo_end < lop->lo_first)
972 			lop->lo_end = NFS64BITSSET;
973 	}
974 
975 	if (retlen > NFS_SRVMAXIO || retlen < 0)
976 		nd->nd_repstat = EIO;
977 	if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
978 		if (nd->nd_flag & ND_NFSV3)
979 			nd->nd_repstat = EINVAL;
980 		else
981 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
982 			    EINVAL;
983 	}
984 	NFSZERO_ATTRBIT(&attrbits);
985 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
986 	forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
987 	if (!nd->nd_repstat)
988 		nd->nd_repstat = forat_ret;
989 	if (!nd->nd_repstat &&
990 	    (forat.na_uid != nd->nd_cred->cr_uid ||
991 	     NFSVNO_EXSTRICTACCESS(exp)))
992 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
993 		    nd->nd_cred, exp, p,
994 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
995 	/*
996 	 * DS reads are marked by ND_DSSERVER or use the proxy special
997 	 * stateid.
998 	 */
999 	if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
1000 	    ND_NFSV4 && gotproxystateid == 0)
1001 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1002 		    &stateid, exp, nd, p);
1003 	if (nd->nd_repstat) {
1004 		vput(vp);
1005 		if (nd->nd_flag & ND_NFSV3)
1006 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1007 		goto out;
1008 	}
1009 
1010 	/*
1011 	 * For NFS Version 2, it is not obvious what a write of zero length
1012 	 * should do, but I might as well be consistent with Version 3,
1013 	 * which is to return ok so long as there are no permission problems.
1014 	 */
1015 	if (retlen > 0) {
1016 		nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
1017 		    nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1018 		error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1019 		if (error)
1020 			goto nfsmout;
1021 	}
1022 	if (nd->nd_flag & ND_NFSV4)
1023 		aftat_ret = 0;
1024 	else
1025 		aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1026 	vput(vp);
1027 	if (!nd->nd_repstat)
1028 		nd->nd_repstat = aftat_ret;
1029 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1030 		if (nd->nd_flag & ND_NFSV3)
1031 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1032 		if (nd->nd_repstat)
1033 			goto out;
1034 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1035 		*tl++ = txdr_unsigned(retlen);
1036 		/*
1037 		 * If nfs_async is set, then pretend the write was FILESYNC.
1038 		 * Warning: Doing this violates RFC1813 and runs a risk
1039 		 * of data written by a client being lost when the server
1040 		 * crashes/reboots.
1041 		 */
1042 		if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1043 			*tl++ = txdr_unsigned(stable);
1044 		else
1045 			*tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1046 		/*
1047 		 * Actually, there is no need to txdr these fields,
1048 		 * but it may make the values more human readable,
1049 		 * for debugging purposes.
1050 		 */
1051 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
1052 		*tl = txdr_unsigned(nfsboottime.tv_usec);
1053 	} else if (!nd->nd_repstat)
1054 		nfsrv_fillattr(nd, &nva);
1055 
1056 out:
1057 	NFSEXITCODE2(0, nd);
1058 	return (0);
1059 nfsmout:
1060 	vput(vp);
1061 	NFSEXITCODE2(error, nd);
1062 	return (error);
1063 }
1064 
1065 /*
1066  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1067  * now does a truncate to 0 length via. setattr if it already exists
1068  * The core creation routine has been extracted out into nfsrv_creatsub(),
1069  * so it can also be used by nfsrv_open() for V4.
1070  */
1071 APPLESTATIC int
1072 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1073     vnode_t dp, struct nfsexstuff *exp)
1074 {
1075 	struct nfsvattr nva, dirfor, diraft;
1076 	struct nfsv2_sattr *sp;
1077 	struct nameidata named;
1078 	u_int32_t *tl;
1079 	int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1080 	int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1081 	NFSDEV_T rdev = 0;
1082 	vnode_t vp = NULL, dirp = NULL;
1083 	fhandle_t fh;
1084 	char *bufp;
1085 	u_long *hashp;
1086 	enum vtype vtyp;
1087 	int32_t cverf[2], tverf[2] = { 0, 0 };
1088 	struct thread *p = curthread;
1089 
1090 	if (nd->nd_repstat) {
1091 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1092 		goto out;
1093 	}
1094 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1095 	    LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
1096 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1097 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1098 	if (error)
1099 		goto nfsmout;
1100 	if (!nd->nd_repstat) {
1101 		NFSVNO_ATTRINIT(&nva);
1102 		if (nd->nd_flag & ND_NFSV2) {
1103 			NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1104 			vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1105 			if (vtyp == VNON)
1106 				vtyp = VREG;
1107 			NFSVNO_SETATTRVAL(&nva, type, vtyp);
1108 			NFSVNO_SETATTRVAL(&nva, mode,
1109 			    nfstov_mode(sp->sa_mode));
1110 			switch (nva.na_type) {
1111 			case VREG:
1112 				tsize = fxdr_unsigned(int32_t, sp->sa_size);
1113 				if (tsize != -1)
1114 					NFSVNO_SETATTRVAL(&nva, size,
1115 					    (u_quad_t)tsize);
1116 				break;
1117 			case VCHR:
1118 			case VBLK:
1119 			case VFIFO:
1120 				rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1121 				break;
1122 			default:
1123 				break;
1124 			}
1125 		} else {
1126 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1127 			how = fxdr_unsigned(int, *tl);
1128 			switch (how) {
1129 			case NFSCREATE_GUARDED:
1130 			case NFSCREATE_UNCHECKED:
1131 				error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1132 				if (error)
1133 					goto nfsmout;
1134 				break;
1135 			case NFSCREATE_EXCLUSIVE:
1136 				NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1137 				cverf[0] = *tl++;
1138 				cverf[1] = *tl;
1139 				exclusive_flag = 1;
1140 				break;
1141 			}
1142 			NFSVNO_SETATTRVAL(&nva, type, VREG);
1143 		}
1144 	}
1145 	if (nd->nd_repstat) {
1146 		nfsvno_relpathbuf(&named);
1147 		if (nd->nd_flag & ND_NFSV3) {
1148 			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1149 			    NULL);
1150 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1151 			    &diraft);
1152 		}
1153 		vput(dp);
1154 		goto out;
1155 	}
1156 
1157 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1158 	if (dirp) {
1159 		if (nd->nd_flag & ND_NFSV2) {
1160 			vrele(dirp);
1161 			dirp = NULL;
1162 		} else {
1163 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1164 			    NULL);
1165 		}
1166 	}
1167 	if (nd->nd_repstat) {
1168 		if (nd->nd_flag & ND_NFSV3)
1169 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1170 			    &diraft);
1171 		if (dirp)
1172 			vrele(dirp);
1173 		goto out;
1174 	}
1175 
1176 	if (!(nd->nd_flag & ND_NFSV2)) {
1177 		switch (how) {
1178 		case NFSCREATE_GUARDED:
1179 			if (named.ni_vp)
1180 				nd->nd_repstat = EEXIST;
1181 			break;
1182 		case NFSCREATE_UNCHECKED:
1183 			break;
1184 		case NFSCREATE_EXCLUSIVE:
1185 			if (named.ni_vp == NULL)
1186 				NFSVNO_SETATTRVAL(&nva, mode, 0);
1187 			break;
1188 		}
1189 	}
1190 
1191 	/*
1192 	 * Iff doesn't exist, create it
1193 	 * otherwise just truncate to 0 length
1194 	 *   should I set the mode too ?
1195 	 */
1196 	nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1197 	    &exclusive_flag, cverf, rdev, exp);
1198 
1199 	if (!nd->nd_repstat) {
1200 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1201 		if (!nd->nd_repstat)
1202 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1203 			    NULL);
1204 		vput(vp);
1205 		if (!nd->nd_repstat) {
1206 			tverf[0] = nva.na_atime.tv_sec;
1207 			tverf[1] = nva.na_atime.tv_nsec;
1208 		}
1209 	}
1210 	if (nd->nd_flag & ND_NFSV2) {
1211 		if (!nd->nd_repstat) {
1212 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1213 			nfsrv_fillattr(nd, &nva);
1214 		}
1215 	} else {
1216 		if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1217 		    || cverf[1] != tverf[1]))
1218 			nd->nd_repstat = EEXIST;
1219 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1220 		vrele(dirp);
1221 		if (!nd->nd_repstat) {
1222 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1223 			nfsrv_postopattr(nd, 0, &nva);
1224 		}
1225 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1226 	}
1227 
1228 out:
1229 	NFSEXITCODE2(0, nd);
1230 	return (0);
1231 nfsmout:
1232 	vput(dp);
1233 	nfsvno_relpathbuf(&named);
1234 	NFSEXITCODE2(error, nd);
1235 	return (error);
1236 }
1237 
1238 /*
1239  * nfs v3 mknod service (and v4 create)
1240  */
1241 APPLESTATIC int
1242 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1243     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1244 {
1245 	struct nfsvattr nva, dirfor, diraft;
1246 	u_int32_t *tl;
1247 	struct nameidata named;
1248 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1249 	u_int32_t major, minor;
1250 	enum vtype vtyp = VNON;
1251 	nfstype nfs4type = NFNON;
1252 	vnode_t vp, dirp = NULL;
1253 	nfsattrbit_t attrbits;
1254 	char *bufp = NULL, *pathcp = NULL;
1255 	u_long *hashp, cnflags;
1256 	NFSACL_T *aclp = NULL;
1257 	struct thread *p = curthread;
1258 
1259 	NFSVNO_ATTRINIT(&nva);
1260 	cnflags = (LOCKPARENT | SAVESTART);
1261 	if (nd->nd_repstat) {
1262 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1263 		goto out;
1264 	}
1265 #ifdef NFS4_ACL_EXTATTR_NAME
1266 	aclp = acl_alloc(M_WAITOK);
1267 	aclp->acl_cnt = 0;
1268 #endif
1269 
1270 	/*
1271 	 * For V4, the creation stuff is here, Yuck!
1272 	 */
1273 	if (nd->nd_flag & ND_NFSV4) {
1274 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1275 		vtyp = nfsv34tov_type(*tl);
1276 		nfs4type = fxdr_unsigned(nfstype, *tl);
1277 		switch (nfs4type) {
1278 		case NFLNK:
1279 			error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1280 			    &pathlen);
1281 			if (error)
1282 				goto nfsmout;
1283 			break;
1284 		case NFCHR:
1285 		case NFBLK:
1286 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1287 			major = fxdr_unsigned(u_int32_t, *tl++);
1288 			minor = fxdr_unsigned(u_int32_t, *tl);
1289 			nva.na_rdev = NFSMAKEDEV(major, minor);
1290 			break;
1291 		case NFSOCK:
1292 		case NFFIFO:
1293 			break;
1294 		case NFDIR:
1295 			cnflags = (LOCKPARENT | SAVENAME);
1296 			break;
1297 		default:
1298 			nd->nd_repstat = NFSERR_BADTYPE;
1299 			vrele(dp);
1300 #ifdef NFS4_ACL_EXTATTR_NAME
1301 			acl_free(aclp);
1302 #endif
1303 			goto out;
1304 		}
1305 	}
1306 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1307 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1308 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1309 	if (error)
1310 		goto nfsmout;
1311 	if (!nd->nd_repstat) {
1312 		if (nd->nd_flag & ND_NFSV3) {
1313 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1314 			vtyp = nfsv34tov_type(*tl);
1315 		}
1316 		error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1317 		if (error)
1318 			goto nfsmout;
1319 		nva.na_type = vtyp;
1320 		if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1321 		    (vtyp == VCHR || vtyp == VBLK)) {
1322 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1323 			major = fxdr_unsigned(u_int32_t, *tl++);
1324 			minor = fxdr_unsigned(u_int32_t, *tl);
1325 			nva.na_rdev = NFSMAKEDEV(major, minor);
1326 		}
1327 	}
1328 
1329 	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1330 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1331 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1332 		    dirfor.na_gid == nva.na_gid)
1333 			NFSVNO_UNSET(&nva, gid);
1334 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1335 	}
1336 	if (nd->nd_repstat) {
1337 		vrele(dp);
1338 #ifdef NFS4_ACL_EXTATTR_NAME
1339 		acl_free(aclp);
1340 #endif
1341 		nfsvno_relpathbuf(&named);
1342 		if (pathcp)
1343 			free(pathcp, M_TEMP);
1344 		if (nd->nd_flag & ND_NFSV3)
1345 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1346 			    &diraft);
1347 		goto out;
1348 	}
1349 
1350 	/*
1351 	 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1352 	 * in va_mode, so we'll have to set a default here.
1353 	 */
1354 	if (NFSVNO_NOTSETMODE(&nva)) {
1355 		if (vtyp == VLNK)
1356 			nva.na_mode = 0755;
1357 		else
1358 			nva.na_mode = 0400;
1359 	}
1360 
1361 	if (vtyp == VDIR)
1362 		named.ni_cnd.cn_flags |= WILLBEDIR;
1363 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1364 	if (nd->nd_repstat) {
1365 		if (dirp) {
1366 			if (nd->nd_flag & ND_NFSV3)
1367 				dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1368 				    p, 0, NULL);
1369 			vrele(dirp);
1370 		}
1371 #ifdef NFS4_ACL_EXTATTR_NAME
1372 		acl_free(aclp);
1373 #endif
1374 		if (nd->nd_flag & ND_NFSV3)
1375 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1376 			    &diraft);
1377 		goto out;
1378 	}
1379 	if (dirp)
1380 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1381 
1382 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1383 		if (vtyp == VDIR) {
1384 			nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1385 			    &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1386 			    exp);
1387 #ifdef NFS4_ACL_EXTATTR_NAME
1388 			acl_free(aclp);
1389 #endif
1390 			goto out;
1391 		} else if (vtyp == VLNK) {
1392 			nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1393 			    &dirfor, &diraft, &diraft_ret, &attrbits,
1394 			    aclp, p, exp, pathcp, pathlen);
1395 #ifdef NFS4_ACL_EXTATTR_NAME
1396 			acl_free(aclp);
1397 #endif
1398 			free(pathcp, M_TEMP);
1399 			goto out;
1400 		}
1401 	}
1402 
1403 	nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1404 	if (!nd->nd_repstat) {
1405 		vp = named.ni_vp;
1406 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1407 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1408 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1409 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1410 			    NULL);
1411 		if (vpp != NULL && nd->nd_repstat == 0) {
1412 			NFSVOPUNLOCK(vp);
1413 			*vpp = vp;
1414 		} else
1415 			vput(vp);
1416 	}
1417 
1418 	diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1419 	vrele(dirp);
1420 	if (!nd->nd_repstat) {
1421 		if (nd->nd_flag & ND_NFSV3) {
1422 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1423 			nfsrv_postopattr(nd, 0, &nva);
1424 		} else {
1425 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1426 			*tl++ = newnfs_false;
1427 			txdr_hyper(dirfor.na_filerev, tl);
1428 			tl += 2;
1429 			txdr_hyper(diraft.na_filerev, tl);
1430 			(void) nfsrv_putattrbit(nd, &attrbits);
1431 		}
1432 	}
1433 	if (nd->nd_flag & ND_NFSV3)
1434 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1435 #ifdef NFS4_ACL_EXTATTR_NAME
1436 	acl_free(aclp);
1437 #endif
1438 
1439 out:
1440 	NFSEXITCODE2(0, nd);
1441 	return (0);
1442 nfsmout:
1443 	vrele(dp);
1444 #ifdef NFS4_ACL_EXTATTR_NAME
1445 	acl_free(aclp);
1446 #endif
1447 	if (bufp)
1448 		nfsvno_relpathbuf(&named);
1449 	if (pathcp)
1450 		free(pathcp, M_TEMP);
1451 
1452 	NFSEXITCODE2(error, nd);
1453 	return (error);
1454 }
1455 
1456 /*
1457  * nfs remove service
1458  */
1459 APPLESTATIC int
1460 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1461     vnode_t dp, struct nfsexstuff *exp)
1462 {
1463 	struct nameidata named;
1464 	u_int32_t *tl;
1465 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
1466 	vnode_t dirp = NULL;
1467 	struct nfsvattr dirfor, diraft;
1468 	char *bufp;
1469 	u_long *hashp;
1470 	struct thread *p = curthread;
1471 
1472 	if (nd->nd_repstat) {
1473 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1474 		goto out;
1475 	}
1476 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1477 	    LOCKPARENT | LOCKLEAF);
1478 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1479 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1480 	if (error) {
1481 		vput(dp);
1482 		nfsvno_relpathbuf(&named);
1483 		goto out;
1484 	}
1485 	if (!nd->nd_repstat) {
1486 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1487 	} else {
1488 		vput(dp);
1489 		nfsvno_relpathbuf(&named);
1490 	}
1491 	if (dirp) {
1492 		if (!(nd->nd_flag & ND_NFSV2)) {
1493 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1494 			    NULL);
1495 		} else {
1496 			vrele(dirp);
1497 			dirp = NULL;
1498 		}
1499 	}
1500 	if (!nd->nd_repstat) {
1501 		if (nd->nd_flag & ND_NFSV4) {
1502 			if (vnode_vtype(named.ni_vp) == VDIR)
1503 				nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1504 				    nd->nd_cred, p, exp);
1505 			else
1506 				nd->nd_repstat = nfsvno_removesub(&named, 1,
1507 				    nd->nd_cred, p, exp);
1508 		} else if (nd->nd_procnum == NFSPROC_RMDIR) {
1509 			nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1510 			    nd->nd_cred, p, exp);
1511 		} else {
1512 			nd->nd_repstat = nfsvno_removesub(&named, 0,
1513 			    nd->nd_cred, p, exp);
1514 		}
1515 	}
1516 	if (!(nd->nd_flag & ND_NFSV2)) {
1517 		if (dirp) {
1518 			diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1519 			    NULL);
1520 			vrele(dirp);
1521 		}
1522 		if (nd->nd_flag & ND_NFSV3) {
1523 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1524 			    &diraft);
1525 		} else if (!nd->nd_repstat) {
1526 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1527 			*tl++ = newnfs_false;
1528 			txdr_hyper(dirfor.na_filerev, tl);
1529 			tl += 2;
1530 			txdr_hyper(diraft.na_filerev, tl);
1531 		}
1532 	}
1533 
1534 out:
1535 	NFSEXITCODE2(error, nd);
1536 	return (error);
1537 }
1538 
1539 /*
1540  * nfs rename service
1541  */
1542 APPLESTATIC int
1543 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1544     vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1545 {
1546 	u_int32_t *tl;
1547 	int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1548 	int tdirfor_ret = 1, tdiraft_ret = 1;
1549 	struct nameidata fromnd, tond;
1550 	vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1551 	struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1552 	struct nfsexstuff tnes;
1553 	struct nfsrvfh tfh;
1554 	char *bufp, *tbufp = NULL;
1555 	u_long *hashp;
1556 	fhandle_t fh;
1557 	struct thread *p = curthread;
1558 
1559 	if (nd->nd_repstat) {
1560 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1561 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1562 		goto out;
1563 	}
1564 	if (!(nd->nd_flag & ND_NFSV2))
1565 		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1566 	tond.ni_cnd.cn_nameiop = 0;
1567 	tond.ni_startdir = NULL;
1568 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1569 	nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1570 	error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1571 	if (error) {
1572 		vput(dp);
1573 		if (todp)
1574 			vrele(todp);
1575 		nfsvno_relpathbuf(&fromnd);
1576 		goto out;
1577 	}
1578 	/*
1579 	 * Unlock dp in this code section, so it is unlocked before
1580 	 * tdp gets locked. This avoids a potential LOR if tdp is the
1581 	 * parent directory of dp.
1582 	 */
1583 	if (nd->nd_flag & ND_NFSV4) {
1584 		tdp = todp;
1585 		tnes = *toexp;
1586 		if (dp != tdp) {
1587 			NFSVOPUNLOCK(dp);
1588 			/* Might lock tdp. */
1589 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1590 			    NULL);
1591 		} else {
1592 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1593 			    NULL);
1594 			NFSVOPUNLOCK(dp);
1595 		}
1596 	} else {
1597 		tfh.nfsrvfh_len = 0;
1598 		error = nfsrv_mtofh(nd, &tfh);
1599 		if (error == 0)
1600 			error = nfsvno_getfh(dp, &fh, p);
1601 		if (error) {
1602 			vput(dp);
1603 			/* todp is always NULL except NFSv4 */
1604 			nfsvno_relpathbuf(&fromnd);
1605 			goto out;
1606 		}
1607 
1608 		/* If this is the same file handle, just VREF() the vnode. */
1609 		if (tfh.nfsrvfh_len == NFSX_MYFH &&
1610 		    !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1611 			VREF(dp);
1612 			tdp = dp;
1613 			tnes = *exp;
1614 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1615 			    NULL);
1616 			NFSVOPUNLOCK(dp);
1617 		} else {
1618 			NFSVOPUNLOCK(dp);
1619 			nd->nd_cred->cr_uid = nd->nd_saveduid;
1620 			nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1621 			    0);	/* Locks tdp. */
1622 			if (tdp) {
1623 				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1624 				    p, 1, NULL);
1625 				NFSVOPUNLOCK(tdp);
1626 			}
1627 		}
1628 	}
1629 	NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1630 	nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1631 	if (!nd->nd_repstat) {
1632 		error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1633 		if (error) {
1634 			if (tdp)
1635 				vrele(tdp);
1636 			vrele(dp);
1637 			nfsvno_relpathbuf(&fromnd);
1638 			nfsvno_relpathbuf(&tond);
1639 			goto out;
1640 		}
1641 	}
1642 	if (nd->nd_repstat) {
1643 		if (nd->nd_flag & ND_NFSV3) {
1644 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1645 			    &fdiraft);
1646 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1647 			    &tdiraft);
1648 		}
1649 		if (tdp)
1650 			vrele(tdp);
1651 		vrele(dp);
1652 		nfsvno_relpathbuf(&fromnd);
1653 		nfsvno_relpathbuf(&tond);
1654 		goto out;
1655 	}
1656 
1657 	/*
1658 	 * Done parsing, now down to business.
1659 	 */
1660 	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1661 	if (nd->nd_repstat) {
1662 		if (nd->nd_flag & ND_NFSV3) {
1663 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1664 			    &fdiraft);
1665 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1666 			    &tdiraft);
1667 		}
1668 		if (fdirp)
1669 			vrele(fdirp);
1670 		if (tdp)
1671 			vrele(tdp);
1672 		nfsvno_relpathbuf(&tond);
1673 		goto out;
1674 	}
1675 	if (vnode_vtype(fromnd.ni_vp) == VDIR)
1676 		tond.ni_cnd.cn_flags |= WILLBEDIR;
1677 	nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1678 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1679 	    nd->nd_flag, nd->nd_cred, p);
1680 	if (fdirp)
1681 		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1682 	if (tdirp)
1683 		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1684 	if (fdirp)
1685 		vrele(fdirp);
1686 	if (tdirp)
1687 		vrele(tdirp);
1688 	if (nd->nd_flag & ND_NFSV3) {
1689 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1690 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1691 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1692 		NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1693 		*tl++ = newnfs_false;
1694 		txdr_hyper(fdirfor.na_filerev, tl);
1695 		tl += 2;
1696 		txdr_hyper(fdiraft.na_filerev, tl);
1697 		tl += 2;
1698 		*tl++ = newnfs_false;
1699 		txdr_hyper(tdirfor.na_filerev, tl);
1700 		tl += 2;
1701 		txdr_hyper(tdiraft.na_filerev, tl);
1702 	}
1703 
1704 out:
1705 	NFSEXITCODE2(error, nd);
1706 	return (error);
1707 }
1708 
1709 /*
1710  * nfs link service
1711  */
1712 APPLESTATIC int
1713 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1714     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1715 {
1716 	struct nameidata named;
1717 	u_int32_t *tl;
1718 	int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1719 	vnode_t dirp = NULL, dp = NULL;
1720 	struct nfsvattr dirfor, diraft, at;
1721 	struct nfsexstuff tnes;
1722 	struct nfsrvfh dfh;
1723 	char *bufp;
1724 	u_long *hashp;
1725 	struct thread *p = curthread;
1726 
1727 	if (nd->nd_repstat) {
1728 		nfsrv_postopattr(nd, getret, &at);
1729 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1730 		goto out;
1731 	}
1732 	NFSVOPUNLOCK(vp);
1733 	if (vnode_vtype(vp) == VDIR) {
1734 		if (nd->nd_flag & ND_NFSV4)
1735 			nd->nd_repstat = NFSERR_ISDIR;
1736 		else
1737 			nd->nd_repstat = NFSERR_INVAL;
1738 		if (tovp)
1739 			vrele(tovp);
1740 	}
1741 	if (!nd->nd_repstat) {
1742 		if (nd->nd_flag & ND_NFSV4) {
1743 			dp = tovp;
1744 			tnes = *toexp;
1745 		} else {
1746 			error = nfsrv_mtofh(nd, &dfh);
1747 			if (error) {
1748 				vrele(vp);
1749 				/* tovp is always NULL unless NFSv4 */
1750 				goto out;
1751 			}
1752 			nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0);
1753 			if (dp)
1754 				NFSVOPUNLOCK(dp);
1755 		}
1756 	}
1757 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1758 	    LOCKPARENT | SAVENAME | NOCACHE);
1759 	if (!nd->nd_repstat) {
1760 		nfsvno_setpathbuf(&named, &bufp, &hashp);
1761 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1762 		if (error) {
1763 			vrele(vp);
1764 			if (dp)
1765 				vrele(dp);
1766 			nfsvno_relpathbuf(&named);
1767 			goto out;
1768 		}
1769 		if (!nd->nd_repstat) {
1770 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1771 			    p, &dirp);
1772 		} else {
1773 			if (dp)
1774 				vrele(dp);
1775 			nfsvno_relpathbuf(&named);
1776 		}
1777 	}
1778 	if (dirp) {
1779 		if (nd->nd_flag & ND_NFSV2) {
1780 			vrele(dirp);
1781 			dirp = NULL;
1782 		} else {
1783 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1784 			    NULL);
1785 		}
1786 	}
1787 	if (!nd->nd_repstat)
1788 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1789 	if (nd->nd_flag & ND_NFSV3)
1790 		getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1791 	if (dirp) {
1792 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1793 		vrele(dirp);
1794 	}
1795 	vrele(vp);
1796 	if (nd->nd_flag & ND_NFSV3) {
1797 		nfsrv_postopattr(nd, getret, &at);
1798 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1799 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1800 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1801 		*tl++ = newnfs_false;
1802 		txdr_hyper(dirfor.na_filerev, tl);
1803 		tl += 2;
1804 		txdr_hyper(diraft.na_filerev, tl);
1805 	}
1806 
1807 out:
1808 	NFSEXITCODE2(error, nd);
1809 	return (error);
1810 }
1811 
1812 /*
1813  * nfs symbolic link service
1814  */
1815 APPLESTATIC int
1816 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1817     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1818 {
1819 	struct nfsvattr nva, dirfor, diraft;
1820 	struct nameidata named;
1821 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1822 	vnode_t dirp = NULL;
1823 	char *bufp, *pathcp = NULL;
1824 	u_long *hashp;
1825 	struct thread *p = curthread;
1826 
1827 	if (nd->nd_repstat) {
1828 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1829 		goto out;
1830 	}
1831 	if (vpp)
1832 		*vpp = NULL;
1833 	NFSVNO_ATTRINIT(&nva);
1834 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1835 	    LOCKPARENT | SAVESTART | NOCACHE);
1836 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1837 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1838 	if (!error && !nd->nd_repstat)
1839 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1840 	if (error) {
1841 		vrele(dp);
1842 		nfsvno_relpathbuf(&named);
1843 		goto out;
1844 	}
1845 	if (!nd->nd_repstat) {
1846 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1847 	} else {
1848 		vrele(dp);
1849 		nfsvno_relpathbuf(&named);
1850 	}
1851 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1852 		vrele(dirp);
1853 		dirp = NULL;
1854 	}
1855 
1856 	/*
1857 	 * And call nfsrvd_symlinksub() to do the common code. It will
1858 	 * return EBADRPC upon a parsing error, 0 otherwise.
1859 	 */
1860 	if (!nd->nd_repstat) {
1861 		if (dirp != NULL)
1862 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1863 			    NULL);
1864 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1865 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1866 		    pathcp, pathlen);
1867 	} else if (dirp != NULL) {
1868 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1869 		vrele(dirp);
1870 	}
1871 	if (pathcp)
1872 		free(pathcp, M_TEMP);
1873 
1874 	if (nd->nd_flag & ND_NFSV3) {
1875 		if (!nd->nd_repstat) {
1876 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1877 			nfsrv_postopattr(nd, 0, &nva);
1878 		}
1879 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1880 	}
1881 
1882 out:
1883 	NFSEXITCODE2(error, nd);
1884 	return (error);
1885 }
1886 
1887 /*
1888  * Common code for creating a symbolic link.
1889  */
1890 static void
1891 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1892     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1893     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1894     int *diraft_retp, nfsattrbit_t *attrbitp,
1895     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1896     int pathlen)
1897 {
1898 	u_int32_t *tl;
1899 
1900 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1901 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1902 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1903 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1904 		if (nd->nd_flag & ND_NFSV3) {
1905 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1906 			if (!nd->nd_repstat)
1907 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1908 				    nvap, nd, p, 1, NULL);
1909 		}
1910 		if (vpp != NULL && nd->nd_repstat == 0) {
1911 			NFSVOPUNLOCK(ndp->ni_vp);
1912 			*vpp = ndp->ni_vp;
1913 		} else
1914 			vput(ndp->ni_vp);
1915 	}
1916 	if (dirp) {
1917 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1918 		vrele(dirp);
1919 	}
1920 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1921 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1922 		*tl++ = newnfs_false;
1923 		txdr_hyper(dirforp->na_filerev, tl);
1924 		tl += 2;
1925 		txdr_hyper(diraftp->na_filerev, tl);
1926 		(void) nfsrv_putattrbit(nd, attrbitp);
1927 	}
1928 
1929 	NFSEXITCODE2(0, nd);
1930 }
1931 
1932 /*
1933  * nfs mkdir service
1934  */
1935 APPLESTATIC int
1936 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1937     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1938 {
1939 	struct nfsvattr nva, dirfor, diraft;
1940 	struct nameidata named;
1941 	u_int32_t *tl;
1942 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
1943 	vnode_t dirp = NULL;
1944 	char *bufp;
1945 	u_long *hashp;
1946 	struct thread *p = curthread;
1947 
1948 	if (nd->nd_repstat) {
1949 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1950 		goto out;
1951 	}
1952 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1953 	    LOCKPARENT | SAVENAME | NOCACHE);
1954 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1955 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1956 	if (error)
1957 		goto nfsmout;
1958 	if (!nd->nd_repstat) {
1959 		NFSVNO_ATTRINIT(&nva);
1960 		if (nd->nd_flag & ND_NFSV3) {
1961 			error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1962 			if (error)
1963 				goto nfsmout;
1964 		} else {
1965 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1966 			nva.na_mode = nfstov_mode(*tl++);
1967 		}
1968 	}
1969 	if (!nd->nd_repstat) {
1970 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1971 	} else {
1972 		vrele(dp);
1973 		nfsvno_relpathbuf(&named);
1974 	}
1975 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1976 		vrele(dirp);
1977 		dirp = NULL;
1978 	}
1979 	if (nd->nd_repstat) {
1980 		if (dirp != NULL) {
1981 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1982 			    NULL);
1983 			vrele(dirp);
1984 		}
1985 		if (nd->nd_flag & ND_NFSV3)
1986 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1987 			    &diraft);
1988 		goto out;
1989 	}
1990 	if (dirp != NULL)
1991 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1992 
1993 	/*
1994 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1995 	 */
1996 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1997 	    &diraft_ret, NULL, NULL, p, exp);
1998 
1999 	if (nd->nd_flag & ND_NFSV3) {
2000 		if (!nd->nd_repstat) {
2001 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
2002 			nfsrv_postopattr(nd, 0, &nva);
2003 		}
2004 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2005 	} else if (!nd->nd_repstat) {
2006 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2007 		nfsrv_fillattr(nd, &nva);
2008 	}
2009 
2010 out:
2011 	NFSEXITCODE2(0, nd);
2012 	return (0);
2013 nfsmout:
2014 	vrele(dp);
2015 	nfsvno_relpathbuf(&named);
2016 	NFSEXITCODE2(error, nd);
2017 	return (error);
2018 }
2019 
2020 /*
2021  * Code common to mkdir for V2,3 and 4.
2022  */
2023 static void
2024 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2025     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2026     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2027     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2028     NFSPROC_T *p, struct nfsexstuff *exp)
2029 {
2030 	vnode_t vp;
2031 	u_int32_t *tl;
2032 
2033 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
2034 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2035 	    nd->nd_cred, p, exp);
2036 	if (!nd->nd_repstat) {
2037 		vp = ndp->ni_vp;
2038 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2039 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2040 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2041 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2042 			    NULL);
2043 		if (vpp && !nd->nd_repstat) {
2044 			NFSVOPUNLOCK(vp);
2045 			*vpp = vp;
2046 		} else {
2047 			vput(vp);
2048 		}
2049 	}
2050 	if (dirp) {
2051 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2052 		vrele(dirp);
2053 	}
2054 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2055 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2056 		*tl++ = newnfs_false;
2057 		txdr_hyper(dirforp->na_filerev, tl);
2058 		tl += 2;
2059 		txdr_hyper(diraftp->na_filerev, tl);
2060 		(void) nfsrv_putattrbit(nd, attrbitp);
2061 	}
2062 
2063 	NFSEXITCODE2(0, nd);
2064 }
2065 
2066 /*
2067  * nfs commit service
2068  */
2069 APPLESTATIC int
2070 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2071     vnode_t vp, __unused struct nfsexstuff *exp)
2072 {
2073 	struct nfsvattr bfor, aft;
2074 	u_int32_t *tl;
2075 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
2076 	u_int64_t off;
2077 	struct thread *p = curthread;
2078 
2079        if (nd->nd_repstat) {
2080 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2081 		goto out;
2082 	}
2083 
2084 	/* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2085 	if (vp->v_type != VREG) {
2086 		if (nd->nd_flag & ND_NFSV3)
2087 			error = NFSERR_NOTSUPP;
2088 		else
2089 			error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2090 		goto nfsmout;
2091 	}
2092 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2093 
2094 	/*
2095 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
2096 	 * count parameters, so these arguments are useless (someday maybe).
2097 	 */
2098 	off = fxdr_hyper(tl);
2099 	tl += 2;
2100 	cnt = fxdr_unsigned(int, *tl);
2101 	if (nd->nd_flag & ND_NFSV3)
2102 		for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2103 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2104 	if (nd->nd_flag & ND_NFSV3) {
2105 		aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2106 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2107 	}
2108 	vput(vp);
2109 	if (!nd->nd_repstat) {
2110 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2111 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
2112 		*tl = txdr_unsigned(nfsboottime.tv_usec);
2113 	}
2114 
2115 out:
2116 	NFSEXITCODE2(0, nd);
2117 	return (0);
2118 nfsmout:
2119 	vput(vp);
2120 	NFSEXITCODE2(error, nd);
2121 	return (error);
2122 }
2123 
2124 /*
2125  * nfs statfs service
2126  */
2127 APPLESTATIC int
2128 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2129     vnode_t vp, __unused struct nfsexstuff *exp)
2130 {
2131 	struct statfs *sf;
2132 	u_int32_t *tl;
2133 	int getret = 1;
2134 	struct nfsvattr at;
2135 	u_quad_t tval;
2136 	struct thread *p = curthread;
2137 
2138 	sf = NULL;
2139 	if (nd->nd_repstat) {
2140 		nfsrv_postopattr(nd, getret, &at);
2141 		goto out;
2142 	}
2143 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2144 	nd->nd_repstat = nfsvno_statfs(vp, sf);
2145 	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2146 	vput(vp);
2147 	if (nd->nd_flag & ND_NFSV3)
2148 		nfsrv_postopattr(nd, getret, &at);
2149 	if (nd->nd_repstat)
2150 		goto out;
2151 	if (nd->nd_flag & ND_NFSV2) {
2152 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2153 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
2154 		*tl++ = txdr_unsigned(sf->f_bsize);
2155 		*tl++ = txdr_unsigned(sf->f_blocks);
2156 		*tl++ = txdr_unsigned(sf->f_bfree);
2157 		*tl = txdr_unsigned(sf->f_bavail);
2158 	} else {
2159 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2160 		tval = (u_quad_t)sf->f_blocks;
2161 		tval *= (u_quad_t)sf->f_bsize;
2162 		txdr_hyper(tval, tl); tl += 2;
2163 		tval = (u_quad_t)sf->f_bfree;
2164 		tval *= (u_quad_t)sf->f_bsize;
2165 		txdr_hyper(tval, tl); tl += 2;
2166 		tval = (u_quad_t)sf->f_bavail;
2167 		tval *= (u_quad_t)sf->f_bsize;
2168 		txdr_hyper(tval, tl); tl += 2;
2169 		tval = (u_quad_t)sf->f_files;
2170 		txdr_hyper(tval, tl); tl += 2;
2171 		tval = (u_quad_t)sf->f_ffree;
2172 		txdr_hyper(tval, tl); tl += 2;
2173 		tval = (u_quad_t)sf->f_ffree;
2174 		txdr_hyper(tval, tl); tl += 2;
2175 		*tl = 0;
2176 	}
2177 
2178 out:
2179 	free(sf, M_STATFS);
2180 	NFSEXITCODE2(0, nd);
2181 	return (0);
2182 }
2183 
2184 /*
2185  * nfs fsinfo service
2186  */
2187 APPLESTATIC int
2188 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2189     vnode_t vp, __unused struct nfsexstuff *exp)
2190 {
2191 	u_int32_t *tl;
2192 	struct nfsfsinfo fs;
2193 	int getret = 1;
2194 	struct nfsvattr at;
2195 	struct thread *p = curthread;
2196 
2197 	if (nd->nd_repstat) {
2198 		nfsrv_postopattr(nd, getret, &at);
2199 		goto out;
2200 	}
2201 	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2202 	nfsvno_getfs(&fs, isdgram);
2203 	vput(vp);
2204 	nfsrv_postopattr(nd, getret, &at);
2205 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2206 	*tl++ = txdr_unsigned(fs.fs_rtmax);
2207 	*tl++ = txdr_unsigned(fs.fs_rtpref);
2208 	*tl++ = txdr_unsigned(fs.fs_rtmult);
2209 	*tl++ = txdr_unsigned(fs.fs_wtmax);
2210 	*tl++ = txdr_unsigned(fs.fs_wtpref);
2211 	*tl++ = txdr_unsigned(fs.fs_wtmult);
2212 	*tl++ = txdr_unsigned(fs.fs_dtpref);
2213 	txdr_hyper(fs.fs_maxfilesize, tl);
2214 	tl += 2;
2215 	txdr_nfsv3time(&fs.fs_timedelta, tl);
2216 	tl += 2;
2217 	*tl = txdr_unsigned(fs.fs_properties);
2218 
2219 out:
2220 	NFSEXITCODE2(0, nd);
2221 	return (0);
2222 }
2223 
2224 /*
2225  * nfs pathconf service
2226  */
2227 APPLESTATIC int
2228 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2229     vnode_t vp, __unused struct nfsexstuff *exp)
2230 {
2231 	struct nfsv3_pathconf *pc;
2232 	int getret = 1;
2233 	long linkmax, namemax, chownres, notrunc;
2234 	struct nfsvattr at;
2235 	struct thread *p = curthread;
2236 
2237 	if (nd->nd_repstat) {
2238 		nfsrv_postopattr(nd, getret, &at);
2239 		goto out;
2240 	}
2241 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2242 	    nd->nd_cred, p);
2243 	if (!nd->nd_repstat)
2244 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2245 		    nd->nd_cred, p);
2246 	if (!nd->nd_repstat)
2247 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2248 		    &chownres, nd->nd_cred, p);
2249 	if (!nd->nd_repstat)
2250 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2251 		    nd->nd_cred, p);
2252 	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2253 	vput(vp);
2254 	nfsrv_postopattr(nd, getret, &at);
2255 	if (!nd->nd_repstat) {
2256 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2257 		pc->pc_linkmax = txdr_unsigned(linkmax);
2258 		pc->pc_namemax = txdr_unsigned(namemax);
2259 		pc->pc_notrunc = txdr_unsigned(notrunc);
2260 		pc->pc_chownrestricted = txdr_unsigned(chownres);
2261 
2262 		/*
2263 		 * These should probably be supported by VOP_PATHCONF(), but
2264 		 * until msdosfs is exportable (why would you want to?), the
2265 		 * Unix defaults should be ok.
2266 		 */
2267 		pc->pc_caseinsensitive = newnfs_false;
2268 		pc->pc_casepreserving = newnfs_true;
2269 	}
2270 
2271 out:
2272 	NFSEXITCODE2(0, nd);
2273 	return (0);
2274 }
2275 
2276 /*
2277  * nfsv4 lock service
2278  */
2279 APPLESTATIC int
2280 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2281     vnode_t vp, struct nfsexstuff *exp)
2282 {
2283 	u_int32_t *tl;
2284 	int i;
2285 	struct nfsstate *stp = NULL;
2286 	struct nfslock *lop;
2287 	struct nfslockconflict cf;
2288 	int error = 0;
2289 	u_short flags = NFSLCK_LOCK, lflags;
2290 	u_int64_t offset, len;
2291 	nfsv4stateid_t stateid;
2292 	nfsquad_t clientid;
2293 	struct thread *p = curthread;
2294 
2295 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2296 	i = fxdr_unsigned(int, *tl++);
2297 	switch (i) {
2298 	case NFSV4LOCKT_READW:
2299 		flags |= NFSLCK_BLOCKING;
2300 	case NFSV4LOCKT_READ:
2301 		lflags = NFSLCK_READ;
2302 		break;
2303 	case NFSV4LOCKT_WRITEW:
2304 		flags |= NFSLCK_BLOCKING;
2305 	case NFSV4LOCKT_WRITE:
2306 		lflags = NFSLCK_WRITE;
2307 		break;
2308 	default:
2309 		nd->nd_repstat = NFSERR_BADXDR;
2310 		goto nfsmout;
2311 	}
2312 	if (*tl++ == newnfs_true)
2313 		flags |= NFSLCK_RECLAIM;
2314 	offset = fxdr_hyper(tl);
2315 	tl += 2;
2316 	len = fxdr_hyper(tl);
2317 	tl += 2;
2318 	if (*tl == newnfs_true)
2319 		flags |= NFSLCK_OPENTOLOCK;
2320 	if (flags & NFSLCK_OPENTOLOCK) {
2321 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2322 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2323 		if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2324 			nd->nd_repstat = NFSERR_BADXDR;
2325 			goto nfsmout;
2326 		}
2327 		stp = malloc(sizeof (struct nfsstate) + i,
2328 			M_NFSDSTATE, M_WAITOK);
2329 		stp->ls_ownerlen = i;
2330 		stp->ls_op = nd->nd_rp;
2331 		stp->ls_seq = fxdr_unsigned(int, *tl++);
2332 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2333 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2334 			NFSX_STATEIDOTHER);
2335 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2336 
2337 		/*
2338 		 * For the special stateid of other all 0s and seqid == 1, set
2339 		 * the stateid to the current stateid, if it is set.
2340 		 */
2341 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
2342 		    stp->ls_stateid.seqid == 1 &&
2343 		    stp->ls_stateid.other[0] == 0 &&
2344 		    stp->ls_stateid.other[1] == 0 &&
2345 		    stp->ls_stateid.other[2] == 0) {
2346 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2347 				stp->ls_stateid = nd->nd_curstateid;
2348 				stp->ls_stateid.seqid = 0;
2349 			} else {
2350 				nd->nd_repstat = NFSERR_BADSTATEID;
2351 				goto nfsmout;
2352 			}
2353 		}
2354 
2355 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2356 		clientid.lval[0] = *tl++;
2357 		clientid.lval[1] = *tl++;
2358 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2359 			if ((nd->nd_flag & ND_NFSV41) != 0)
2360 				clientid.qval = nd->nd_clientid.qval;
2361 			else if (nd->nd_clientid.qval != clientid.qval)
2362 				printf("EEK3 multiple clids\n");
2363 		} else {
2364 			if ((nd->nd_flag & ND_NFSV41) != 0)
2365 				printf("EEK! no clientid from session\n");
2366 			nd->nd_flag |= ND_IMPLIEDCLID;
2367 			nd->nd_clientid.qval = clientid.qval;
2368 		}
2369 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2370 		if (error)
2371 			goto nfsmout;
2372 	} else {
2373 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2374 		stp = malloc(sizeof (struct nfsstate),
2375 			M_NFSDSTATE, M_WAITOK);
2376 		stp->ls_ownerlen = 0;
2377 		stp->ls_op = nd->nd_rp;
2378 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2379 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2380 			NFSX_STATEIDOTHER);
2381 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2382 
2383 		/*
2384 		 * For the special stateid of other all 0s and seqid == 1, set
2385 		 * the stateid to the current stateid, if it is set.
2386 		 */
2387 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
2388 		    stp->ls_stateid.seqid == 1 &&
2389 		    stp->ls_stateid.other[0] == 0 &&
2390 		    stp->ls_stateid.other[1] == 0 &&
2391 		    stp->ls_stateid.other[2] == 0) {
2392 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2393 				stp->ls_stateid = nd->nd_curstateid;
2394 				stp->ls_stateid.seqid = 0;
2395 			} else {
2396 				nd->nd_repstat = NFSERR_BADSTATEID;
2397 				goto nfsmout;
2398 			}
2399 		}
2400 
2401 		stp->ls_seq = fxdr_unsigned(int, *tl);
2402 		clientid.lval[0] = stp->ls_stateid.other[0];
2403 		clientid.lval[1] = stp->ls_stateid.other[1];
2404 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2405 			if ((nd->nd_flag & ND_NFSV41) != 0)
2406 				clientid.qval = nd->nd_clientid.qval;
2407 			else if (nd->nd_clientid.qval != clientid.qval)
2408 				printf("EEK4 multiple clids\n");
2409 		} else {
2410 			if ((nd->nd_flag & ND_NFSV41) != 0)
2411 				printf("EEK! no clientid from session\n");
2412 			nd->nd_flag |= ND_IMPLIEDCLID;
2413 			nd->nd_clientid.qval = clientid.qval;
2414 		}
2415 	}
2416 	lop = malloc(sizeof (struct nfslock),
2417 		M_NFSDLOCK, M_WAITOK);
2418 	lop->lo_first = offset;
2419 	if (len == NFS64BITSSET) {
2420 		lop->lo_end = NFS64BITSSET;
2421 	} else {
2422 		lop->lo_end = offset + len;
2423 		if (lop->lo_end <= lop->lo_first)
2424 			nd->nd_repstat = NFSERR_INVAL;
2425 	}
2426 	lop->lo_flags = lflags;
2427 	stp->ls_flags = flags;
2428 	stp->ls_uid = nd->nd_cred->cr_uid;
2429 
2430 	/*
2431 	 * Do basic access checking.
2432 	 */
2433 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2434 	    if (vnode_vtype(vp) == VDIR)
2435 		nd->nd_repstat = NFSERR_ISDIR;
2436 	    else
2437 		nd->nd_repstat = NFSERR_INVAL;
2438 	}
2439 	if (!nd->nd_repstat) {
2440 	    if (lflags & NFSLCK_WRITE) {
2441 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2442 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2443 		    NFSACCCHK_VPISLOCKED, NULL);
2444 	    } else {
2445 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2446 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2447 		    NFSACCCHK_VPISLOCKED, NULL);
2448 		if (nd->nd_repstat)
2449 		    nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2450 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2451 			NFSACCCHK_VPISLOCKED, NULL);
2452 	    }
2453 	}
2454 
2455 	/*
2456 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2457 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
2458 	 * of nd_repstat, if it gets that far.
2459 	 */
2460 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2461 		&stateid, exp, nd, p);
2462 	if (lop)
2463 		free(lop, M_NFSDLOCK);
2464 	if (stp)
2465 		free(stp, M_NFSDSTATE);
2466 	if (!nd->nd_repstat) {
2467 		/* For NFSv4.1, set the Current StateID. */
2468 		if ((nd->nd_flag & ND_NFSV41) != 0) {
2469 			nd->nd_curstateid = stateid;
2470 			nd->nd_flag |= ND_CURSTATEID;
2471 		}
2472 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2473 		*tl++ = txdr_unsigned(stateid.seqid);
2474 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2475 	} else if (nd->nd_repstat == NFSERR_DENIED) {
2476 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2477 		txdr_hyper(cf.cl_first, tl);
2478 		tl += 2;
2479 		if (cf.cl_end == NFS64BITSSET)
2480 			len = NFS64BITSSET;
2481 		else
2482 			len = cf.cl_end - cf.cl_first;
2483 		txdr_hyper(len, tl);
2484 		tl += 2;
2485 		if (cf.cl_flags == NFSLCK_WRITE)
2486 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2487 		else
2488 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2489 		*tl++ = stateid.other[0];
2490 		*tl = stateid.other[1];
2491 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2492 	}
2493 	vput(vp);
2494 	NFSEXITCODE2(0, nd);
2495 	return (0);
2496 nfsmout:
2497 	vput(vp);
2498 	if (stp)
2499 		free(stp, M_NFSDSTATE);
2500 	NFSEXITCODE2(error, nd);
2501 	return (error);
2502 }
2503 
2504 /*
2505  * nfsv4 lock test service
2506  */
2507 APPLESTATIC int
2508 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2509     vnode_t vp, struct nfsexstuff *exp)
2510 {
2511 	u_int32_t *tl;
2512 	int i;
2513 	struct nfsstate *stp = NULL;
2514 	struct nfslock lo, *lop = &lo;
2515 	struct nfslockconflict cf;
2516 	int error = 0;
2517 	nfsv4stateid_t stateid;
2518 	nfsquad_t clientid;
2519 	u_int64_t len;
2520 	struct thread *p = curthread;
2521 
2522 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2523 	i = fxdr_unsigned(int, *(tl + 7));
2524 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2525 		nd->nd_repstat = NFSERR_BADXDR;
2526 		goto nfsmout;
2527 	}
2528 	stp = malloc(sizeof (struct nfsstate) + i,
2529 	    M_NFSDSTATE, M_WAITOK);
2530 	stp->ls_ownerlen = i;
2531 	stp->ls_op = NULL;
2532 	stp->ls_flags = NFSLCK_TEST;
2533 	stp->ls_uid = nd->nd_cred->cr_uid;
2534 	i = fxdr_unsigned(int, *tl++);
2535 	switch (i) {
2536 	case NFSV4LOCKT_READW:
2537 		stp->ls_flags |= NFSLCK_BLOCKING;
2538 	case NFSV4LOCKT_READ:
2539 		lo.lo_flags = NFSLCK_READ;
2540 		break;
2541 	case NFSV4LOCKT_WRITEW:
2542 		stp->ls_flags |= NFSLCK_BLOCKING;
2543 	case NFSV4LOCKT_WRITE:
2544 		lo.lo_flags = NFSLCK_WRITE;
2545 		break;
2546 	default:
2547 		nd->nd_repstat = NFSERR_BADXDR;
2548 		goto nfsmout;
2549 	}
2550 	lo.lo_first = fxdr_hyper(tl);
2551 	tl += 2;
2552 	len = fxdr_hyper(tl);
2553 	if (len == NFS64BITSSET) {
2554 		lo.lo_end = NFS64BITSSET;
2555 	} else {
2556 		lo.lo_end = lo.lo_first + len;
2557 		if (lo.lo_end <= lo.lo_first)
2558 			nd->nd_repstat = NFSERR_INVAL;
2559 	}
2560 	tl += 2;
2561 	clientid.lval[0] = *tl++;
2562 	clientid.lval[1] = *tl;
2563 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2564 		if ((nd->nd_flag & ND_NFSV41) != 0)
2565 			clientid.qval = nd->nd_clientid.qval;
2566 		else if (nd->nd_clientid.qval != clientid.qval)
2567 			printf("EEK5 multiple clids\n");
2568 	} else {
2569 		if ((nd->nd_flag & ND_NFSV41) != 0)
2570 			printf("EEK! no clientid from session\n");
2571 		nd->nd_flag |= ND_IMPLIEDCLID;
2572 		nd->nd_clientid.qval = clientid.qval;
2573 	}
2574 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2575 	if (error)
2576 		goto nfsmout;
2577 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2578 	    if (vnode_vtype(vp) == VDIR)
2579 		nd->nd_repstat = NFSERR_ISDIR;
2580 	    else
2581 		nd->nd_repstat = NFSERR_INVAL;
2582 	}
2583 	if (!nd->nd_repstat)
2584 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2585 	    &stateid, exp, nd, p);
2586 	if (nd->nd_repstat) {
2587 	    if (nd->nd_repstat == NFSERR_DENIED) {
2588 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2589 		txdr_hyper(cf.cl_first, tl);
2590 		tl += 2;
2591 		if (cf.cl_end == NFS64BITSSET)
2592 			len = NFS64BITSSET;
2593 		else
2594 			len = cf.cl_end - cf.cl_first;
2595 		txdr_hyper(len, tl);
2596 		tl += 2;
2597 		if (cf.cl_flags == NFSLCK_WRITE)
2598 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2599 		else
2600 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2601 		*tl++ = stp->ls_stateid.other[0];
2602 		*tl = stp->ls_stateid.other[1];
2603 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2604 	    }
2605 	}
2606 	vput(vp);
2607 	if (stp)
2608 		free(stp, M_NFSDSTATE);
2609 	NFSEXITCODE2(0, nd);
2610 	return (0);
2611 nfsmout:
2612 	vput(vp);
2613 	if (stp)
2614 		free(stp, M_NFSDSTATE);
2615 	NFSEXITCODE2(error, nd);
2616 	return (error);
2617 }
2618 
2619 /*
2620  * nfsv4 unlock service
2621  */
2622 APPLESTATIC int
2623 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2624     vnode_t vp, struct nfsexstuff *exp)
2625 {
2626 	u_int32_t *tl;
2627 	int i;
2628 	struct nfsstate *stp;
2629 	struct nfslock *lop;
2630 	int error = 0;
2631 	nfsv4stateid_t stateid;
2632 	nfsquad_t clientid;
2633 	u_int64_t len;
2634 	struct thread *p = curthread;
2635 
2636 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2637 	stp = malloc(sizeof (struct nfsstate),
2638 	    M_NFSDSTATE, M_WAITOK);
2639 	lop = malloc(sizeof (struct nfslock),
2640 	    M_NFSDLOCK, M_WAITOK);
2641 	stp->ls_flags = NFSLCK_UNLOCK;
2642 	lop->lo_flags = NFSLCK_UNLOCK;
2643 	stp->ls_op = nd->nd_rp;
2644 	i = fxdr_unsigned(int, *tl++);
2645 	switch (i) {
2646 	case NFSV4LOCKT_READW:
2647 		stp->ls_flags |= NFSLCK_BLOCKING;
2648 	case NFSV4LOCKT_READ:
2649 		break;
2650 	case NFSV4LOCKT_WRITEW:
2651 		stp->ls_flags |= NFSLCK_BLOCKING;
2652 	case NFSV4LOCKT_WRITE:
2653 		break;
2654 	default:
2655 		nd->nd_repstat = NFSERR_BADXDR;
2656 		free(stp, M_NFSDSTATE);
2657 		free(lop, M_NFSDLOCK);
2658 		goto nfsmout;
2659 	}
2660 	stp->ls_ownerlen = 0;
2661 	stp->ls_uid = nd->nd_cred->cr_uid;
2662 	stp->ls_seq = fxdr_unsigned(int, *tl++);
2663 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2664 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2665 	    NFSX_STATEIDOTHER);
2666 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2667 
2668 	/*
2669 	 * For the special stateid of other all 0s and seqid == 1, set the
2670 	 * stateid to the current stateid, if it is set.
2671 	 */
2672 	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2673 	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2674 	    stp->ls_stateid.other[2] == 0) {
2675 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2676 			stp->ls_stateid = nd->nd_curstateid;
2677 			stp->ls_stateid.seqid = 0;
2678 		} else {
2679 			nd->nd_repstat = NFSERR_BADSTATEID;
2680 			goto nfsmout;
2681 		}
2682 	}
2683 
2684 	lop->lo_first = fxdr_hyper(tl);
2685 	tl += 2;
2686 	len = fxdr_hyper(tl);
2687 	if (len == NFS64BITSSET) {
2688 		lop->lo_end = NFS64BITSSET;
2689 	} else {
2690 		lop->lo_end = lop->lo_first + len;
2691 		if (lop->lo_end <= lop->lo_first)
2692 			nd->nd_repstat = NFSERR_INVAL;
2693 	}
2694 	clientid.lval[0] = stp->ls_stateid.other[0];
2695 	clientid.lval[1] = stp->ls_stateid.other[1];
2696 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2697 		if ((nd->nd_flag & ND_NFSV41) != 0)
2698 			clientid.qval = nd->nd_clientid.qval;
2699 		else if (nd->nd_clientid.qval != clientid.qval)
2700 			printf("EEK6 multiple clids\n");
2701 	} else {
2702 		if ((nd->nd_flag & ND_NFSV41) != 0)
2703 			printf("EEK! no clientid from session\n");
2704 		nd->nd_flag |= ND_IMPLIEDCLID;
2705 		nd->nd_clientid.qval = clientid.qval;
2706 	}
2707 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2708 	    if (vnode_vtype(vp) == VDIR)
2709 		nd->nd_repstat = NFSERR_ISDIR;
2710 	    else
2711 		nd->nd_repstat = NFSERR_INVAL;
2712 	}
2713 	/*
2714 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2715 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
2716 	 * value of nd_repstat, if it gets that far.
2717 	 */
2718 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2719 	    &stateid, exp, nd, p);
2720 	if (stp)
2721 		free(stp, M_NFSDSTATE);
2722 	if (lop)
2723 		free(lop, M_NFSDLOCK);
2724 	if (!nd->nd_repstat) {
2725 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2726 		*tl++ = txdr_unsigned(stateid.seqid);
2727 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2728 	}
2729 nfsmout:
2730 	vput(vp);
2731 	NFSEXITCODE2(error, nd);
2732 	return (error);
2733 }
2734 
2735 /*
2736  * nfsv4 open service
2737  */
2738 APPLESTATIC int
2739 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2740     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2741 {
2742 	u_int32_t *tl;
2743 	int i, retext;
2744 	struct nfsstate *stp = NULL;
2745 	int error = 0, create, claim, exclusive_flag = 0;
2746 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2747 	int how = NFSCREATE_UNCHECKED;
2748 	int32_t cverf[2], tverf[2] = { 0, 0 };
2749 	vnode_t vp = NULL, dirp = NULL;
2750 	struct nfsvattr nva, dirfor, diraft;
2751 	struct nameidata named;
2752 	nfsv4stateid_t stateid, delegstateid;
2753 	nfsattrbit_t attrbits;
2754 	nfsquad_t clientid;
2755 	char *bufp = NULL;
2756 	u_long *hashp;
2757 	NFSACL_T *aclp = NULL;
2758 	struct thread *p = curthread;
2759 
2760 #ifdef NFS4_ACL_EXTATTR_NAME
2761 	aclp = acl_alloc(M_WAITOK);
2762 	aclp->acl_cnt = 0;
2763 #endif
2764 	NFSZERO_ATTRBIT(&attrbits);
2765 	named.ni_startdir = NULL;
2766 	named.ni_cnd.cn_nameiop = 0;
2767 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2768 	i = fxdr_unsigned(int, *(tl + 5));
2769 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2770 		nd->nd_repstat = NFSERR_BADXDR;
2771 		goto nfsmout;
2772 	}
2773 	stp = malloc(sizeof (struct nfsstate) + i,
2774 	    M_NFSDSTATE, M_WAITOK);
2775 	stp->ls_ownerlen = i;
2776 	stp->ls_op = nd->nd_rp;
2777 	stp->ls_flags = NFSLCK_OPEN;
2778 	stp->ls_uid = nd->nd_cred->cr_uid;
2779 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2780 	i = fxdr_unsigned(int, *tl++);
2781 	retext = 0;
2782 	if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2783 	    NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2784 		retext = 1;
2785 		/* For now, ignore these. */
2786 		i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2787 		switch (i & NFSV4OPEN_WANTDELEGMASK) {
2788 		case NFSV4OPEN_WANTANYDELEG:
2789 			stp->ls_flags |= (NFSLCK_WANTRDELEG |
2790 			    NFSLCK_WANTWDELEG);
2791 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2792 			break;
2793 		case NFSV4OPEN_WANTREADDELEG:
2794 			stp->ls_flags |= NFSLCK_WANTRDELEG;
2795 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2796 			break;
2797 		case NFSV4OPEN_WANTWRITEDELEG:
2798 			stp->ls_flags |= NFSLCK_WANTWDELEG;
2799 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2800 			break;
2801 		case NFSV4OPEN_WANTNODELEG:
2802 			stp->ls_flags |= NFSLCK_WANTNODELEG;
2803 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2804 			break;
2805 		case NFSV4OPEN_WANTCANCEL:
2806 			printf("NFSv4: ignore Open WantCancel\n");
2807 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2808 			break;
2809 		default:
2810 			/* nd_repstat will be set to NFSERR_INVAL below. */
2811 			break;
2812 		}
2813 	}
2814 	switch (i) {
2815 	case NFSV4OPEN_ACCESSREAD:
2816 		stp->ls_flags |= NFSLCK_READACCESS;
2817 		break;
2818 	case NFSV4OPEN_ACCESSWRITE:
2819 		stp->ls_flags |= NFSLCK_WRITEACCESS;
2820 		break;
2821 	case NFSV4OPEN_ACCESSBOTH:
2822 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2823 		break;
2824 	default:
2825 		nd->nd_repstat = NFSERR_INVAL;
2826 	}
2827 	i = fxdr_unsigned(int, *tl++);
2828 	switch (i) {
2829 	case NFSV4OPEN_DENYNONE:
2830 		break;
2831 	case NFSV4OPEN_DENYREAD:
2832 		stp->ls_flags |= NFSLCK_READDENY;
2833 		break;
2834 	case NFSV4OPEN_DENYWRITE:
2835 		stp->ls_flags |= NFSLCK_WRITEDENY;
2836 		break;
2837 	case NFSV4OPEN_DENYBOTH:
2838 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2839 		break;
2840 	default:
2841 		nd->nd_repstat = NFSERR_INVAL;
2842 	}
2843 	clientid.lval[0] = *tl++;
2844 	clientid.lval[1] = *tl;
2845 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2846 		if ((nd->nd_flag & ND_NFSV41) != 0)
2847 			clientid.qval = nd->nd_clientid.qval;
2848 		else if (nd->nd_clientid.qval != clientid.qval)
2849 			printf("EEK7 multiple clids\n");
2850 	} else {
2851 		if ((nd->nd_flag & ND_NFSV41) != 0)
2852 			printf("EEK! no clientid from session\n");
2853 		nd->nd_flag |= ND_IMPLIEDCLID;
2854 		nd->nd_clientid.qval = clientid.qval;
2855 	}
2856 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2857 	if (error)
2858 		goto nfsmout;
2859 	NFSVNO_ATTRINIT(&nva);
2860 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2861 	create = fxdr_unsigned(int, *tl);
2862 	if (!nd->nd_repstat)
2863 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2864 	if (create == NFSV4OPEN_CREATE) {
2865 		nva.na_type = VREG;
2866 		nva.na_mode = 0;
2867 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2868 		how = fxdr_unsigned(int, *tl);
2869 		switch (how) {
2870 		case NFSCREATE_UNCHECKED:
2871 		case NFSCREATE_GUARDED:
2872 			error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2873 			if (error)
2874 				goto nfsmout;
2875 			/*
2876 			 * If the na_gid being set is the same as that of
2877 			 * the directory it is going in, clear it, since
2878 			 * that is what will be set by default. This allows
2879 			 * a user that isn't in that group to do the create.
2880 			 */
2881 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2882 			    nva.na_gid == dirfor.na_gid)
2883 				NFSVNO_UNSET(&nva, gid);
2884 			if (!nd->nd_repstat)
2885 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2886 			break;
2887 		case NFSCREATE_EXCLUSIVE:
2888 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2889 			cverf[0] = *tl++;
2890 			cverf[1] = *tl;
2891 			break;
2892 		case NFSCREATE_EXCLUSIVE41:
2893 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2894 			cverf[0] = *tl++;
2895 			cverf[1] = *tl;
2896 			error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2897 			if (error != 0)
2898 				goto nfsmout;
2899 			if (NFSISSET_ATTRBIT(&attrbits,
2900 			    NFSATTRBIT_TIMEACCESSSET))
2901 				nd->nd_repstat = NFSERR_INVAL;
2902 			/*
2903 			 * If the na_gid being set is the same as that of
2904 			 * the directory it is going in, clear it, since
2905 			 * that is what will be set by default. This allows
2906 			 * a user that isn't in that group to do the create.
2907 			 */
2908 			if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2909 			    nva.na_gid == dirfor.na_gid)
2910 				NFSVNO_UNSET(&nva, gid);
2911 			if (nd->nd_repstat == 0)
2912 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2913 			break;
2914 		default:
2915 			nd->nd_repstat = NFSERR_BADXDR;
2916 			goto nfsmout;
2917 		}
2918 	} else if (create != NFSV4OPEN_NOCREATE) {
2919 		nd->nd_repstat = NFSERR_BADXDR;
2920 		goto nfsmout;
2921 	}
2922 
2923 	/*
2924 	 * Now, handle the claim, which usually includes looking up a
2925 	 * name in the directory referenced by dp. The exception is
2926 	 * NFSV4OPEN_CLAIMPREVIOUS.
2927 	 */
2928 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2929 	claim = fxdr_unsigned(int, *tl);
2930 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2931 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2932 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2933 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2934 		stp->ls_flags |= NFSLCK_DELEGCUR;
2935 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2936 		stp->ls_flags |= NFSLCK_DELEGPREV;
2937 	}
2938 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2939 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2940 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2941 		    claim != NFSV4OPEN_CLAIMNULL)
2942 			nd->nd_repstat = NFSERR_INVAL;
2943 		if (nd->nd_repstat) {
2944 			nd->nd_repstat = nfsrv_opencheck(clientid,
2945 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
2946 			goto nfsmout;
2947 		}
2948 		if (create == NFSV4OPEN_CREATE)
2949 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2950 			LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2951 		else
2952 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2953 			LOCKLEAF | SAVESTART);
2954 		nfsvno_setpathbuf(&named, &bufp, &hashp);
2955 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2956 		if (error) {
2957 			vrele(dp);
2958 #ifdef NFS4_ACL_EXTATTR_NAME
2959 			acl_free(aclp);
2960 #endif
2961 			free(stp, M_NFSDSTATE);
2962 			nfsvno_relpathbuf(&named);
2963 			NFSEXITCODE2(error, nd);
2964 			return (error);
2965 		}
2966 		if (!nd->nd_repstat) {
2967 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2968 			    p, &dirp);
2969 		} else {
2970 			vrele(dp);
2971 			nfsvno_relpathbuf(&named);
2972 		}
2973 		if (create == NFSV4OPEN_CREATE) {
2974 		    switch (how) {
2975 		    case NFSCREATE_UNCHECKED:
2976 			if (named.ni_vp) {
2977 				/*
2978 				 * Clear the setable attribute bits, except
2979 				 * for Size, if it is being truncated.
2980 				 */
2981 				NFSZERO_ATTRBIT(&attrbits);
2982 				if (NFSVNO_ISSETSIZE(&nva))
2983 					NFSSETBIT_ATTRBIT(&attrbits,
2984 					    NFSATTRBIT_SIZE);
2985 			}
2986 			break;
2987 		    case NFSCREATE_GUARDED:
2988 			if (named.ni_vp && !nd->nd_repstat)
2989 				nd->nd_repstat = EEXIST;
2990 			break;
2991 		    case NFSCREATE_EXCLUSIVE:
2992 			exclusive_flag = 1;
2993 			if (!named.ni_vp)
2994 				nva.na_mode = 0;
2995 			break;
2996 		    case NFSCREATE_EXCLUSIVE41:
2997 			exclusive_flag = 1;
2998 			break;
2999 		    }
3000 		}
3001 		nfsvno_open(nd, &named, clientid, &stateid, stp,
3002 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3003 		    nd->nd_cred, exp, &vp);
3004 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3005 	    NFSV4OPEN_CLAIMFH) {
3006 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3007 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3008 			i = fxdr_unsigned(int, *tl);
3009 			switch (i) {
3010 			case NFSV4OPEN_DELEGATEREAD:
3011 				stp->ls_flags |= NFSLCK_DELEGREAD;
3012 				break;
3013 			case NFSV4OPEN_DELEGATEWRITE:
3014 				stp->ls_flags |= NFSLCK_DELEGWRITE;
3015 			case NFSV4OPEN_DELEGATENONE:
3016 				break;
3017 			default:
3018 				nd->nd_repstat = NFSERR_BADXDR;
3019 				goto nfsmout;
3020 			}
3021 			stp->ls_flags |= NFSLCK_RECLAIM;
3022 		} else {
3023 			/* CLAIM_NULL_FH */
3024 			if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3025 				nd->nd_repstat = NFSERR_INVAL;
3026 		}
3027 		vp = dp;
3028 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3029 		if (!VN_IS_DOOMED(vp))
3030 			nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3031 			    stp, vp, nd, p, nd->nd_repstat);
3032 		else
3033 			nd->nd_repstat = NFSERR_PERM;
3034 	} else {
3035 		nd->nd_repstat = NFSERR_BADXDR;
3036 		goto nfsmout;
3037 	}
3038 
3039 	/*
3040 	 * Do basic access checking.
3041 	 */
3042 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
3043 		/*
3044 		 * The IETF working group decided that this is the correct
3045 		 * error return for all non-regular files.
3046 		 */
3047 		nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3048 	}
3049 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3050 	    nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3051 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3052 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3053 	    nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3054 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3055 	    if (nd->nd_repstat)
3056 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3057 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
3058 		    NFSACCCHK_VPISLOCKED, NULL);
3059 	}
3060 
3061 	if (!nd->nd_repstat) {
3062 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3063 		if (!nd->nd_repstat) {
3064 			tverf[0] = nva.na_atime.tv_sec;
3065 			tverf[1] = nva.na_atime.tv_nsec;
3066 		}
3067 	}
3068 	if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3069 	    cverf[1] != tverf[1]))
3070 		nd->nd_repstat = EEXIST;
3071 	/*
3072 	 * Do the open locking/delegation stuff.
3073 	 */
3074 	if (!nd->nd_repstat)
3075 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3076 		&delegstateid, &rflags, exp, p, nva.na_filerev);
3077 
3078 	/*
3079 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3080 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3081 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
3082 	 */
3083 	if (vp)
3084 		NFSVOPUNLOCK(vp);
3085 	if (stp)
3086 		free(stp, M_NFSDSTATE);
3087 	if (!nd->nd_repstat && dirp)
3088 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3089 	if (!nd->nd_repstat) {
3090 		/* For NFSv4.1, set the Current StateID. */
3091 		if ((nd->nd_flag & ND_NFSV41) != 0) {
3092 			nd->nd_curstateid = stateid;
3093 			nd->nd_flag |= ND_CURSTATEID;
3094 		}
3095 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3096 		*tl++ = txdr_unsigned(stateid.seqid);
3097 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3098 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3099 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3100 			*tl++ = newnfs_true;
3101 			*tl++ = 0;
3102 			*tl++ = 0;
3103 			*tl++ = 0;
3104 			*tl++ = 0;
3105 		} else {
3106 			*tl++ = newnfs_false;	/* Since dirp is not locked */
3107 			txdr_hyper(dirfor.na_filerev, tl);
3108 			tl += 2;
3109 			txdr_hyper(diraft.na_filerev, tl);
3110 			tl += 2;
3111 		}
3112 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3113 		(void) nfsrv_putattrbit(nd, &attrbits);
3114 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3115 		if (rflags & NFSV4OPEN_READDELEGATE)
3116 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3117 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3118 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3119 		else if (retext != 0) {
3120 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3121 			if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3122 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3123 				*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3124 			} else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3125 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3126 				*tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3127 			} else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3128 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3129 				*tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3130 				*tl = newnfs_false;
3131 			} else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3132 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3133 				*tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3134 				*tl = newnfs_false;
3135 			} else {
3136 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3137 				*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3138 			}
3139 		} else
3140 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3141 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3142 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3143 			*tl++ = txdr_unsigned(delegstateid.seqid);
3144 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3145 			    NFSX_STATEIDOTHER);
3146 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3147 			if (rflags & NFSV4OPEN_RECALL)
3148 				*tl = newnfs_true;
3149 			else
3150 				*tl = newnfs_false;
3151 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3152 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3153 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3154 				txdr_hyper(nva.na_size, tl);
3155 			}
3156 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3157 			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3158 			*tl++ = txdr_unsigned(0x0);
3159 			acemask = NFSV4ACE_ALLFILESMASK;
3160 			if (nva.na_mode & S_IRUSR)
3161 			    acemask |= NFSV4ACE_READMASK;
3162 			if (nva.na_mode & S_IWUSR)
3163 			    acemask |= NFSV4ACE_WRITEMASK;
3164 			if (nva.na_mode & S_IXUSR)
3165 			    acemask |= NFSV4ACE_EXECUTEMASK;
3166 			*tl = txdr_unsigned(acemask);
3167 			(void) nfsm_strtom(nd, "OWNER@", 6);
3168 		}
3169 		*vpp = vp;
3170 	} else if (vp) {
3171 		vrele(vp);
3172 	}
3173 	if (dirp)
3174 		vrele(dirp);
3175 #ifdef NFS4_ACL_EXTATTR_NAME
3176 	acl_free(aclp);
3177 #endif
3178 	NFSEXITCODE2(0, nd);
3179 	return (0);
3180 nfsmout:
3181 	vrele(dp);
3182 #ifdef NFS4_ACL_EXTATTR_NAME
3183 	acl_free(aclp);
3184 #endif
3185 	if (stp)
3186 		free(stp, M_NFSDSTATE);
3187 	NFSEXITCODE2(error, nd);
3188 	return (error);
3189 }
3190 
3191 /*
3192  * nfsv4 close service
3193  */
3194 APPLESTATIC int
3195 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3196     vnode_t vp, __unused struct nfsexstuff *exp)
3197 {
3198 	u_int32_t *tl;
3199 	struct nfsstate st, *stp = &st;
3200 	int error = 0, writeacc;
3201 	nfsv4stateid_t stateid;
3202 	nfsquad_t clientid;
3203 	struct nfsvattr na;
3204 	struct thread *p = curthread;
3205 
3206 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3207 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3208 	stp->ls_ownerlen = 0;
3209 	stp->ls_op = nd->nd_rp;
3210 	stp->ls_uid = nd->nd_cred->cr_uid;
3211 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3212 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3213 	    NFSX_STATEIDOTHER);
3214 
3215 	/*
3216 	 * For the special stateid of other all 0s and seqid == 1, set the
3217 	 * stateid to the current stateid, if it is set.
3218 	 */
3219 	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3220 	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3221 	    stp->ls_stateid.other[2] == 0) {
3222 		if ((nd->nd_flag & ND_CURSTATEID) != 0)
3223 			stp->ls_stateid = nd->nd_curstateid;
3224 		else {
3225 			nd->nd_repstat = NFSERR_BADSTATEID;
3226 			goto nfsmout;
3227 		}
3228 	}
3229 
3230 	stp->ls_flags = NFSLCK_CLOSE;
3231 	clientid.lval[0] = stp->ls_stateid.other[0];
3232 	clientid.lval[1] = stp->ls_stateid.other[1];
3233 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3234 		if ((nd->nd_flag & ND_NFSV41) != 0)
3235 			clientid.qval = nd->nd_clientid.qval;
3236 		else if (nd->nd_clientid.qval != clientid.qval)
3237 			printf("EEK8 multiple clids\n");
3238 	} else {
3239 		if ((nd->nd_flag & ND_NFSV41) != 0)
3240 			printf("EEK! no clientid from session\n");
3241 		nd->nd_flag |= ND_IMPLIEDCLID;
3242 		nd->nd_clientid.qval = clientid.qval;
3243 	}
3244 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3245 	    &writeacc);
3246 	/* For pNFS, update the attributes. */
3247 	if (writeacc != 0 || nfsrv_pnfsatime != 0)
3248 		nfsrv_updatemdsattr(vp, &na, p);
3249 	vput(vp);
3250 	if (!nd->nd_repstat) {
3251 		/*
3252 		 * If the stateid that has been closed is the current stateid,
3253 		 * unset it.
3254 		 */
3255 		if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3256 		    stateid.other[0] == nd->nd_curstateid.other[0] &&
3257 		    stateid.other[1] == nd->nd_curstateid.other[1] &&
3258 		    stateid.other[2] == nd->nd_curstateid.other[2])
3259 			nd->nd_flag &= ~ND_CURSTATEID;
3260 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3261 		*tl++ = txdr_unsigned(stateid.seqid);
3262 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3263 	}
3264 	NFSEXITCODE2(0, nd);
3265 	return (0);
3266 nfsmout:
3267 	vput(vp);
3268 	NFSEXITCODE2(error, nd);
3269 	return (error);
3270 }
3271 
3272 /*
3273  * nfsv4 delegpurge service
3274  */
3275 APPLESTATIC int
3276 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3277     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3278 {
3279 	u_int32_t *tl;
3280 	int error = 0;
3281 	nfsquad_t clientid;
3282 	struct thread *p = curthread;
3283 
3284 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3285 		nd->nd_repstat = NFSERR_WRONGSEC;
3286 		goto nfsmout;
3287 	}
3288 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3289 	clientid.lval[0] = *tl++;
3290 	clientid.lval[1] = *tl;
3291 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3292 		if ((nd->nd_flag & ND_NFSV41) != 0)
3293 			clientid.qval = nd->nd_clientid.qval;
3294 		else if (nd->nd_clientid.qval != clientid.qval)
3295 			printf("EEK9 multiple clids\n");
3296 	} else {
3297 		if ((nd->nd_flag & ND_NFSV41) != 0)
3298 			printf("EEK! no clientid from session\n");
3299 		nd->nd_flag |= ND_IMPLIEDCLID;
3300 		nd->nd_clientid.qval = clientid.qval;
3301 	}
3302 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3303 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3304 nfsmout:
3305 	NFSEXITCODE2(error, nd);
3306 	return (error);
3307 }
3308 
3309 /*
3310  * nfsv4 delegreturn service
3311  */
3312 APPLESTATIC int
3313 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3314     vnode_t vp, __unused struct nfsexstuff *exp)
3315 {
3316 	u_int32_t *tl;
3317 	int error = 0, writeacc;
3318 	nfsv4stateid_t stateid;
3319 	nfsquad_t clientid;
3320 	struct nfsvattr na;
3321 	struct thread *p = curthread;
3322 
3323 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3324 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3325 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3326 	clientid.lval[0] = stateid.other[0];
3327 	clientid.lval[1] = stateid.other[1];
3328 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3329 		if ((nd->nd_flag & ND_NFSV41) != 0)
3330 			clientid.qval = nd->nd_clientid.qval;
3331 		else if (nd->nd_clientid.qval != clientid.qval)
3332 			printf("EEK10 multiple clids\n");
3333 	} else {
3334 		if ((nd->nd_flag & ND_NFSV41) != 0)
3335 			printf("EEK! no clientid from session\n");
3336 		nd->nd_flag |= ND_IMPLIEDCLID;
3337 		nd->nd_clientid.qval = clientid.qval;
3338 	}
3339 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3340 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3341 	/* For pNFS, update the attributes. */
3342 	if (writeacc != 0 || nfsrv_pnfsatime != 0)
3343 		nfsrv_updatemdsattr(vp, &na, p);
3344 nfsmout:
3345 	vput(vp);
3346 	NFSEXITCODE2(error, nd);
3347 	return (error);
3348 }
3349 
3350 /*
3351  * nfsv4 get file handle service
3352  */
3353 APPLESTATIC int
3354 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3355     vnode_t vp, __unused struct nfsexstuff *exp)
3356 {
3357 	fhandle_t fh;
3358 	struct thread *p = curthread;
3359 
3360 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3361 	vput(vp);
3362 	if (!nd->nd_repstat)
3363 		(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3364 	NFSEXITCODE2(0, nd);
3365 	return (0);
3366 }
3367 
3368 /*
3369  * nfsv4 open confirm service
3370  */
3371 APPLESTATIC int
3372 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3373     vnode_t vp, __unused struct nfsexstuff *exp)
3374 {
3375 	u_int32_t *tl;
3376 	struct nfsstate st, *stp = &st;
3377 	int error = 0;
3378 	nfsv4stateid_t stateid;
3379 	nfsquad_t clientid;
3380 	struct thread *p = curthread;
3381 
3382 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3383 		nd->nd_repstat = NFSERR_NOTSUPP;
3384 		goto nfsmout;
3385 	}
3386 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3387 	stp->ls_ownerlen = 0;
3388 	stp->ls_op = nd->nd_rp;
3389 	stp->ls_uid = nd->nd_cred->cr_uid;
3390 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3391 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3392 	    NFSX_STATEIDOTHER);
3393 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3394 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3395 	stp->ls_flags = NFSLCK_CONFIRM;
3396 	clientid.lval[0] = stp->ls_stateid.other[0];
3397 	clientid.lval[1] = stp->ls_stateid.other[1];
3398 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3399 		if ((nd->nd_flag & ND_NFSV41) != 0)
3400 			clientid.qval = nd->nd_clientid.qval;
3401 		else if (nd->nd_clientid.qval != clientid.qval)
3402 			printf("EEK11 multiple clids\n");
3403 	} else {
3404 		if ((nd->nd_flag & ND_NFSV41) != 0)
3405 			printf("EEK! no clientid from session\n");
3406 		nd->nd_flag |= ND_IMPLIEDCLID;
3407 		nd->nd_clientid.qval = clientid.qval;
3408 	}
3409 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3410 	    NULL);
3411 	if (!nd->nd_repstat) {
3412 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3413 		*tl++ = txdr_unsigned(stateid.seqid);
3414 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3415 	}
3416 nfsmout:
3417 	vput(vp);
3418 	NFSEXITCODE2(error, nd);
3419 	return (error);
3420 }
3421 
3422 /*
3423  * nfsv4 open downgrade service
3424  */
3425 APPLESTATIC int
3426 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3427     vnode_t vp, __unused struct nfsexstuff *exp)
3428 {
3429 	u_int32_t *tl;
3430 	int i;
3431 	struct nfsstate st, *stp = &st;
3432 	int error = 0;
3433 	nfsv4stateid_t stateid;
3434 	nfsquad_t clientid;
3435 	struct thread *p = curthread;
3436 
3437 	/* opendowngrade can only work on a file object.*/
3438 	if (vp->v_type != VREG) {
3439 		error = NFSERR_INVAL;
3440 		goto nfsmout;
3441 	}
3442 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3443 	stp->ls_ownerlen = 0;
3444 	stp->ls_op = nd->nd_rp;
3445 	stp->ls_uid = nd->nd_cred->cr_uid;
3446 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3447 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3448 	    NFSX_STATEIDOTHER);
3449 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3450 
3451 	/*
3452 	 * For the special stateid of other all 0s and seqid == 1, set the
3453 	 * stateid to the current stateid, if it is set.
3454 	 */
3455 	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3456 	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3457 	    stp->ls_stateid.other[2] == 0) {
3458 		if ((nd->nd_flag & ND_CURSTATEID) != 0)
3459 			stp->ls_stateid = nd->nd_curstateid;
3460 		else {
3461 			nd->nd_repstat = NFSERR_BADSTATEID;
3462 			goto nfsmout;
3463 		}
3464 	}
3465 
3466 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3467 	i = fxdr_unsigned(int, *tl++);
3468 	if ((nd->nd_flag & ND_NFSV41) != 0)
3469 		i &= ~NFSV4OPEN_WANTDELEGMASK;
3470 	switch (i) {
3471 	case NFSV4OPEN_ACCESSREAD:
3472 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3473 		break;
3474 	case NFSV4OPEN_ACCESSWRITE:
3475 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3476 		break;
3477 	case NFSV4OPEN_ACCESSBOTH:
3478 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3479 		    NFSLCK_DOWNGRADE);
3480 		break;
3481 	default:
3482 		nd->nd_repstat = NFSERR_INVAL;
3483 	}
3484 	i = fxdr_unsigned(int, *tl);
3485 	switch (i) {
3486 	case NFSV4OPEN_DENYNONE:
3487 		break;
3488 	case NFSV4OPEN_DENYREAD:
3489 		stp->ls_flags |= NFSLCK_READDENY;
3490 		break;
3491 	case NFSV4OPEN_DENYWRITE:
3492 		stp->ls_flags |= NFSLCK_WRITEDENY;
3493 		break;
3494 	case NFSV4OPEN_DENYBOTH:
3495 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3496 		break;
3497 	default:
3498 		nd->nd_repstat = NFSERR_INVAL;
3499 	}
3500 
3501 	clientid.lval[0] = stp->ls_stateid.other[0];
3502 	clientid.lval[1] = stp->ls_stateid.other[1];
3503 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3504 		if ((nd->nd_flag & ND_NFSV41) != 0)
3505 			clientid.qval = nd->nd_clientid.qval;
3506 		else if (nd->nd_clientid.qval != clientid.qval)
3507 			printf("EEK12 multiple clids\n");
3508 	} else {
3509 		if ((nd->nd_flag & ND_NFSV41) != 0)
3510 			printf("EEK! no clientid from session\n");
3511 		nd->nd_flag |= ND_IMPLIEDCLID;
3512 		nd->nd_clientid.qval = clientid.qval;
3513 	}
3514 	if (!nd->nd_repstat)
3515 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3516 		    nd, p, NULL);
3517 	if (!nd->nd_repstat) {
3518 		/* For NFSv4.1, set the Current StateID. */
3519 		if ((nd->nd_flag & ND_NFSV41) != 0) {
3520 			nd->nd_curstateid = stateid;
3521 			nd->nd_flag |= ND_CURSTATEID;
3522 		}
3523 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3524 		*tl++ = txdr_unsigned(stateid.seqid);
3525 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3526 	}
3527 nfsmout:
3528 	vput(vp);
3529 	NFSEXITCODE2(error, nd);
3530 	return (error);
3531 }
3532 
3533 /*
3534  * nfsv4 renew lease service
3535  */
3536 APPLESTATIC int
3537 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3538     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3539 {
3540 	u_int32_t *tl;
3541 	int error = 0;
3542 	nfsquad_t clientid;
3543 	struct thread *p = curthread;
3544 
3545 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3546 		nd->nd_repstat = NFSERR_NOTSUPP;
3547 		goto nfsmout;
3548 	}
3549 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3550 		nd->nd_repstat = NFSERR_WRONGSEC;
3551 		goto nfsmout;
3552 	}
3553 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3554 	clientid.lval[0] = *tl++;
3555 	clientid.lval[1] = *tl;
3556 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3557 		if ((nd->nd_flag & ND_NFSV41) != 0)
3558 			clientid.qval = nd->nd_clientid.qval;
3559 		else if (nd->nd_clientid.qval != clientid.qval)
3560 			printf("EEK13 multiple clids\n");
3561 	} else {
3562 		if ((nd->nd_flag & ND_NFSV41) != 0)
3563 			printf("EEK! no clientid from session\n");
3564 		nd->nd_flag |= ND_IMPLIEDCLID;
3565 		nd->nd_clientid.qval = clientid.qval;
3566 	}
3567 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3568 	    NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3569 nfsmout:
3570 	NFSEXITCODE2(error, nd);
3571 	return (error);
3572 }
3573 
3574 /*
3575  * nfsv4 security info service
3576  */
3577 APPLESTATIC int
3578 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3579     vnode_t dp, struct nfsexstuff *exp)
3580 {
3581 	u_int32_t *tl;
3582 	int len;
3583 	struct nameidata named;
3584 	vnode_t dirp = NULL, vp;
3585 	struct nfsrvfh fh;
3586 	struct nfsexstuff retnes;
3587 	u_int32_t *sizp;
3588 	int error = 0, savflag, i;
3589 	char *bufp;
3590 	u_long *hashp;
3591 	struct thread *p = curthread;
3592 
3593 	/*
3594 	 * All this just to get the export flags for the name.
3595 	 */
3596 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3597 	    LOCKLEAF | SAVESTART);
3598 	nfsvno_setpathbuf(&named, &bufp, &hashp);
3599 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3600 	if (error) {
3601 		vput(dp);
3602 		nfsvno_relpathbuf(&named);
3603 		goto out;
3604 	}
3605 	if (!nd->nd_repstat) {
3606 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3607 	} else {
3608 		vput(dp);
3609 		nfsvno_relpathbuf(&named);
3610 	}
3611 	if (dirp)
3612 		vrele(dirp);
3613 	if (nd->nd_repstat)
3614 		goto out;
3615 	vrele(named.ni_startdir);
3616 	nfsvno_relpathbuf(&named);
3617 	fh.nfsrvfh_len = NFSX_MYFH;
3618 	vp = named.ni_vp;
3619 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3620 	vput(vp);
3621 	savflag = nd->nd_flag;
3622 	if (!nd->nd_repstat) {
3623 		nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0);
3624 		if (vp)
3625 			vput(vp);
3626 	}
3627 	nd->nd_flag = savflag;
3628 	if (nd->nd_repstat)
3629 		goto out;
3630 
3631 	/*
3632 	 * Finally have the export flags for name, so we can create
3633 	 * the security info.
3634 	 */
3635 	len = 0;
3636 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3637 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
3638 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
3639 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3640 			*tl = txdr_unsigned(RPCAUTH_UNIX);
3641 			len++;
3642 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3643 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3644 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3645 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3646 			    nfsgss_mechlist[KERBV_MECH].len);
3647 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3648 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3649 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3650 			len++;
3651 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3652 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3653 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3654 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3655 			    nfsgss_mechlist[KERBV_MECH].len);
3656 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3657 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3658 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3659 			len++;
3660 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3661 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3662 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3663 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3664 			    nfsgss_mechlist[KERBV_MECH].len);
3665 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3666 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3667 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3668 			len++;
3669 		}
3670 	}
3671 	*sizp = txdr_unsigned(len);
3672 
3673 out:
3674 	NFSEXITCODE2(error, nd);
3675 	return (error);
3676 }
3677 
3678 /*
3679  * nfsv4 set client id service
3680  */
3681 APPLESTATIC int
3682 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3683     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3684 {
3685 	u_int32_t *tl;
3686 	int i;
3687 	int error = 0, idlen;
3688 	struct nfsclient *clp = NULL;
3689 #ifdef INET
3690 	struct sockaddr_in *rin;
3691 #endif
3692 #ifdef INET6
3693 	struct sockaddr_in6 *rin6;
3694 #endif
3695 #if defined(INET) || defined(INET6)
3696 	u_char *ucp, *ucp2;
3697 #endif
3698 	u_char *verf, *addrbuf;
3699 	nfsquad_t clientid, confirm;
3700 	struct thread *p = curthread;
3701 
3702 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3703 		nd->nd_repstat = NFSERR_NOTSUPP;
3704 		goto nfsmout;
3705 	}
3706 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3707 		nd->nd_repstat = NFSERR_WRONGSEC;
3708 		goto out;
3709 	}
3710 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3711 	verf = (u_char *)tl;
3712 	tl += (NFSX_VERF / NFSX_UNSIGNED);
3713 	i = fxdr_unsigned(int, *tl);
3714 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3715 		nd->nd_repstat = NFSERR_BADXDR;
3716 		goto nfsmout;
3717 	}
3718 	idlen = i;
3719 	if (nd->nd_flag & ND_GSS)
3720 		i += nd->nd_princlen;
3721 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3722 	    M_ZERO);
3723 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3724 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3725 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3726 	/* Allocated large enough for an AF_INET or AF_INET6 socket. */
3727 	clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3728 	    M_WAITOK | M_ZERO);
3729 	clp->lc_req.nr_cred = NULL;
3730 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3731 	clp->lc_idlen = idlen;
3732 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3733 	if (error)
3734 		goto nfsmout;
3735 	if (nd->nd_flag & ND_GSS) {
3736 		clp->lc_flags = LCL_GSS;
3737 		if (nd->nd_flag & ND_GSSINTEGRITY)
3738 			clp->lc_flags |= LCL_GSSINTEGRITY;
3739 		else if (nd->nd_flag & ND_GSSPRIVACY)
3740 			clp->lc_flags |= LCL_GSSPRIVACY;
3741 	} else {
3742 		clp->lc_flags = 0;
3743 	}
3744 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3745 		clp->lc_flags |= LCL_NAME;
3746 		clp->lc_namelen = nd->nd_princlen;
3747 		clp->lc_name = &clp->lc_id[idlen];
3748 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3749 	} else {
3750 		clp->lc_uid = nd->nd_cred->cr_uid;
3751 		clp->lc_gid = nd->nd_cred->cr_gid;
3752 	}
3753 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3754 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3755 	error = nfsrv_getclientipaddr(nd, clp);
3756 	if (error)
3757 		goto nfsmout;
3758 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3759 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3760 
3761 	/*
3762 	 * nfsrv_setclient() does the actual work of adding it to the
3763 	 * client list. If there is no error, the structure has been
3764 	 * linked into the client list and clp should no longer be used
3765 	 * here. When an error is returned, it has not been linked in,
3766 	 * so it should be free'd.
3767 	 */
3768 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3769 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3770 		/*
3771 		 * 8 is the maximum length of the port# string.
3772 		 */
3773 		addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
3774 		switch (clp->lc_req.nr_nam->sa_family) {
3775 #ifdef INET
3776 		case AF_INET:
3777 			if (clp->lc_flags & LCL_TCPCALLBACK)
3778 				(void) nfsm_strtom(nd, "tcp", 3);
3779 			else
3780 				(void) nfsm_strtom(nd, "udp", 3);
3781 			rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
3782 			ucp = (u_char *)&rin->sin_addr.s_addr;
3783 			ucp2 = (u_char *)&rin->sin_port;
3784 			sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3785 			    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3786 			    ucp2[0] & 0xff, ucp2[1] & 0xff);
3787 			break;
3788 #endif
3789 #ifdef INET6
3790 		case AF_INET6:
3791 			if (clp->lc_flags & LCL_TCPCALLBACK)
3792 				(void) nfsm_strtom(nd, "tcp6", 4);
3793 			else
3794 				(void) nfsm_strtom(nd, "udp6", 4);
3795 			rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
3796 			ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
3797 			    INET6_ADDRSTRLEN);
3798 			if (ucp != NULL)
3799 				i = strlen(ucp);
3800 			else
3801 				i = 0;
3802 			ucp2 = (u_char *)&rin6->sin6_port;
3803 			sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
3804 			    ucp2[1] & 0xff);
3805 			break;
3806 #endif
3807 		}
3808 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3809 		free(addrbuf, M_TEMP);
3810 	}
3811 	if (clp) {
3812 		free(clp->lc_req.nr_nam, M_SONAME);
3813 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3814 		free(clp->lc_stateid, M_NFSDCLIENT);
3815 		free(clp, M_NFSDCLIENT);
3816 	}
3817 	if (!nd->nd_repstat) {
3818 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3819 		*tl++ = clientid.lval[0];
3820 		*tl++ = clientid.lval[1];
3821 		*tl++ = confirm.lval[0];
3822 		*tl = confirm.lval[1];
3823 	}
3824 
3825 out:
3826 	NFSEXITCODE2(0, nd);
3827 	return (0);
3828 nfsmout:
3829 	if (clp) {
3830 		free(clp->lc_req.nr_nam, M_SONAME);
3831 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3832 		free(clp->lc_stateid, M_NFSDCLIENT);
3833 		free(clp, M_NFSDCLIENT);
3834 	}
3835 	NFSEXITCODE2(error, nd);
3836 	return (error);
3837 }
3838 
3839 /*
3840  * nfsv4 set client id confirm service
3841  */
3842 APPLESTATIC int
3843 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3844     __unused int isdgram, __unused vnode_t vp,
3845     __unused struct nfsexstuff *exp)
3846 {
3847 	u_int32_t *tl;
3848 	int error = 0;
3849 	nfsquad_t clientid, confirm;
3850 	struct thread *p = curthread;
3851 
3852 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3853 		nd->nd_repstat = NFSERR_NOTSUPP;
3854 		goto nfsmout;
3855 	}
3856 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3857 		nd->nd_repstat = NFSERR_WRONGSEC;
3858 		goto nfsmout;
3859 	}
3860 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3861 	clientid.lval[0] = *tl++;
3862 	clientid.lval[1] = *tl++;
3863 	confirm.lval[0] = *tl++;
3864 	confirm.lval[1] = *tl;
3865 
3866 	/*
3867 	 * nfsrv_getclient() searches the client list for a match and
3868 	 * returns the appropriate NFSERR status.
3869 	 */
3870 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3871 	    NULL, NULL, confirm, 0, nd, p);
3872 nfsmout:
3873 	NFSEXITCODE2(error, nd);
3874 	return (error);
3875 }
3876 
3877 /*
3878  * nfsv4 verify service
3879  */
3880 APPLESTATIC int
3881 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3882     vnode_t vp, __unused struct nfsexstuff *exp)
3883 {
3884 	int error = 0, ret, fhsize = NFSX_MYFH;
3885 	struct nfsvattr nva;
3886 	struct statfs *sf;
3887 	struct nfsfsinfo fs;
3888 	fhandle_t fh;
3889 	struct thread *p = curthread;
3890 
3891 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3892 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3893 	if (!nd->nd_repstat)
3894 		nd->nd_repstat = nfsvno_statfs(vp, sf);
3895 	if (!nd->nd_repstat)
3896 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3897 	if (!nd->nd_repstat) {
3898 		nfsvno_getfs(&fs, isdgram);
3899 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3900 		    sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3901 		if (!error) {
3902 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3903 				if (ret == 0)
3904 					nd->nd_repstat = NFSERR_SAME;
3905 				else if (ret != NFSERR_NOTSAME)
3906 					nd->nd_repstat = ret;
3907 			} else if (ret)
3908 				nd->nd_repstat = ret;
3909 		}
3910 	}
3911 	vput(vp);
3912 	free(sf, M_STATFS);
3913 	NFSEXITCODE2(error, nd);
3914 	return (error);
3915 }
3916 
3917 /*
3918  * nfs openattr rpc
3919  */
3920 APPLESTATIC int
3921 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3922     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3923     __unused struct nfsexstuff *exp)
3924 {
3925 	u_int32_t *tl;
3926 	int error = 0, createdir __unused;
3927 
3928 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3929 	createdir = fxdr_unsigned(int, *tl);
3930 	nd->nd_repstat = NFSERR_NOTSUPP;
3931 nfsmout:
3932 	vrele(dp);
3933 	NFSEXITCODE2(error, nd);
3934 	return (error);
3935 }
3936 
3937 /*
3938  * nfsv4 release lock owner service
3939  */
3940 APPLESTATIC int
3941 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3942     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3943 {
3944 	u_int32_t *tl;
3945 	struct nfsstate *stp = NULL;
3946 	int error = 0, len;
3947 	nfsquad_t clientid;
3948 	struct thread *p = curthread;
3949 
3950 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3951 		nd->nd_repstat = NFSERR_NOTSUPP;
3952 		goto nfsmout;
3953 	}
3954 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3955 		nd->nd_repstat = NFSERR_WRONGSEC;
3956 		goto nfsmout;
3957 	}
3958 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3959 	len = fxdr_unsigned(int, *(tl + 2));
3960 	if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3961 		nd->nd_repstat = NFSERR_BADXDR;
3962 		goto nfsmout;
3963 	}
3964 	stp = malloc(sizeof (struct nfsstate) + len,
3965 	    M_NFSDSTATE, M_WAITOK);
3966 	stp->ls_ownerlen = len;
3967 	stp->ls_op = NULL;
3968 	stp->ls_flags = NFSLCK_RELEASE;
3969 	stp->ls_uid = nd->nd_cred->cr_uid;
3970 	clientid.lval[0] = *tl++;
3971 	clientid.lval[1] = *tl;
3972 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3973 		if ((nd->nd_flag & ND_NFSV41) != 0)
3974 			clientid.qval = nd->nd_clientid.qval;
3975 		else if (nd->nd_clientid.qval != clientid.qval)
3976 			printf("EEK14 multiple clids\n");
3977 	} else {
3978 		if ((nd->nd_flag & ND_NFSV41) != 0)
3979 			printf("EEK! no clientid from session\n");
3980 		nd->nd_flag |= ND_IMPLIEDCLID;
3981 		nd->nd_clientid.qval = clientid.qval;
3982 	}
3983 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
3984 	if (error)
3985 		goto nfsmout;
3986 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3987 	free(stp, M_NFSDSTATE);
3988 
3989 	NFSEXITCODE2(0, nd);
3990 	return (0);
3991 nfsmout:
3992 	if (stp)
3993 		free(stp, M_NFSDSTATE);
3994 	NFSEXITCODE2(error, nd);
3995 	return (error);
3996 }
3997 
3998 /*
3999  * nfsv4 exchange_id service
4000  */
4001 APPLESTATIC int
4002 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4003     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4004 {
4005 	uint32_t *tl;
4006 	int error = 0, i, idlen;
4007 	struct nfsclient *clp = NULL;
4008 	nfsquad_t clientid, confirm;
4009 	uint8_t *verf;
4010 	uint32_t sp4type, v41flags;
4011 	uint64_t owner_minor;
4012 	struct timespec verstime;
4013 #ifdef INET
4014 	struct sockaddr_in *sin, *rin;
4015 #endif
4016 #ifdef INET6
4017 	struct sockaddr_in6 *sin6, *rin6;
4018 #endif
4019 	struct thread *p = curthread;
4020 
4021 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4022 		nd->nd_repstat = NFSERR_WRONGSEC;
4023 		goto nfsmout;
4024 	}
4025 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4026 	verf = (uint8_t *)tl;
4027 	tl += (NFSX_VERF / NFSX_UNSIGNED);
4028 	i = fxdr_unsigned(int, *tl);
4029 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4030 		nd->nd_repstat = NFSERR_BADXDR;
4031 		goto nfsmout;
4032 	}
4033 	idlen = i;
4034 	if (nd->nd_flag & ND_GSS)
4035 		i += nd->nd_princlen;
4036 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4037 	    M_ZERO);
4038 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4039 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4040 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4041 	/* Allocated large enough for an AF_INET or AF_INET6 socket. */
4042 	clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4043 	    M_WAITOK | M_ZERO);
4044 	switch (nd->nd_nam->sa_family) {
4045 #ifdef INET
4046 	case AF_INET:
4047 		rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4048 		sin = (struct sockaddr_in *)nd->nd_nam;
4049 		rin->sin_family = AF_INET;
4050 		rin->sin_len = sizeof(struct sockaddr_in);
4051 		rin->sin_port = 0;
4052 		rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4053 		break;
4054 #endif
4055 #ifdef INET6
4056 	case AF_INET6:
4057 		rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4058 		sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4059 		rin6->sin6_family = AF_INET6;
4060 		rin6->sin6_len = sizeof(struct sockaddr_in6);
4061 		rin6->sin6_port = 0;
4062 		rin6->sin6_addr = sin6->sin6_addr;
4063 		break;
4064 #endif
4065 	}
4066 	clp->lc_req.nr_cred = NULL;
4067 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4068 	clp->lc_idlen = idlen;
4069 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4070 	if (error != 0)
4071 		goto nfsmout;
4072 	if ((nd->nd_flag & ND_GSS) != 0) {
4073 		clp->lc_flags = LCL_GSS | LCL_NFSV41;
4074 		if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4075 			clp->lc_flags |= LCL_GSSINTEGRITY;
4076 		else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4077 			clp->lc_flags |= LCL_GSSPRIVACY;
4078 	} else
4079 		clp->lc_flags = LCL_NFSV41;
4080 	if ((nd->nd_flag & ND_NFSV42) != 0)
4081 		clp->lc_flags |= LCL_NFSV42;
4082 	if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4083 		clp->lc_flags |= LCL_NAME;
4084 		clp->lc_namelen = nd->nd_princlen;
4085 		clp->lc_name = &clp->lc_id[idlen];
4086 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4087 	} else {
4088 		clp->lc_uid = nd->nd_cred->cr_uid;
4089 		clp->lc_gid = nd->nd_cred->cr_gid;
4090 	}
4091 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4092 	v41flags = fxdr_unsigned(uint32_t, *tl++);
4093 	if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4094 	    NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4095 	    NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4096 		nd->nd_repstat = NFSERR_INVAL;
4097 		goto nfsmout;
4098 	}
4099 	if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4100 		confirm.lval[1] = 1;
4101 	else
4102 		confirm.lval[1] = 0;
4103 	if (nfsrv_devidcnt == 0)
4104 		v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4105  	else
4106  		v41flags = NFSV4EXCH_USEPNFSMDS;
4107 	sp4type = fxdr_unsigned(uint32_t, *tl);
4108 	if (sp4type != NFSV4EXCH_SP4NONE) {
4109 		nd->nd_repstat = NFSERR_NOTSUPP;
4110 		goto nfsmout;
4111 	}
4112 
4113 	/*
4114 	 * nfsrv_setclient() does the actual work of adding it to the
4115 	 * client list. If there is no error, the structure has been
4116 	 * linked into the client list and clp should no longer be used
4117 	 * here. When an error is returned, it has not been linked in,
4118 	 * so it should be free'd.
4119 	 */
4120 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4121 	if (clp != NULL) {
4122 		free(clp->lc_req.nr_nam, M_SONAME);
4123 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4124 		free(clp->lc_stateid, M_NFSDCLIENT);
4125 		free(clp, M_NFSDCLIENT);
4126 	}
4127 	if (nd->nd_repstat == 0) {
4128 		if (confirm.lval[1] != 0)
4129 			v41flags |= NFSV4EXCH_CONFIRMEDR;
4130 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
4131 		*tl++ = clientid.lval[0];			/* ClientID */
4132 		*tl++ = clientid.lval[1];
4133 		*tl++ = txdr_unsigned(confirm.lval[0]);		/* SequenceID */
4134 		*tl++ = txdr_unsigned(v41flags);		/* Exch flags */
4135 		*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);	/* No SSV */
4136 		owner_minor = 0;				/* Owner */
4137 		txdr_hyper(owner_minor, tl);			/* Minor */
4138 		(void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4139 		    strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
4140 		(void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4141 		    strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */
4142 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4143 		*tl = txdr_unsigned(1);
4144 		(void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4145 		(void)nfsm_strtom(nd, version, strlen(version));
4146 		NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4147 		verstime.tv_sec = 1293840000;		/* Jan 1, 2011 */
4148 		verstime.tv_nsec = 0;
4149 		txdr_nfsv4time(&verstime, tl);
4150 	}
4151 	NFSEXITCODE2(0, nd);
4152 	return (0);
4153 nfsmout:
4154 	if (clp != NULL) {
4155 		free(clp->lc_req.nr_nam, M_SONAME);
4156 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4157 		free(clp->lc_stateid, M_NFSDCLIENT);
4158 		free(clp, M_NFSDCLIENT);
4159 	}
4160 	NFSEXITCODE2(error, nd);
4161 	return (error);
4162 }
4163 
4164 /*
4165  * nfsv4 create session service
4166  */
4167 APPLESTATIC int
4168 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4169     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4170 {
4171 	uint32_t *tl;
4172 	int error = 0;
4173 	nfsquad_t clientid, confirm;
4174 	struct nfsdsession *sep = NULL;
4175 	uint32_t rdmacnt;
4176 	struct thread *p = curthread;
4177 
4178 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4179 		nd->nd_repstat = NFSERR_WRONGSEC;
4180 		goto nfsmout;
4181 	}
4182 	sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4183 	    M_NFSDSESSION, M_WAITOK | M_ZERO);
4184 	sep->sess_refcnt = 1;
4185 	mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4186 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4187 	clientid.lval[0] = *tl++;
4188 	clientid.lval[1] = *tl++;
4189 	confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4190 	sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4191 	/* Persistent sessions and RDMA are not supported. */
4192 	sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4193 
4194 	/* Fore channel attributes. */
4195 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4196 	tl++;					/* Header pad always 0. */
4197 	sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4198 	if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4199 		sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4200 		printf("Consider increasing kern.ipc.maxsockbuf\n");
4201 	}
4202 	sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4203 	if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4204 		sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4205 		printf("Consider increasing kern.ipc.maxsockbuf\n");
4206 	}
4207 	sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4208 	sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4209 	sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4210 	if (sep->sess_maxslots > NFSV4_SLOTS)
4211 		sep->sess_maxslots = NFSV4_SLOTS;
4212 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
4213 	if (rdmacnt > 1) {
4214 		nd->nd_repstat = NFSERR_BADXDR;
4215 		goto nfsmout;
4216 	} else if (rdmacnt == 1)
4217 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4218 
4219 	/* Back channel attributes. */
4220 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4221 	tl++;					/* Header pad always 0. */
4222 	sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4223 	sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4224 	sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4225 	sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4226 	sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4227 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
4228 	if (rdmacnt > 1) {
4229 		nd->nd_repstat = NFSERR_BADXDR;
4230 		goto nfsmout;
4231 	} else if (rdmacnt == 1)
4232 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4233 
4234 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4235 	sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4236 
4237 	/*
4238 	 * nfsrv_getclient() searches the client list for a match and
4239 	 * returns the appropriate NFSERR status.
4240 	 */
4241 	nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4242 	    NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4243 	if (nd->nd_repstat == 0) {
4244 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4245 		NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4246 		NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4247 		*tl++ = txdr_unsigned(confirm.lval[0]);	/* sequenceid */
4248 		*tl++ = txdr_unsigned(sep->sess_crflags);
4249 
4250 		/* Fore channel attributes. */
4251 		*tl++ = 0;
4252 		*tl++ = txdr_unsigned(sep->sess_maxreq);
4253 		*tl++ = txdr_unsigned(sep->sess_maxresp);
4254 		*tl++ = txdr_unsigned(sep->sess_maxrespcached);
4255 		*tl++ = txdr_unsigned(sep->sess_maxops);
4256 		*tl++ = txdr_unsigned(sep->sess_maxslots);
4257 		*tl++ = txdr_unsigned(1);
4258 		*tl++ = txdr_unsigned(0);			/* No RDMA. */
4259 
4260 		/* Back channel attributes. */
4261 		*tl++ = 0;
4262 		*tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4263 		*tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4264 		*tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4265 		*tl++ = txdr_unsigned(sep->sess_cbmaxops);
4266 		*tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4267 		*tl++ = txdr_unsigned(1);
4268 		*tl = txdr_unsigned(0);			/* No RDMA. */
4269 	}
4270 nfsmout:
4271 	if (nd->nd_repstat != 0 && sep != NULL)
4272 		free(sep, M_NFSDSESSION);
4273 	NFSEXITCODE2(error, nd);
4274 	return (error);
4275 }
4276 
4277 /*
4278  * nfsv4 sequence service
4279  */
4280 APPLESTATIC int
4281 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4282     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4283 {
4284 	uint32_t *tl;
4285 	uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4286 	int cache_this, error = 0;
4287 	struct thread *p = curthread;
4288 
4289 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4290 		nd->nd_repstat = NFSERR_WRONGSEC;
4291 		goto nfsmout;
4292 	}
4293 	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4294 	NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4295 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4296 	sequenceid = fxdr_unsigned(uint32_t, *tl++);
4297 	nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4298 	highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4299 	if (*tl == newnfs_true)
4300 		cache_this = 1;
4301 	else
4302 		cache_this = 0;
4303 	nd->nd_flag |= ND_HASSEQUENCE;
4304 	nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4305 	    &target_highest_slotid, cache_this, &sflags, p);
4306 	if (nd->nd_repstat == 0) {
4307 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4308 		NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4309 		NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4310 		*tl++ = txdr_unsigned(sequenceid);
4311 		*tl++ = txdr_unsigned(nd->nd_slotid);
4312 		*tl++ = txdr_unsigned(highest_slotid);
4313 		*tl++ = txdr_unsigned(target_highest_slotid);
4314 		*tl = txdr_unsigned(sflags);
4315 	}
4316 nfsmout:
4317 	NFSEXITCODE2(error, nd);
4318 	return (error);
4319 }
4320 
4321 /*
4322  * nfsv4 reclaim complete service
4323  */
4324 APPLESTATIC int
4325 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4326     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4327 {
4328 	uint32_t *tl;
4329 	int error = 0, onefs;
4330 
4331 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4332 		nd->nd_repstat = NFSERR_WRONGSEC;
4333 		goto nfsmout;
4334 	}
4335 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4336 	/*
4337 	 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4338 	 * to be used after a file system has been transferred to a different
4339 	 * file server.  However, RFC5661 is somewhat vague w.r.t. this and
4340 	 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4341 	 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4342 	 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4343 	 * NFS_OK without doing anything.
4344 	 */
4345 	onefs = 0;
4346 	if (*tl == newnfs_true)
4347 		onefs = 1;
4348 	nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4349 nfsmout:
4350 	NFSEXITCODE2(error, nd);
4351 	return (error);
4352 }
4353 
4354 /*
4355  * nfsv4 destroy clientid service
4356  */
4357 APPLESTATIC int
4358 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4359     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4360 {
4361 	uint32_t *tl;
4362 	nfsquad_t clientid;
4363 	int error = 0;
4364 	struct thread *p = curthread;
4365 
4366 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4367 		nd->nd_repstat = NFSERR_WRONGSEC;
4368 		goto nfsmout;
4369 	}
4370 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4371 	clientid.lval[0] = *tl++;
4372 	clientid.lval[1] = *tl;
4373 	nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4374 nfsmout:
4375 	NFSEXITCODE2(error, nd);
4376 	return (error);
4377 }
4378 
4379 /*
4380  * nfsv4 bind connection to session service
4381  */
4382 APPLESTATIC int
4383 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4384     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4385 {
4386 	uint32_t *tl;
4387 	uint8_t sessid[NFSX_V4SESSIONID];
4388 	int error = 0, foreaft;
4389 
4390 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4391 		nd->nd_repstat = NFSERR_WRONGSEC;
4392 		goto nfsmout;
4393 	}
4394 	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4395 	NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4396 	tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4397 	foreaft = fxdr_unsigned(int, *tl++);
4398 	if (*tl == newnfs_true) {
4399 		/* RDMA is not supported. */
4400 		nd->nd_repstat = NFSERR_NOTSUPP;
4401 		goto nfsmout;
4402 	}
4403 
4404 	nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4405 	if (nd->nd_repstat == 0) {
4406 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4407 		    NFSX_UNSIGNED);
4408 		NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4409 		tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4410 		*tl++ = txdr_unsigned(foreaft);
4411 		*tl = newnfs_false;
4412 	}
4413 nfsmout:
4414 	NFSEXITCODE2(error, nd);
4415 	return (error);
4416 }
4417 
4418 /*
4419  * nfsv4 destroy session service
4420  */
4421 APPLESTATIC int
4422 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4423     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4424 {
4425 	uint8_t *cp, sessid[NFSX_V4SESSIONID];
4426 	int error = 0;
4427 
4428 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4429 		nd->nd_repstat = NFSERR_WRONGSEC;
4430 		goto nfsmout;
4431 	}
4432 	NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4433 	NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4434 	nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4435 nfsmout:
4436 	NFSEXITCODE2(error, nd);
4437 	return (error);
4438 }
4439 
4440 /*
4441  * nfsv4 free stateid service
4442  */
4443 APPLESTATIC int
4444 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4445     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4446 {
4447 	uint32_t *tl;
4448 	nfsv4stateid_t stateid;
4449 	int error = 0;
4450 	struct thread *p = curthread;
4451 
4452 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4453 		nd->nd_repstat = NFSERR_WRONGSEC;
4454 		goto nfsmout;
4455 	}
4456 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4457 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4458 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4459 
4460 	/*
4461 	 * For the special stateid of other all 0s and seqid == 1, set the
4462 	 * stateid to the current stateid, if it is set.
4463 	 */
4464 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4465 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
4466 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4467 			stateid = nd->nd_curstateid;
4468 			stateid.seqid = 0;
4469 		} else {
4470 			nd->nd_repstat = NFSERR_BADSTATEID;
4471 			goto nfsmout;
4472 		}
4473 	}
4474 
4475 	nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4476 
4477 	/* If the current stateid has been free'd, unset it. */
4478 	if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4479 	    stateid.other[0] == nd->nd_curstateid.other[0] &&
4480 	    stateid.other[1] == nd->nd_curstateid.other[1] &&
4481 	    stateid.other[2] == nd->nd_curstateid.other[2])
4482 		nd->nd_flag &= ~ND_CURSTATEID;
4483 nfsmout:
4484 	NFSEXITCODE2(error, nd);
4485 	return (error);
4486 }
4487 
4488 /*
4489  * nfsv4 layoutget service
4490  */
4491 APPLESTATIC int
4492 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4493     vnode_t vp, struct nfsexstuff *exp)
4494 {
4495 	uint32_t *tl;
4496 	nfsv4stateid_t stateid;
4497 	int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4498 	uint64_t offset, len, minlen;
4499 	char *layp;
4500 	struct thread *p = curthread;
4501 
4502 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4503 		nd->nd_repstat = NFSERR_WRONGSEC;
4504 		goto nfsmout;
4505 	}
4506 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4507 	    NFSX_STATEID);
4508 	tl++;		/* Signal layout available. Ignore for now. */
4509 	layouttype = fxdr_unsigned(int, *tl++);
4510 	iomode = fxdr_unsigned(int, *tl++);
4511 	offset = fxdr_hyper(tl); tl += 2;
4512 	len = fxdr_hyper(tl); tl += 2;
4513 	minlen = fxdr_hyper(tl); tl += 2;
4514 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4515 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4516 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4517 	maxcnt = fxdr_unsigned(int, *tl);
4518 	NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4519 	    layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4520 	    (uintmax_t)minlen);
4521 	if (len < minlen ||
4522 	    (minlen != UINT64_MAX && offset + minlen < offset) ||
4523 	    (len != UINT64_MAX && offset + len < offset)) {
4524 		nd->nd_repstat = NFSERR_INVAL;
4525 		goto nfsmout;
4526 	}
4527 
4528 	/*
4529 	 * For the special stateid of other all 0s and seqid == 1, set the
4530 	 * stateid to the current stateid, if it is set.
4531 	 */
4532 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4533 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
4534 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4535 			stateid = nd->nd_curstateid;
4536 			stateid.seqid = 0;
4537 		} else {
4538 			nd->nd_repstat = NFSERR_BADSTATEID;
4539 			goto nfsmout;
4540 		}
4541 	}
4542 
4543 	layp = NULL;
4544 	if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4545 		layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4546 	else if (layouttype == NFSLAYOUT_FLEXFILE)
4547 		layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4548 		    M_WAITOK);
4549 	else
4550 		nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4551 	if (layp != NULL)
4552 		nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4553 		    &iomode, &offset, &len, minlen, &stateid, maxcnt,
4554 		    &retonclose, &layoutlen, layp, nd->nd_cred, p);
4555 	NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4556 	    layoutlen);
4557 	if (nd->nd_repstat == 0) {
4558 		/* For NFSv4.1, set the Current StateID. */
4559 		if ((nd->nd_flag & ND_NFSV41) != 0) {
4560 			nd->nd_curstateid = stateid;
4561 			nd->nd_flag |= ND_CURSTATEID;
4562 		}
4563 		NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4564 		    2 * NFSX_HYPER);
4565 		*tl++ = txdr_unsigned(retonclose);
4566 		*tl++ = txdr_unsigned(stateid.seqid);
4567 		NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4568 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4569 		*tl++ = txdr_unsigned(1);	/* Only returns one layout. */
4570 		txdr_hyper(offset, tl); tl += 2;
4571 		txdr_hyper(len, tl); tl += 2;
4572 		*tl++ = txdr_unsigned(iomode);
4573 		*tl = txdr_unsigned(layouttype);
4574 		nfsm_strtom(nd, layp, layoutlen);
4575 	} else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4576 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4577 		*tl = newnfs_false;
4578 	}
4579 	free(layp, M_TEMP);
4580 nfsmout:
4581 	vput(vp);
4582 	NFSEXITCODE2(error, nd);
4583 	return (error);
4584 }
4585 
4586 /*
4587  * nfsv4 layoutcommit service
4588  */
4589 APPLESTATIC int
4590 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4591     vnode_t vp, struct nfsexstuff *exp)
4592 {
4593 	uint32_t *tl;
4594 	nfsv4stateid_t stateid;
4595 	int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4596 	int hasnewsize;
4597 	uint64_t offset, len, newoff = 0, newsize;
4598 	struct timespec newmtime;
4599 	char *layp;
4600 	struct thread *p = curthread;
4601 
4602 	layp = NULL;
4603 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4604 		nd->nd_repstat = NFSERR_WRONGSEC;
4605 		goto nfsmout;
4606 	}
4607 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4608 	    NFSX_STATEID);
4609 	offset = fxdr_hyper(tl); tl += 2;
4610 	len = fxdr_hyper(tl); tl += 2;
4611 	reclaim = fxdr_unsigned(int, *tl++);
4612 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4613 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4614 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4615 	/*
4616 	 * For the special stateid of other all 0s and seqid == 1, set the
4617 	 * stateid to the current stateid, if it is set.
4618 	 */
4619 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4620 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
4621 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4622 			stateid = nd->nd_curstateid;
4623 			stateid.seqid = 0;
4624 		} else {
4625 			nd->nd_repstat = NFSERR_BADSTATEID;
4626 			goto nfsmout;
4627 		}
4628 	}
4629 
4630 	hasnewoff = fxdr_unsigned(int, *tl);
4631 	if (hasnewoff != 0) {
4632 		NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4633 		newoff = fxdr_hyper(tl); tl += 2;
4634 	} else
4635 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4636 	hasnewmtime = fxdr_unsigned(int, *tl);
4637 	if (hasnewmtime != 0) {
4638 		NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4639 		fxdr_nfsv4time(tl, &newmtime);
4640 		tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4641 	} else
4642 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4643 	layouttype = fxdr_unsigned(int, *tl++);
4644 	maxcnt = fxdr_unsigned(int, *tl);
4645 	if (maxcnt > 0) {
4646 		layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4647 		error = nfsrv_mtostr(nd, layp, maxcnt);
4648 		if (error != 0)
4649 			goto nfsmout;
4650 	}
4651 	nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4652 	    newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4653 	    maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4654 	NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4655 	if (nd->nd_repstat == 0) {
4656 		if (hasnewsize != 0) {
4657 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4658 			*tl++ = newnfs_true;
4659 			txdr_hyper(newsize, tl);
4660 		} else {
4661 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4662 			*tl = newnfs_false;
4663 		}
4664 	}
4665 nfsmout:
4666 	free(layp, M_TEMP);
4667 	vput(vp);
4668 	NFSEXITCODE2(error, nd);
4669 	return (error);
4670 }
4671 
4672 /*
4673  * nfsv4 layoutreturn service
4674  */
4675 APPLESTATIC int
4676 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4677     vnode_t vp, struct nfsexstuff *exp)
4678 {
4679 	uint32_t *tl, *layp;
4680 	nfsv4stateid_t stateid;
4681 	int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4682 	uint64_t offset, len;
4683 	struct thread *p = curthread;
4684 
4685 	layp = NULL;
4686 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4687 		nd->nd_repstat = NFSERR_WRONGSEC;
4688 		goto nfsmout;
4689 	}
4690 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4691 	reclaim = *tl++;
4692 	layouttype = fxdr_unsigned(int, *tl++);
4693 	iomode = fxdr_unsigned(int, *tl++);
4694 	kind = fxdr_unsigned(int, *tl);
4695 	NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4696 	    layouttype, iomode, kind);
4697 	if (kind == NFSV4LAYOUTRET_FILE) {
4698 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4699 		    NFSX_UNSIGNED);
4700 		offset = fxdr_hyper(tl); tl += 2;
4701 		len = fxdr_hyper(tl); tl += 2;
4702 		stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4703 		NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4704 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4705 
4706 		/*
4707 		 * For the special stateid of other all 0s and seqid == 1, set
4708 		 * the stateid to the current stateid, if it is set.
4709 		 */
4710 		if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4711 		    stateid.other[1] == 0 && stateid.other[2] == 0) {
4712 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4713 				stateid = nd->nd_curstateid;
4714 				stateid.seqid = 0;
4715 			} else {
4716 				nd->nd_repstat = NFSERR_BADSTATEID;
4717 				goto nfsmout;
4718 			}
4719 		}
4720 
4721 		maxcnt = fxdr_unsigned(int, *tl);
4722 		if (maxcnt > 0) {
4723 			layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4724 			error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
4725 			if (error != 0)
4726 				goto nfsmout;
4727 		}
4728 	} else {
4729 		if (reclaim == newnfs_true) {
4730 			nd->nd_repstat = NFSERR_INVAL;
4731 			goto nfsmout;
4732 		}
4733 		offset = len = 0;
4734 		maxcnt = 0;
4735 	}
4736 	nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
4737 	    offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
4738 	    nd->nd_cred, p);
4739 	NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
4740 	    fnd);
4741 	if (nd->nd_repstat == 0) {
4742 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4743 		if (fnd != 0) {
4744 			*tl = newnfs_true;
4745 			NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
4746 			*tl++ = txdr_unsigned(stateid.seqid);
4747 			NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4748 		} else
4749 			*tl = newnfs_false;
4750 	}
4751 nfsmout:
4752 	free(layp, M_TEMP);
4753 	vput(vp);
4754 	NFSEXITCODE2(error, nd);
4755 	return (error);
4756 }
4757 
4758 /*
4759  * nfsv4 layout error service
4760  */
4761 APPLESTATIC int
4762 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
4763     vnode_t vp, struct nfsexstuff *exp)
4764 {
4765 	uint32_t *tl;
4766 	nfsv4stateid_t stateid;
4767 	int cnt, error = 0, i, stat;
4768 	int opnum __unused;
4769 	char devid[NFSX_V4DEVICEID];
4770 	uint64_t offset, len;
4771 
4772 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4773 		nd->nd_repstat = NFSERR_WRONGSEC;
4774 		goto nfsmout;
4775 	}
4776 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4777 	    NFSX_UNSIGNED);
4778 	offset = fxdr_hyper(tl); tl += 2;
4779 	len = fxdr_hyper(tl); tl += 2;
4780 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4781 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4782 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4783 	cnt = fxdr_unsigned(int, *tl);
4784 	NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
4785 	    (uintmax_t)len, cnt);
4786 	/*
4787 	 * For the special stateid of other all 0s and seqid == 1, set
4788 	 * the stateid to the current stateid, if it is set.
4789 	 */
4790 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4791 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
4792 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4793 			stateid = nd->nd_curstateid;
4794 			stateid.seqid = 0;
4795 		} else {
4796 			nd->nd_repstat = NFSERR_BADSTATEID;
4797 			goto nfsmout;
4798 		}
4799 	}
4800 
4801 	/*
4802 	 * Ignore offset, len and stateid for now.
4803 	 */
4804 	for (i = 0; i < cnt; i++) {
4805 		NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
4806 		    NFSX_UNSIGNED);
4807 		NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4808 		tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4809 		stat = fxdr_unsigned(int, *tl++);
4810 		opnum = fxdr_unsigned(int, *tl);
4811 		NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
4812 		/*
4813 		 * Except for NFSERR_ACCES and NFSERR_STALE errors,
4814 		 * disable the mirror.
4815 		 */
4816 		if (stat != NFSERR_ACCES && stat != NFSERR_STALE)
4817 			nfsrv_delds(devid, curthread);
4818 	}
4819 nfsmout:
4820 	vput(vp);
4821 	NFSEXITCODE2(error, nd);
4822 	return (error);
4823 }
4824 
4825 /*
4826  * nfsv4 layout stats service
4827  */
4828 APPLESTATIC int
4829 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
4830     vnode_t vp, struct nfsexstuff *exp)
4831 {
4832 	uint32_t *tl;
4833 	nfsv4stateid_t stateid;
4834 	int cnt, error = 0;
4835 	int layouttype __unused;
4836 	char devid[NFSX_V4DEVICEID] __unused;
4837 	uint64_t offset, len, readcount, readbytes, writecount, writebytes
4838 	    __unused;
4839 
4840 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4841 		nd->nd_repstat = NFSERR_WRONGSEC;
4842 		goto nfsmout;
4843 	}
4844 	NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
4845 	    NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
4846 	offset = fxdr_hyper(tl); tl += 2;
4847 	len = fxdr_hyper(tl); tl += 2;
4848 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4849 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4850 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4851 	readcount = fxdr_hyper(tl); tl += 2;
4852 	readbytes = fxdr_hyper(tl); tl += 2;
4853 	writecount = fxdr_hyper(tl); tl += 2;
4854 	writebytes = fxdr_hyper(tl); tl += 2;
4855 	NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4856 	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4857 	layouttype = fxdr_unsigned(int, *tl++);
4858 	cnt = fxdr_unsigned(int, *tl);
4859 	error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
4860 	if (error != 0)
4861 		goto nfsmout;
4862 	NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
4863 	/*
4864 	 * For the special stateid of other all 0s and seqid == 1, set
4865 	 * the stateid to the current stateid, if it is set.
4866 	 */
4867 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4868 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
4869 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4870 			stateid = nd->nd_curstateid;
4871 			stateid.seqid = 0;
4872 		} else {
4873 			nd->nd_repstat = NFSERR_BADSTATEID;
4874 			goto nfsmout;
4875 		}
4876 	}
4877 
4878 	/*
4879 	 * No use for the stats for now.
4880 	 */
4881 nfsmout:
4882 	vput(vp);
4883 	NFSEXITCODE2(error, nd);
4884 	return (error);
4885 }
4886 
4887 /*
4888  * nfsv4 io_advise service
4889  */
4890 APPLESTATIC int
4891 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
4892     vnode_t vp, struct nfsexstuff *exp)
4893 {
4894 	uint32_t *tl;
4895 	nfsv4stateid_t stateid;
4896 	nfsattrbit_t hints;
4897 	int error = 0, ret;
4898 	off_t offset, len;
4899 
4900 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4901 		nd->nd_repstat = NFSERR_WRONGSEC;
4902 		goto nfsmout;
4903 	}
4904 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
4905 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4906 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4907 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4908 	offset = fxdr_hyper(tl); tl += 2;
4909 	len = fxdr_hyper(tl);
4910 	error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
4911 	if (error != 0)
4912 		goto nfsmout;
4913 	/*
4914 	 * For the special stateid of other all 0s and seqid == 1, set
4915 	 * the stateid to the current stateid, if it is set.
4916 	 */
4917 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4918 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
4919 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4920 			stateid = nd->nd_curstateid;
4921 			stateid.seqid = 0;
4922 		} else {
4923 			nd->nd_repstat = NFSERR_BADSTATEID;
4924 			goto nfsmout;
4925 		}
4926 	}
4927 
4928 	if (offset < 0) {
4929 		nd->nd_repstat = NFSERR_INVAL;
4930 		goto nfsmout;
4931 	}
4932 	if (len < 0)
4933 		len = 0;
4934 	if (vp->v_type != VREG) {
4935 		if (vp->v_type == VDIR)
4936 			nd->nd_repstat = NFSERR_ISDIR;
4937 		else
4938 			nd->nd_repstat = NFSERR_WRONGTYPE;
4939 		goto nfsmout;
4940 	}
4941 
4942 	/*
4943 	 * For now, we can only handle WILLNEED and DONTNEED and don't use
4944 	 * the stateid.
4945 	 */
4946 	if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
4947 	    !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
4948 	    (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
4949 	    !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
4950 		NFSVOPUNLOCK(vp);
4951 		if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
4952 			ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
4953 			NFSZERO_ATTRBIT(&hints);
4954 			if (ret == 0)
4955 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
4956 			else
4957 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4958 		} else {
4959 			ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
4960 			NFSZERO_ATTRBIT(&hints);
4961 			if (ret == 0)
4962 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
4963 			else
4964 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4965 		}
4966 		vrele(vp);
4967 	} else {
4968 		NFSZERO_ATTRBIT(&hints);
4969 		NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4970 		vput(vp);
4971 	}
4972 	nfsrv_putattrbit(nd, &hints);
4973 	NFSEXITCODE2(error, nd);
4974 	return (error);
4975 nfsmout:
4976 	vput(vp);
4977 	NFSEXITCODE2(error, nd);
4978 	return (error);
4979 }
4980 
4981 /*
4982  * nfsv4 getdeviceinfo service
4983  */
4984 APPLESTATIC int
4985 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
4986     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4987 {
4988 	uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
4989 	int cnt, devaddrlen, error = 0, i, layouttype;
4990 	char devid[NFSX_V4DEVICEID], *devaddr;
4991 	time_t dev_time;
4992 
4993 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4994 		nd->nd_repstat = NFSERR_WRONGSEC;
4995 		goto nfsmout;
4996 	}
4997 	NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
4998 	NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4999 	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5000 	layouttype = fxdr_unsigned(int, *tl++);
5001 	maxcnt = fxdr_unsigned(uint32_t, *tl++);
5002 	cnt = fxdr_unsigned(int, *tl);
5003 	NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5004 	    maxcnt, cnt);
5005 	if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5006 		nd->nd_repstat = NFSERR_INVAL;
5007 		goto nfsmout;
5008 	}
5009 	if (cnt > 0) {
5010 		NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5011 		for (i = 0; i < cnt; i++)
5012 			notify[i] = fxdr_unsigned(uint32_t, *tl++);
5013 	}
5014 	for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5015 		notify[i] = 0;
5016 
5017 	/*
5018 	 * Check that the device id is not stale.  Device ids are recreated
5019 	 * each time the nfsd threads are restarted.
5020 	 */
5021 	NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5022 	if (dev_time != nfsdev_time) {
5023 		nd->nd_repstat = NFSERR_NOENT;
5024 		goto nfsmout;
5025 	}
5026 
5027 	/* Look for the device id. */
5028 	nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5029 	    notify, &devaddrlen, &devaddr);
5030 	NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5031 	if (nd->nd_repstat == 0) {
5032 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5033 		*tl = txdr_unsigned(layouttype);
5034 		nfsm_strtom(nd, devaddr, devaddrlen);
5035 		cnt = 0;
5036 		for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5037 			if (notify[i] != 0)
5038 				cnt = i + 1;
5039 		}
5040 		NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5041 		*tl++ = txdr_unsigned(cnt);
5042 		for (i = 0; i < cnt; i++)
5043 			*tl++ = txdr_unsigned(notify[i]);
5044 	} else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5045 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5046 		*tl = txdr_unsigned(maxcnt);
5047 	}
5048 nfsmout:
5049 	NFSEXITCODE2(error, nd);
5050 	return (error);
5051 }
5052 
5053 /*
5054  * nfsv4 test stateid service
5055  */
5056 APPLESTATIC int
5057 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5058     __unused vnode_t vp, __unused struct nfsexstuff *exp)
5059 {
5060 	uint32_t *tl;
5061 	nfsv4stateid_t *stateidp = NULL, *tstateidp;
5062 	int cnt, error = 0, i, ret;
5063 	struct thread *p = curthread;
5064 
5065 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5066 		nd->nd_repstat = NFSERR_WRONGSEC;
5067 		goto nfsmout;
5068 	}
5069 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5070 	cnt = fxdr_unsigned(int, *tl);
5071 	if (cnt <= 0 || cnt > 1024) {
5072 		nd->nd_repstat = NFSERR_BADXDR;
5073 		goto nfsmout;
5074 	}
5075 	stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5076 	tstateidp = stateidp;
5077 	for (i = 0; i < cnt; i++) {
5078 		NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5079 		tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5080 		NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5081 		tstateidp++;
5082 	}
5083 	NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5084 	*tl = txdr_unsigned(cnt);
5085 	tstateidp = stateidp;
5086 	for (i = 0; i < cnt; i++) {
5087 		ret = nfsrv_teststateid(nd, tstateidp, p);
5088 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5089 		*tl = txdr_unsigned(ret);
5090 		tstateidp++;
5091 	}
5092 nfsmout:
5093 	free(stateidp, M_TEMP);
5094 	NFSEXITCODE2(error, nd);
5095 	return (error);
5096 }
5097 
5098 /*
5099  * nfs allocate service
5100  */
5101 APPLESTATIC int
5102 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5103     vnode_t vp, struct nfsexstuff *exp)
5104 {
5105 	uint32_t *tl;
5106 	struct nfsvattr forat;
5107 	int error = 0, forat_ret = 1, gotproxystateid;
5108 	off_t off, len;
5109 	struct nfsstate st, *stp = &st;
5110 	struct nfslock lo, *lop = &lo;
5111 	nfsv4stateid_t stateid;
5112 	nfsquad_t clientid;
5113 	nfsattrbit_t attrbits;
5114 
5115 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5116 		nd->nd_repstat = NFSERR_WRONGSEC;
5117 		goto nfsmout;
5118 	}
5119 	gotproxystateid = 0;
5120 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5121 	stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5122 	lop->lo_flags = NFSLCK_WRITE;
5123 	stp->ls_ownerlen = 0;
5124 	stp->ls_op = NULL;
5125 	stp->ls_uid = nd->nd_cred->cr_uid;
5126 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5127 	clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5128 	clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5129 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5130 		if ((nd->nd_flag & ND_NFSV41) != 0)
5131 			clientid.qval = nd->nd_clientid.qval;
5132 		else if (nd->nd_clientid.qval != clientid.qval)
5133 			printf("EEK2 multiple clids\n");
5134 	} else {
5135 		if ((nd->nd_flag & ND_NFSV41) != 0)
5136 			printf("EEK! no clientid from session\n");
5137 		nd->nd_flag |= ND_IMPLIEDCLID;
5138 		nd->nd_clientid.qval = clientid.qval;
5139 	}
5140 	stp->ls_stateid.other[2] = *tl++;
5141 	/*
5142 	 * Don't allow this to be done for a DS.
5143 	 */
5144 	if ((nd->nd_flag & ND_DSSERVER) != 0)
5145 		nd->nd_repstat = NFSERR_NOTSUPP;
5146 	/* However, allow the proxy stateid. */
5147 	if (stp->ls_stateid.seqid == 0xffffffff &&
5148 	    stp->ls_stateid.other[0] == 0x55555555 &&
5149 	    stp->ls_stateid.other[1] == 0x55555555 &&
5150 	    stp->ls_stateid.other[2] == 0x55555555)
5151 		gotproxystateid = 1;
5152 	off = fxdr_hyper(tl); tl += 2;
5153 	lop->lo_first = off;
5154 	len = fxdr_hyper(tl);
5155 	lop->lo_end = off + len;
5156 	/*
5157 	 * Paranoia, just in case it wraps around, which shouldn't
5158 	 * ever happen anyhow.
5159 	 */
5160 	if (nd->nd_repstat == 0 && (lop->lo_end < lop->lo_first || len <= 0))
5161 		nd->nd_repstat = NFSERR_INVAL;
5162 
5163 	if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5164 		nd->nd_repstat = NFSERR_WRONGTYPE;
5165 	NFSZERO_ATTRBIT(&attrbits);
5166 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5167 	forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5168 	if (nd->nd_repstat == 0)
5169 		nd->nd_repstat = forat_ret;
5170 	if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5171 	     NFSVNO_EXSTRICTACCESS(exp)))
5172 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5173 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5174 		    NULL);
5175 	if (nd->nd_repstat == 0 && gotproxystateid == 0)
5176 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5177 		    &stateid, exp, nd, curthread);
5178 
5179 	if (nd->nd_repstat == 0)
5180 		nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5181 		    curthread);
5182 	vput(vp);
5183 	NFSEXITCODE2(0, nd);
5184 	return (0);
5185 nfsmout:
5186 	vput(vp);
5187 	NFSEXITCODE2(error, nd);
5188 	return (error);
5189 }
5190 
5191 /*
5192  * nfs copy service
5193  */
5194 APPLESTATIC int
5195 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5196     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5197 {
5198 	uint32_t *tl;
5199 	struct nfsvattr at;
5200 	int cnt, error = 0, ret;
5201 	off_t inoff, outoff;
5202 	uint64_t len;
5203 	size_t xfer;
5204 	struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5205 	struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5206 	nfsquad_t clientid;
5207 	nfsv4stateid_t stateid;
5208 	nfsattrbit_t attrbits;
5209 	void *rl_rcookie, *rl_wcookie;
5210 
5211 	rl_rcookie = rl_wcookie = NULL;
5212 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5213 		nd->nd_repstat = NFSERR_WRONGSEC;
5214 		goto nfsmout;
5215 	}
5216 	if (nfsrv_devidcnt > 0) {
5217 		/*
5218 		 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5219 		 * will do the copy via I/O on the DS(s).
5220 		 */
5221 		nd->nd_repstat = NFSERR_NOTSUPP;
5222 		goto nfsmout;
5223 	}
5224 	if (vp == tovp) {
5225 		/* Copying a byte range within the same file is not allowed. */
5226 		nd->nd_repstat = NFSERR_INVAL;
5227 		goto nfsmout;
5228 	}
5229 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5230 	    3 * NFSX_UNSIGNED);
5231 	instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5232 	inlop->lo_flags = NFSLCK_READ;
5233 	instp->ls_ownerlen = 0;
5234 	instp->ls_op = NULL;
5235 	instp->ls_uid = nd->nd_cred->cr_uid;
5236 	instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5237 	clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5238 	clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5239 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5240 		clientid.qval = nd->nd_clientid.qval;
5241 	instp->ls_stateid.other[2] = *tl++;
5242 	outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5243 	outlop->lo_flags = NFSLCK_WRITE;
5244 	outstp->ls_ownerlen = 0;
5245 	outstp->ls_op = NULL;
5246 	outstp->ls_uid = nd->nd_cred->cr_uid;
5247 	outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5248 	outstp->ls_stateid.other[0] = *tl++;
5249 	outstp->ls_stateid.other[1] = *tl++;
5250 	outstp->ls_stateid.other[2] = *tl++;
5251 	inoff = fxdr_hyper(tl); tl += 2;
5252 	inlop->lo_first = inoff;
5253 	outoff = fxdr_hyper(tl); tl += 2;
5254 	outlop->lo_first = outoff;
5255 	len = fxdr_hyper(tl); tl += 2;
5256 	if (len == 0) {
5257 		/* len == 0 means to EOF. */
5258 		inlop->lo_end = OFF_MAX;
5259 		outlop->lo_end = OFF_MAX;
5260 	} else {
5261 		inlop->lo_end = inlop->lo_first + len;
5262 		outlop->lo_end = outlop->lo_first + len;
5263 	}
5264 
5265 	/*
5266 	 * At this time only consecutive, synchronous copy is supported,
5267 	 * so ca_consecutive and ca_synchronous can be ignored.
5268 	 */
5269 	tl += 2;
5270 
5271 	cnt = fxdr_unsigned(int, *tl);
5272 	if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5273 		nd->nd_repstat = NFSERR_NOTSUPP;
5274 	if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5275 	    inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5276 	    inlop->lo_end < inlop->lo_first || outlop->lo_end <
5277 	    outlop->lo_first))
5278 		nd->nd_repstat = NFSERR_INVAL;
5279 
5280 	if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5281 		nd->nd_repstat = NFSERR_WRONGTYPE;
5282 
5283 	/* Check permissions for the input file. */
5284 	NFSZERO_ATTRBIT(&attrbits);
5285 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5286 	ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5287 	if (nd->nd_repstat == 0)
5288 		nd->nd_repstat = ret;
5289 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5290 	     NFSVNO_EXSTRICTACCESS(exp)))
5291 		nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5292 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5293 		    NULL);
5294 	if (nd->nd_repstat == 0)
5295 		nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5296 		    clientid, &stateid, exp, nd, curthread);
5297 	NFSVOPUNLOCK(vp);
5298 	if (nd->nd_repstat != 0)
5299 		goto out;
5300 
5301 	error = NFSVOPLOCK(tovp, LK_SHARED);
5302 	if (error != 0)
5303 		goto out;
5304 	if (vnode_vtype(tovp) != VREG)
5305 		nd->nd_repstat = NFSERR_WRONGTYPE;
5306 
5307 	/* For the output file, we only need the Owner attribute. */
5308 	ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5309 	if (nd->nd_repstat == 0)
5310 		nd->nd_repstat = ret;
5311 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5312 	     NFSVNO_EXSTRICTACCESS(exp)))
5313 		nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5314 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5315 		    NULL);
5316 	if (nd->nd_repstat == 0)
5317 		nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5318 		    clientid, &stateid, toexp, nd, curthread);
5319 	NFSVOPUNLOCK(tovp);
5320 
5321 	/* Range lock the byte ranges for both invp and outvp. */
5322 	if (nd->nd_repstat == 0) {
5323 		for (;;) {
5324 			if (len == 0) {
5325 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5326 				    OFF_MAX);
5327 				rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5328 				    OFF_MAX);
5329 			} else {
5330 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5331 				    outoff + len);
5332 				rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5333 				    inoff + len);
5334 			}
5335 			if (rl_rcookie != NULL)
5336 				break;
5337 			vn_rangelock_unlock(tovp, rl_wcookie);
5338 			if (len == 0)
5339 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
5340 				    OFF_MAX);
5341 			else
5342 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
5343 				    inoff + len);
5344 			vn_rangelock_unlock(vp, rl_rcookie);
5345 		}
5346 
5347 		error = NFSVOPLOCK(vp, LK_SHARED);
5348 		if (error == 0) {
5349 			ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5350 			if (ret == 0) {
5351 				/*
5352 				 * Since invp is range locked, na_size should
5353 				 * not change.
5354 				 */
5355 				if (len == 0 && at.na_size > inoff) {
5356 					/*
5357 					 * If len == 0, set it based on invp's
5358 					 * size. If offset is past EOF, just
5359 					 * leave len == 0.
5360 					 */
5361 					len = at.na_size - inoff;
5362 				} else if (nfsrv_linux42server == 0 &&
5363 				    inoff + len > at.na_size) {
5364 					/*
5365 					 * RFC-7862 says that NFSERR_INVAL must
5366 					 * be returned when inoff + len exceeds
5367 					 * the file size, however the NFSv4.2
5368 					 * Linux client likes to do this, so
5369 					 * only check if nfsrv_linux42server
5370 					 * is not set.
5371 					 */
5372 					nd->nd_repstat = NFSERR_INVAL;
5373 				}
5374 			}
5375 			NFSVOPUNLOCK(vp);
5376 			if (ret != 0 && nd->nd_repstat == 0)
5377 				nd->nd_repstat = ret;
5378 		} else if (nd->nd_repstat == 0)
5379 			nd->nd_repstat = error;
5380 	}
5381 
5382 	/*
5383 	 * Do the actual copy to an upper limit of vfs.nfs.maxcopyrange.
5384 	 * This limit is applied to ensure that the RPC replies in a
5385 	 * reasonable time.
5386 	 */
5387 	if (len > nfs_maxcopyrange)
5388 		xfer = nfs_maxcopyrange;
5389 	else
5390 		xfer = len;
5391 	if (nd->nd_repstat == 0) {
5392 		nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5393 		    &xfer, 0, nd->nd_cred, nd->nd_cred, NULL);
5394 		if (nd->nd_repstat == 0)
5395 			len = xfer;
5396 	}
5397 
5398 	/* Unlock the ranges. */
5399 	if (rl_rcookie != NULL)
5400 		vn_rangelock_unlock(vp, rl_rcookie);
5401 	if (rl_wcookie != NULL)
5402 		vn_rangelock_unlock(tovp, rl_wcookie);
5403 
5404 	if (nd->nd_repstat == 0) {
5405 		NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5406 		    NFSX_VERF);
5407 		*tl++ = txdr_unsigned(0);	/* No callback ids. */
5408 		txdr_hyper(len, tl); tl += 2;
5409 		*tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
5410 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
5411 		*tl++ = txdr_unsigned(nfsboottime.tv_usec);
5412 		*tl++ = newnfs_true;
5413 		*tl = newnfs_true;
5414 	}
5415 out:
5416 	vrele(vp);
5417 	vrele(tovp);
5418 	NFSEXITCODE2(error, nd);
5419 	return (error);
5420 nfsmout:
5421 	vput(vp);
5422 	vrele(tovp);
5423 	NFSEXITCODE2(error, nd);
5424 	return (error);
5425 }
5426 
5427 /*
5428  * nfs seek service
5429  */
5430 APPLESTATIC int
5431 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
5432     vnode_t vp, struct nfsexstuff *exp)
5433 {
5434 	uint32_t *tl;
5435 	struct nfsvattr at;
5436 	int content, error = 0;
5437 	off_t off;
5438 	u_long cmd;
5439 	nfsattrbit_t attrbits;
5440 	bool eof;
5441 
5442 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5443 		nd->nd_repstat = NFSERR_WRONGSEC;
5444 		goto nfsmout;
5445 	}
5446 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
5447 	/* Ignore the stateid for now. */
5448 	tl += (NFSX_STATEID / NFSX_UNSIGNED);
5449 	off = fxdr_hyper(tl); tl += 2;
5450 	content = fxdr_unsigned(int, *tl);
5451 	if (content == NFSV4CONTENT_DATA)
5452 		cmd = FIOSEEKDATA;
5453 	else if (content == NFSV4CONTENT_HOLE)
5454 		cmd = FIOSEEKHOLE;
5455 	else
5456 		nd->nd_repstat = NFSERR_BADXDR;
5457 	if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR)
5458 		nd->nd_repstat = NFSERR_ISDIR;
5459 	if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5460 		nd->nd_repstat = NFSERR_WRONGTYPE;
5461 	if (nd->nd_repstat == 0 && off < 0)
5462 		nd->nd_repstat = NFSERR_NXIO;
5463 	if (nd->nd_repstat == 0) {
5464 		/* Check permissions for the input file. */
5465 		NFSZERO_ATTRBIT(&attrbits);
5466 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5467 		nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
5468 		    &attrbits);
5469 	}
5470 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5471 	     NFSVNO_EXSTRICTACCESS(exp)))
5472 		nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5473 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5474 		    NULL);
5475 	if (nd->nd_repstat != 0)
5476 		goto nfsmout;
5477 
5478 	/* nfsvno_seek() unlocks and vrele()s the vp. */
5479 	nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
5480 	    nd->nd_cred, curthread);
5481 	if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
5482 	    nfsrv_linux42server != 0)
5483 		nd->nd_repstat = NFSERR_NXIO;
5484 	if (nd->nd_repstat == 0) {
5485 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5486 		if (eof)
5487 			*tl++ = newnfs_true;
5488 		else
5489 			*tl++ = newnfs_false;
5490 		txdr_hyper(off, tl);
5491 	}
5492 	NFSEXITCODE2(error, nd);
5493 	return (error);
5494 nfsmout:
5495 	vput(vp);
5496 	NFSEXITCODE2(error, nd);
5497 	return (error);
5498 }
5499 
5500 /*
5501  * nfs get extended attribute service
5502  */
5503 APPLESTATIC int
5504 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
5505     vnode_t vp, __unused struct nfsexstuff *exp)
5506 {
5507 	uint32_t *tl;
5508 	mbuf_t mp = NULL, mpend = NULL;
5509 	int error, len;
5510 	char *name;
5511 	struct thread *p = curthread;
5512 
5513 	error = 0;
5514 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5515 		nd->nd_repstat = NFSERR_WRONGSEC;
5516 		goto nfsmout;
5517 	}
5518 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5519 	len = fxdr_unsigned(int, *tl);
5520 	if (len <= 0) {
5521 		nd->nd_repstat = NFSERR_BADXDR;
5522 		goto nfsmout;
5523 	}
5524 	if (len > EXTATTR_MAXNAMELEN) {
5525 		nd->nd_repstat = NFSERR_NOXATTR;
5526 		goto nfsmout;
5527 	}
5528 	name = malloc(len + 1, M_TEMP, M_WAITOK);
5529 	nd->nd_repstat = nfsrv_mtostr(nd, name, len);
5530 	if (nd->nd_repstat == 0)
5531 		nd->nd_repstat = nfsvno_getxattr(vp, name, nd->nd_maxresp,
5532 		    nd->nd_cred, p, &mp, &mpend, &len);
5533 	if (nd->nd_repstat == ENOATTR)
5534 		nd->nd_repstat = NFSERR_NOXATTR;
5535 	else if (nd->nd_repstat == EOPNOTSUPP)
5536 		nd->nd_repstat = NFSERR_NOTSUPP;
5537 	if (nd->nd_repstat == 0) {
5538 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5539 		*tl = txdr_unsigned(len);
5540 		mbuf_setnext(nd->nd_mb, mp);
5541 		nd->nd_mb = mpend;
5542 		nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
5543 	}
5544 	free(name, M_TEMP);
5545 
5546 nfsmout:
5547 	if (nd->nd_repstat == 0)
5548 		nd->nd_repstat = error;
5549 	vput(vp);
5550 	NFSEXITCODE2(0, nd);
5551 	return (0);
5552 }
5553 
5554 /*
5555  * nfs set extended attribute service
5556  */
5557 APPLESTATIC int
5558 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
5559     vnode_t vp, __unused struct nfsexstuff *exp)
5560 {
5561 	uint32_t *tl;
5562 	struct nfsvattr ova, nva;
5563 	nfsattrbit_t attrbits;
5564 	int error, len, opt;
5565 	char *name;
5566 	size_t siz;
5567 	struct thread *p = curthread;
5568 
5569 	error = 0;
5570 	name = NULL;
5571 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5572 		nd->nd_repstat = NFSERR_WRONGSEC;
5573 		goto nfsmout;
5574 	}
5575 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5576 	opt = fxdr_unsigned(int, *tl++);
5577 	len = fxdr_unsigned(int, *tl);
5578 	if (len <= 0) {
5579 		nd->nd_repstat = NFSERR_BADXDR;
5580 		goto nfsmout;
5581 	}
5582 	if (len > EXTATTR_MAXNAMELEN) {
5583 		nd->nd_repstat = NFSERR_NOXATTR;
5584 		goto nfsmout;
5585 	}
5586 	name = malloc(len + 1, M_TEMP, M_WAITOK);
5587 	error = nfsrv_mtostr(nd, name, len);
5588 	if (error != 0)
5589 		goto nfsmout;
5590 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5591 	len = fxdr_unsigned(int, *tl);
5592 	if (len <= 0 || len > IOSIZE_MAX) {
5593 		nd->nd_repstat = NFSERR_XATTR2BIG;
5594 		goto nfsmout;
5595 	}
5596 	switch (opt) {
5597 	case NFSV4SXATTR_CREATE:
5598 		error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5599 		    &siz, nd->nd_cred, p);
5600 		if (error != ENOATTR)
5601 			nd->nd_repstat = NFSERR_EXIST;
5602 		error = 0;
5603 		break;
5604 	case NFSV4SXATTR_REPLACE:
5605 		error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5606 		    &siz, nd->nd_cred, p);
5607 		if (error != 0)
5608 			nd->nd_repstat = NFSERR_NOXATTR;
5609 		break;
5610 	case NFSV4SXATTR_EITHER:
5611 		break;
5612 	default:
5613 		nd->nd_repstat = NFSERR_BADXDR;
5614 	}
5615 	if (nd->nd_repstat != 0)
5616 		goto nfsmout;
5617 
5618 	/* Now, do the Set Extended attribute, with Change before and after. */
5619 	NFSZERO_ATTRBIT(&attrbits);
5620 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5621 	nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5622 	if (nd->nd_repstat == 0) {
5623 		nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
5624 		    nd->nd_dpos, nd->nd_cred, p);
5625 		if (nd->nd_repstat == ENXIO)
5626 			nd->nd_repstat = NFSERR_XATTR2BIG;
5627 	}
5628 	if (nd->nd_repstat == 0)
5629 		nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
5630 	if (nd->nd_repstat == 0)
5631 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5632 	if (nd->nd_repstat == 0) {
5633 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
5634 		*tl++ = newnfs_true;
5635 		txdr_hyper(ova.na_filerev, tl); tl += 2;
5636 		txdr_hyper(nva.na_filerev, tl);
5637 	}
5638 
5639 nfsmout:
5640 	free(name, M_TEMP);
5641 	if (nd->nd_repstat == 0)
5642 		nd->nd_repstat = error;
5643 	vput(vp);
5644 	NFSEXITCODE2(0, nd);
5645 	return (0);
5646 }
5647 
5648 /*
5649  * nfs remove extended attribute service
5650  */
5651 APPLESTATIC int
5652 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
5653     vnode_t vp, __unused struct nfsexstuff *exp)
5654 {
5655 	uint32_t *tl;
5656 	struct nfsvattr ova, nva;
5657 	nfsattrbit_t attrbits;
5658 	int error, len;
5659 	char *name;
5660 	struct thread *p = curthread;
5661 
5662 	error = 0;
5663 	name = NULL;
5664 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5665 		nd->nd_repstat = NFSERR_WRONGSEC;
5666 		goto nfsmout;
5667 	}
5668 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5669 	len = fxdr_unsigned(int, *tl);
5670 	if (len <= 0) {
5671 		nd->nd_repstat = NFSERR_BADXDR;
5672 		goto nfsmout;
5673 	}
5674 	if (len > EXTATTR_MAXNAMELEN) {
5675 		nd->nd_repstat = NFSERR_NOXATTR;
5676 		goto nfsmout;
5677 	}
5678 	name = malloc(len + 1, M_TEMP, M_WAITOK);
5679 	error = nfsrv_mtostr(nd, name, len);
5680 	if (error != 0)
5681 		goto nfsmout;
5682 
5683 	if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
5684 		printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
5685 		error = NFSERR_NOXATTR;
5686 		goto nfsmout;
5687 	}
5688 	/*
5689 	 * Now, do the Remove Extended attribute, with Change before and
5690 	 * after.
5691 	*/
5692 	NFSZERO_ATTRBIT(&attrbits);
5693 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5694 	nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5695 	if (nd->nd_repstat == 0) {
5696 		nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
5697 		if (nd->nd_repstat == ENOATTR)
5698 			nd->nd_repstat = NFSERR_NOXATTR;
5699 	}
5700 	if (nd->nd_repstat == 0)
5701 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5702 	if (nd->nd_repstat == 0) {
5703 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER);
5704 		txdr_hyper(ova.na_filerev, tl); tl += 2;
5705 		txdr_hyper(nva.na_filerev, tl);
5706 	}
5707 
5708 nfsmout:
5709 	free(name, M_TEMP);
5710 	if (nd->nd_repstat == 0)
5711 		nd->nd_repstat = error;
5712 	vput(vp);
5713 	NFSEXITCODE2(0, nd);
5714 	return (0);
5715 }
5716 
5717 /*
5718  * nfs list extended attribute service
5719  */
5720 APPLESTATIC int
5721 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
5722     vnode_t vp, __unused struct nfsexstuff *exp)
5723 {
5724 	uint32_t cnt, *tl, len, len2, i, pos, retlen;
5725 	int error;
5726 	uint64_t cookie, cookie2;
5727 	u_char *buf;
5728 	bool eof;
5729 	struct thread *p = curthread;
5730 
5731 	error = 0;
5732 	buf = NULL;
5733 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5734 		nd->nd_repstat = NFSERR_WRONGSEC;
5735 		goto nfsmout;
5736 	}
5737 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5738 	/*
5739 	 * The cookie doesn't need to be in net byte order, but FreeBSD
5740 	 * does so to make it more readable in packet traces.
5741 	 */
5742 	cookie = fxdr_hyper(tl); tl += 2;
5743 	len = fxdr_unsigned(uint32_t, *tl);
5744 	if (len == 0 || cookie >= IOSIZE_MAX) {
5745 		nd->nd_repstat = NFSERR_BADXDR;
5746 		goto nfsmout;
5747 	}
5748 	if (len > nd->nd_maxresp - NFS_MAXXDR)
5749 		len = nd->nd_maxresp - NFS_MAXXDR;
5750 	len2 = len;
5751 	nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
5752 	    &len, &eof);
5753 	if (nd->nd_repstat == EOPNOTSUPP)
5754 		nd->nd_repstat = NFSERR_NOTSUPP;
5755 	if (nd->nd_repstat == 0) {
5756 		cookie2 = cookie + len;
5757 		if (cookie2 < cookie)
5758 			nd->nd_repstat = NFSERR_BADXDR;
5759 	}
5760 	if (nd->nd_repstat == 0) {
5761 		/* Now copy the entries out. */
5762 		retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
5763 		if (len == 0 && retlen <= len2) {
5764 			/* The cookie was at eof. */
5765 			NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
5766 			    NFSX_UNSIGNED);
5767 			txdr_hyper(cookie2, tl); tl += 2;
5768 			*tl++ = txdr_unsigned(0);
5769 			*tl = newnfs_true;
5770 			goto nfsmout;
5771 		}
5772 
5773 		/* Sanity check the cookie. */
5774 		for (pos = 0; pos < len; pos += (i + 1)) {
5775 			if (pos == cookie)
5776 				break;
5777 			i = buf[pos];
5778 		}
5779 		if (pos != cookie) {
5780 			nd->nd_repstat = NFSERR_INVAL;
5781 			goto nfsmout;
5782 		}
5783 
5784 		/* Loop around copying the entrie(s) out. */
5785 		cnt = 0;
5786 		len -= cookie;
5787 		i = buf[pos];
5788 		while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
5789 		    NFSX_UNSIGNED) {
5790 			if (cnt == 0) {
5791 				NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
5792 				    NFSX_UNSIGNED);
5793 				txdr_hyper(cookie2, tl); tl += 2;
5794 			}
5795 			retlen += nfsm_strtom(nd, &buf[pos + 1], i);
5796 			len -= (i + 1);
5797 			pos += (i + 1);
5798 			i = buf[pos];
5799 			cnt++;
5800 		}
5801 		/*
5802 		 * eof is set true/false by nfsvno_listxattr(), but if we
5803 		 * can't copy all entries returned by nfsvno_listxattr(),
5804 		 * we are not at eof.
5805 		 */
5806 		if (len > 0)
5807 			eof = false;
5808 		if (cnt > 0) {
5809 			/* *tl is set above. */
5810 			*tl = txdr_unsigned(cnt);
5811 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5812 			if (eof)
5813 				*tl = newnfs_true;
5814 			else
5815 				*tl = newnfs_false;
5816 		} else
5817 			nd->nd_repstat = NFSERR_TOOSMALL;
5818 	}
5819 
5820 nfsmout:
5821 	free(buf, M_TEMP);
5822 	if (nd->nd_repstat == 0)
5823 		nd->nd_repstat = error;
5824 	vput(vp);
5825 	NFSEXITCODE2(0, nd);
5826 	return (0);
5827 }
5828 
5829 /*
5830  * nfsv4 service not supported
5831  */
5832 APPLESTATIC int
5833 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
5834     __unused vnode_t vp, __unused struct nfsexstuff *exp)
5835 {
5836 
5837 	nd->nd_repstat = NFSERR_NOTSUPP;
5838 	NFSEXITCODE2(0, nd);
5839 	return (0);
5840 }
5841 
5842