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