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