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