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