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