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