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