xref: /freebsd/sys/fs/nfsserver/nfs_nfsdserv.c (revision b4645807afb50f2430ac2125812fd4a9f1d89a8c)
19ec7b004SRick Macklem /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
49ec7b004SRick Macklem  * Copyright (c) 1989, 1993
59ec7b004SRick Macklem  *	The Regents of the University of California.  All rights reserved.
69ec7b004SRick Macklem  *
79ec7b004SRick Macklem  * This code is derived from software contributed to Berkeley by
89ec7b004SRick Macklem  * Rick Macklem at The University of Guelph.
99ec7b004SRick Macklem  *
109ec7b004SRick Macklem  * Redistribution and use in source and binary forms, with or without
119ec7b004SRick Macklem  * modification, are permitted provided that the following conditions
129ec7b004SRick Macklem  * are met:
139ec7b004SRick Macklem  * 1. Redistributions of source code must retain the above copyright
149ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer.
159ec7b004SRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
169ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer in the
179ec7b004SRick Macklem  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
199ec7b004SRick Macklem  *    may be used to endorse or promote products derived from this software
209ec7b004SRick Macklem  *    without specific prior written permission.
219ec7b004SRick Macklem  *
229ec7b004SRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239ec7b004SRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249ec7b004SRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259ec7b004SRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269ec7b004SRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279ec7b004SRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289ec7b004SRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299ec7b004SRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309ec7b004SRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319ec7b004SRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329ec7b004SRick Macklem  * SUCH DAMAGE.
339ec7b004SRick Macklem  *
349ec7b004SRick Macklem  */
359ec7b004SRick Macklem 
369ec7b004SRick Macklem #include <sys/cdefs.h>
379ec7b004SRick Macklem __FBSDID("$FreeBSD$");
389ec7b004SRick Macklem 
39ed2f1001SRick Macklem #include "opt_inet.h"
40ed2f1001SRick Macklem #include "opt_inet6.h"
419ec7b004SRick Macklem /*
429ec7b004SRick Macklem  * nfs version 2, 3 and 4 server calls to vnode ops
439ec7b004SRick Macklem  * - these routines generally have 3 phases
449ec7b004SRick Macklem  *   1 - break down and validate rpc request in mbuf list
459ec7b004SRick Macklem  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
469ec7b004SRick Macklem  *       function in nfsd_port.c
479ec7b004SRick Macklem  *   3 - build the rpc reply in an mbuf list
489ec7b004SRick Macklem  * For nfsv4, these functions are called for each Op within the Compound RPC.
499ec7b004SRick Macklem  */
509ec7b004SRick Macklem 
519ec7b004SRick Macklem #ifndef APPLEKEXT
529ec7b004SRick Macklem #include <fs/nfs/nfsport.h>
539ec7b004SRick Macklem 
549ec7b004SRick Macklem /* Global vars */
559ec7b004SRick Macklem extern u_int32_t newnfs_false, newnfs_true;
569ec7b004SRick Macklem extern enum vtype nv34tov_type[8];
579ec7b004SRick Macklem extern struct timeval nfsboottime;
58c9aad40fSRick Macklem extern int nfs_rootfhset;
5907c0c166SRick Macklem extern int nfsrv_enable_crossmntpt;
601f54e596SRick Macklem extern int nfsrv_statehashsize;
6190d2dfabSRick Macklem extern int nfsrv_layouthashsize;
6290d2dfabSRick Macklem extern time_t nfsdev_time;
6390d2dfabSRick Macklem extern volatile int nfsrv_devidcnt;
6490d2dfabSRick Macklem extern int nfsd_debuglevel;
6590d2dfabSRick Macklem extern u_long sb_max_adj;
6690d2dfabSRick Macklem extern int nfsrv_pnfsatime;
6790d2dfabSRick Macklem extern int nfsrv_maxpnfsmirror;
689ec7b004SRick Macklem #endif	/* !APPLEKEXT */
699ec7b004SRick Macklem 
70e4558aacSXin LI static int	nfs_async = 0;
71e4558aacSXin LI SYSCTL_DECL(_vfs_nfsd);
72e4558aacSXin LI SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
73e4558aacSXin LI     "Tell client that writes were synced even though they were not");
7490d2dfabSRick Macklem extern int	nfsrv_doflexfile;
7590d2dfabSRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
7690d2dfabSRick Macklem     &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
77e4558aacSXin LI 
789ec7b004SRick Macklem /*
799ec7b004SRick Macklem  * This list defines the GSS mechanisms supported.
809ec7b004SRick Macklem  * (Don't ask me how you get these strings from the RFC stuff like
819ec7b004SRick Macklem  *  iso(1), org(3)... but someone did it, so I don't need to know.)
829ec7b004SRick Macklem  */
839ec7b004SRick Macklem static struct nfsgss_mechlist nfsgss_mechlist[] = {
849ec7b004SRick Macklem 	{ 9, "\052\206\110\206\367\022\001\002\002", 11 },
859ec7b004SRick Macklem 	{ 0, "", 0 },
869ec7b004SRick Macklem };
879ec7b004SRick Macklem 
889ec7b004SRick Macklem /* local functions */
899ec7b004SRick Macklem static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
909ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
919ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
929ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp,
939ec7b004SRick Macklem     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
949ec7b004SRick Macklem     int pathlen);
959ec7b004SRick Macklem static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
969ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
979ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
989ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
999ec7b004SRick Macklem     NFSPROC_T *p, struct nfsexstuff *exp);
1009ec7b004SRick Macklem 
1019ec7b004SRick Macklem /*
1029ec7b004SRick Macklem  * nfs access service (not a part of NFS V2)
1039ec7b004SRick Macklem  */
1049ec7b004SRick Macklem APPLESTATIC int
1059ec7b004SRick Macklem nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
106af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
1079ec7b004SRick Macklem {
1089ec7b004SRick Macklem 	u_int32_t *tl;
1099ec7b004SRick Macklem 	int getret, error = 0;
1109ec7b004SRick Macklem 	struct nfsvattr nva;
1119ec7b004SRick Macklem 	u_int32_t testmode, nfsmode, supported = 0;
1128da45f2cSRick Macklem 	accmode_t deletebit;
113af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
1149ec7b004SRick Macklem 
1159ec7b004SRick Macklem 	if (nd->nd_repstat) {
1169ec7b004SRick Macklem 		nfsrv_postopattr(nd, 1, &nva);
117a9285ae5SZack Kirsch 		goto out;
1189ec7b004SRick Macklem 	}
1199ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1209ec7b004SRick Macklem 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
1219ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) &&
1229ec7b004SRick Macklem 	    (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
1239ec7b004SRick Macklem 	     NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
1249ec7b004SRick Macklem 	     NFSACCESS_EXECUTE))) {
1259ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
1269ec7b004SRick Macklem 		vput(vp);
127a9285ae5SZack Kirsch 		goto out;
1289ec7b004SRick Macklem 	}
1299ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_READ) {
1309ec7b004SRick Macklem 		supported |= NFSACCESS_READ;
1318da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
1328da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1339ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_READ;
1349ec7b004SRick Macklem 	}
1359ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_MODIFY) {
1369ec7b004SRick Macklem 		supported |= NFSACCESS_MODIFY;
1378da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
1388da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1399ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_MODIFY;
1409ec7b004SRick Macklem 	}
1419ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_EXTEND) {
1429ec7b004SRick Macklem 		supported |= NFSACCESS_EXTEND;
1438da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
1448da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1459ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_EXTEND;
1469ec7b004SRick Macklem 	}
1479ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_DELETE) {
1489ec7b004SRick Macklem 		supported |= NFSACCESS_DELETE;
1498da45f2cSRick Macklem 		if (vp->v_type == VDIR)
1508da45f2cSRick Macklem 			deletebit = VDELETE_CHILD;
1518da45f2cSRick Macklem 		else
1528da45f2cSRick Macklem 			deletebit = VDELETE;
1538da45f2cSRick Macklem 		if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
1548da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1559ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_DELETE;
1569ec7b004SRick Macklem 	}
1579ec7b004SRick Macklem 	if (vnode_vtype(vp) == VDIR)
1589ec7b004SRick Macklem 		testmode = NFSACCESS_LOOKUP;
1599ec7b004SRick Macklem 	else
1609ec7b004SRick Macklem 		testmode = NFSACCESS_EXECUTE;
1619ec7b004SRick Macklem 	if (nfsmode & testmode) {
1629ec7b004SRick Macklem 		supported |= (nfsmode & testmode);
1638da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
1648da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1659ec7b004SRick Macklem 			nfsmode &= ~testmode;
1669ec7b004SRick Macklem 	}
1679ec7b004SRick Macklem 	nfsmode &= supported;
1689ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
16990d2dfabSRick Macklem 		getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1709ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
1719ec7b004SRick Macklem 	}
1729ec7b004SRick Macklem 	vput(vp);
1739ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
1749ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1759ec7b004SRick Macklem 		*tl++ = txdr_unsigned(supported);
1769ec7b004SRick Macklem 	} else
1779ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1789ec7b004SRick Macklem 	*tl = txdr_unsigned(nfsmode);
179a9285ae5SZack Kirsch 
180a9285ae5SZack Kirsch out:
181a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
1829ec7b004SRick Macklem 	return (0);
1839ec7b004SRick Macklem nfsmout:
1849ec7b004SRick Macklem 	vput(vp);
185a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1869ec7b004SRick Macklem 	return (error);
1879ec7b004SRick Macklem }
1889ec7b004SRick Macklem 
1899ec7b004SRick Macklem /*
1909ec7b004SRick Macklem  * nfs getattr service
1919ec7b004SRick Macklem  */
1929ec7b004SRick Macklem APPLESTATIC int
1939ec7b004SRick Macklem nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
194af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
1959ec7b004SRick Macklem {
1969ec7b004SRick Macklem 	struct nfsvattr nva;
1979ec7b004SRick Macklem 	fhandle_t fh;
198a09001a8SRick Macklem 	int at_root = 0, error = 0, supports_nfsv4acls;
1999ec7b004SRick Macklem 	struct nfsreferral *refp;
20053f476caSRick Macklem 	nfsattrbit_t attrbits, tmpbits;
20107c0c166SRick Macklem 	struct mount *mp;
20207c0c166SRick Macklem 	struct vnode *tvp = NULL;
20307c0c166SRick Macklem 	struct vattr va;
20407c0c166SRick Macklem 	uint64_t mounted_on_fileno = 0;
20553f476caSRick Macklem 	accmode_t accmode;
206af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
2079ec7b004SRick Macklem 
2089ec7b004SRick Macklem 	if (nd->nd_repstat)
209a9285ae5SZack Kirsch 		goto out;
2109ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
2119ec7b004SRick Macklem 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2129ec7b004SRick Macklem 		if (error) {
2139ec7b004SRick Macklem 			vput(vp);
214a9285ae5SZack Kirsch 			goto out;
2159ec7b004SRick Macklem 		}
2169ec7b004SRick Macklem 
2179ec7b004SRick Macklem 		/*
2189ec7b004SRick Macklem 		 * Check for a referral.
2199ec7b004SRick Macklem 		 */
2209ec7b004SRick Macklem 		refp = nfsv4root_getreferral(vp, NULL, 0);
2219ec7b004SRick Macklem 		if (refp != NULL) {
2229ec7b004SRick Macklem 			(void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
2239ec7b004SRick Macklem 			    &nd->nd_repstat);
2249ec7b004SRick Macklem 			vput(vp);
225a9285ae5SZack Kirsch 			goto out;
2269ec7b004SRick Macklem 		}
22753f476caSRick Macklem 		if (nd->nd_repstat == 0) {
22853f476caSRick Macklem 			accmode = 0;
22953f476caSRick Macklem 			NFSSET_ATTRBIT(&tmpbits, &attrbits);
230d8a5961fSMarcelo Araujo 
231d8a5961fSMarcelo Araujo 			/*
232d8a5961fSMarcelo Araujo 			 * GETATTR with write-only attr time_access_set and time_modify_set
233d8a5961fSMarcelo Araujo 			 * should return NFS4ERR_INVAL.
234d8a5961fSMarcelo Araujo 			 */
235d8a5961fSMarcelo Araujo 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
236d8a5961fSMarcelo Araujo 					NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
237d8a5961fSMarcelo Araujo 				error = NFSERR_INVAL;
238d8a5961fSMarcelo Araujo 				vput(vp);
239d8a5961fSMarcelo Araujo 				goto out;
240d8a5961fSMarcelo Araujo 			}
24153f476caSRick Macklem 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
24253f476caSRick Macklem 				NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
24353f476caSRick Macklem 				accmode |= VREAD_ACL;
24453f476caSRick Macklem 			}
24553f476caSRick Macklem 			if (NFSNONZERO_ATTRBIT(&tmpbits))
24653f476caSRick Macklem 				accmode |= VREAD_ATTRIBUTES;
24753f476caSRick Macklem 			if (accmode != 0)
24853f476caSRick Macklem 				nd->nd_repstat = nfsvno_accchk(vp, accmode,
2498da45f2cSRick Macklem 				    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
2508da45f2cSRick Macklem 				    NFSACCCHK_VPISLOCKED, NULL);
2519ec7b004SRick Macklem 		}
25253f476caSRick Macklem 	}
2539ec7b004SRick Macklem 	if (!nd->nd_repstat)
25490d2dfabSRick Macklem 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
2559ec7b004SRick Macklem 	if (!nd->nd_repstat) {
2569ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
2579ec7b004SRick Macklem 			if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
2589ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2599ec7b004SRick Macklem 			if (!nd->nd_repstat)
2609ec7b004SRick Macklem 				nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
26190d2dfabSRick Macklem 				    &nva, &attrbits, p);
26207c0c166SRick Macklem 			if (nd->nd_repstat == 0) {
263a09001a8SRick Macklem 				supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
26407c0c166SRick Macklem 				mp = vp->v_mount;
26507c0c166SRick Macklem 				if (nfsrv_enable_crossmntpt != 0 &&
26607c0c166SRick Macklem 				    vp->v_type == VDIR &&
26707c0c166SRick Macklem 				    (vp->v_vflag & VV_ROOT) != 0 &&
26807c0c166SRick Macklem 				    vp != rootvnode) {
26907c0c166SRick Macklem 					tvp = mp->mnt_vnodecovered;
27007c0c166SRick Macklem 					VREF(tvp);
27107c0c166SRick Macklem 					at_root = 1;
27207c0c166SRick Macklem 				} else
27307c0c166SRick Macklem 					at_root = 0;
27407c0c166SRick Macklem 				vfs_ref(mp);
275a9989634SZack Kirsch 				NFSVOPUNLOCK(vp, 0);
27607c0c166SRick Macklem 				if (at_root != 0) {
27707c0c166SRick Macklem 					if ((nd->nd_repstat =
27898f234f3SZack Kirsch 					     NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
27907c0c166SRick Macklem 						nd->nd_repstat = VOP_GETATTR(
28007c0c166SRick Macklem 						    tvp, &va, nd->nd_cred);
28107c0c166SRick Macklem 						vput(tvp);
28207c0c166SRick Macklem 					} else
28307c0c166SRick Macklem 						vrele(tvp);
28407c0c166SRick Macklem 					if (nd->nd_repstat == 0)
28507c0c166SRick Macklem 						mounted_on_fileno = (uint64_t)
28607c0c166SRick Macklem 						    va.va_fileid;
28707c0c166SRick Macklem 					else
28807c0c166SRick Macklem 						at_root = 0;
28907c0c166SRick Macklem 				}
29007c0c166SRick Macklem 				if (nd->nd_repstat == 0)
29107c0c166SRick Macklem 					nd->nd_repstat = vfs_busy(mp, 0);
29207c0c166SRick Macklem 				vfs_rel(mp);
29307c0c166SRick Macklem 				if (nd->nd_repstat == 0) {
29407c0c166SRick Macklem 					(void)nfsvno_fillattr(nd, mp, vp, &nva,
29507c0c166SRick Macklem 					    &fh, 0, &attrbits, nd->nd_cred, p,
296a09001a8SRick Macklem 					    isdgram, 1, supports_nfsv4acls,
297a09001a8SRick Macklem 					    at_root, mounted_on_fileno);
29807c0c166SRick Macklem 					vfs_unbusy(mp);
29907c0c166SRick Macklem 				}
3009ec7b004SRick Macklem 				vrele(vp);
30107c0c166SRick Macklem 			} else
30207c0c166SRick Macklem 				vput(vp);
3039ec7b004SRick Macklem 		} else {
3049ec7b004SRick Macklem 			nfsrv_fillattr(nd, &nva);
3059ec7b004SRick Macklem 			vput(vp);
3069ec7b004SRick Macklem 		}
3079ec7b004SRick Macklem 	} else {
3089ec7b004SRick Macklem 		vput(vp);
3099ec7b004SRick Macklem 	}
310a9285ae5SZack Kirsch 
311a9285ae5SZack Kirsch out:
312a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
313a9285ae5SZack Kirsch 	return (error);
3149ec7b004SRick Macklem }
3159ec7b004SRick Macklem 
3169ec7b004SRick Macklem /*
3179ec7b004SRick Macklem  * nfs setattr service
3189ec7b004SRick Macklem  */
3199ec7b004SRick Macklem APPLESTATIC int
3209ec7b004SRick Macklem nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
321af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
3229ec7b004SRick Macklem {
3239ec7b004SRick Macklem 	struct nfsvattr nva, nva2;
3249ec7b004SRick Macklem 	u_int32_t *tl;
3259ec7b004SRick Macklem 	int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
32690d2dfabSRick Macklem 	int gotproxystateid;
3279ec7b004SRick Macklem 	struct timespec guard = { 0, 0 };
3289ec7b004SRick Macklem 	nfsattrbit_t attrbits, retbits;
3299ec7b004SRick Macklem 	nfsv4stateid_t stateid;
3309ec7b004SRick Macklem 	NFSACL_T *aclp = NULL;
331af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
3329ec7b004SRick Macklem 
3339ec7b004SRick Macklem 	if (nd->nd_repstat) {
3349ec7b004SRick Macklem 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
335a9285ae5SZack Kirsch 		goto out;
3369ec7b004SRick Macklem 	}
3379ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
338c3e22f83SRick Macklem 	aclp = acl_alloc(M_WAITOK);
3399ec7b004SRick Macklem 	aclp->acl_cnt = 0;
3409ec7b004SRick Macklem #endif
34190d2dfabSRick Macklem 	gotproxystateid = 0;
3429ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
3439ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
3449ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3459ec7b004SRick Macklem 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
34690d2dfabSRick Macklem 		stateid.other[0] = *tl++;
34790d2dfabSRick Macklem 		stateid.other[1] = *tl++;
34890d2dfabSRick Macklem 		stateid.other[2] = *tl;
34990d2dfabSRick Macklem 		if (stateid.other[0] == 0x55555555 &&
35090d2dfabSRick Macklem 		    stateid.other[1] == 0x55555555 &&
35190d2dfabSRick Macklem 		    stateid.other[2] == 0x55555555 &&
35290d2dfabSRick Macklem 		    stateid.seqid == 0xffffffff)
35390d2dfabSRick Macklem 			gotproxystateid = 1;
3549ec7b004SRick Macklem 	}
355d8a5961fSMarcelo Araujo 	error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
3569ec7b004SRick Macklem 	if (error)
3579ec7b004SRick Macklem 		goto nfsmout;
35890d2dfabSRick Macklem 
35990d2dfabSRick Macklem 	/* For NFSv4, only va_uid is used from nva2. */
36090d2dfabSRick Macklem 	NFSZERO_ATTRBIT(&retbits);
36190d2dfabSRick Macklem 	NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
36290d2dfabSRick Macklem 	preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
3639ec7b004SRick Macklem 	if (!nd->nd_repstat)
3649ec7b004SRick Macklem 		nd->nd_repstat = preat_ret;
36590d2dfabSRick Macklem 
36690d2dfabSRick Macklem 	NFSZERO_ATTRBIT(&retbits);
3679ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
3689ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3699ec7b004SRick Macklem 		gcheck = fxdr_unsigned(int, *tl);
3709ec7b004SRick Macklem 		if (gcheck) {
3719ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3729ec7b004SRick Macklem 			fxdr_nfsv3time(tl, &guard);
3739ec7b004SRick Macklem 		}
3749ec7b004SRick Macklem 		if (!nd->nd_repstat && gcheck &&
3759ec7b004SRick Macklem 		    (nva2.na_ctime.tv_sec != guard.tv_sec ||
3769ec7b004SRick Macklem 		     nva2.na_ctime.tv_nsec != guard.tv_nsec))
3779ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_NOT_SYNC;
3789ec7b004SRick Macklem 		if (nd->nd_repstat) {
3799ec7b004SRick Macklem 			vput(vp);
3809ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
3819ec7b004SRick Macklem 			acl_free(aclp);
3829ec7b004SRick Macklem #endif
3839ec7b004SRick Macklem 			nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
384a9285ae5SZack Kirsch 			goto out;
3859ec7b004SRick Macklem 		}
3869ec7b004SRick Macklem 	} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
3879ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
3889ec7b004SRick Macklem 
3899ec7b004SRick Macklem 	/*
3909ec7b004SRick Macklem 	 * Now that we have all the fields, lets do it.
3919ec7b004SRick Macklem 	 * If the size is being changed write access is required, otherwise
3929ec7b004SRick Macklem 	 * just check for a read only file system.
3939ec7b004SRick Macklem 	 */
3949ec7b004SRick Macklem 	if (!nd->nd_repstat) {
3959ec7b004SRick Macklem 		if (NFSVNO_NOTSETSIZE(&nva)) {
3969ec7b004SRick Macklem 			if (NFSVNO_EXRDONLY(exp) ||
3979ec7b004SRick Macklem 			    (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
3989ec7b004SRick Macklem 				nd->nd_repstat = EROFS;
3999ec7b004SRick Macklem 		} else {
4009ec7b004SRick Macklem 			if (vnode_vtype(vp) != VREG)
4019ec7b004SRick Macklem 				nd->nd_repstat = EINVAL;
4029ec7b004SRick Macklem 			else if (nva2.na_uid != nd->nd_cred->cr_uid ||
4039ec7b004SRick Macklem 			    NFSVNO_EXSTRICTACCESS(exp))
4049ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_accchk(vp,
4058da45f2cSRick Macklem 				    VWRITE, nd->nd_cred, exp, p,
4068da45f2cSRick Macklem 				    NFSACCCHK_NOOVERRIDE,
4078da45f2cSRick Macklem 				    NFSACCCHK_VPISLOCKED, NULL);
4089ec7b004SRick Macklem 		}
4099ec7b004SRick Macklem 	}
41090d2dfabSRick Macklem 	/*
41190d2dfabSRick Macklem 	 * Proxy operations from the MDS are allowed via the all 0s special
41290d2dfabSRick Macklem 	 * stateid.
41390d2dfabSRick Macklem 	 */
41490d2dfabSRick Macklem 	if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
41590d2dfabSRick Macklem 	    gotproxystateid == 0)
4169ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
4179ec7b004SRick Macklem 		    &nva, &attrbits, exp, p);
4189ec7b004SRick Macklem 
4199ec7b004SRick Macklem 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
4209ec7b004SRick Macklem 	    /*
4219ec7b004SRick Macklem 	     * For V4, try setting the attrbutes in sets, so that the
4229ec7b004SRick Macklem 	     * reply bitmap will be correct for an error case.
4239ec7b004SRick Macklem 	     */
4249ec7b004SRick Macklem 	    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
4259ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
4269ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
4279ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
4289ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
4299ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4309ec7b004SRick Macklem 		    exp);
4319ec7b004SRick Macklem 		if (!nd->nd_repstat) {
4329ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
4339ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
4349ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
4359ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
4369ec7b004SRick Macklem 		}
4379ec7b004SRick Macklem 	    }
4389ec7b004SRick Macklem 	    if (!nd->nd_repstat &&
4399ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
4409ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
4419ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
4429ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4439ec7b004SRick Macklem 		    exp);
4449ec7b004SRick Macklem 		if (!nd->nd_repstat)
4459ec7b004SRick Macklem 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
4469ec7b004SRick Macklem 	    }
4479ec7b004SRick Macklem 	    if (!nd->nd_repstat &&
4489ec7b004SRick Macklem 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
4499ec7b004SRick Macklem 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
4509ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
4519ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
4529ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
4539ec7b004SRick Macklem 		if (nva.na_vaflags & VA_UTIMES_NULL) {
4549ec7b004SRick Macklem 			nva2.na_vaflags |= VA_UTIMES_NULL;
4559ec7b004SRick Macklem 			NFSVNO_SETACTIVE(&nva2, vaflags);
4569ec7b004SRick Macklem 		}
4579ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4589ec7b004SRick Macklem 		    exp);
4599ec7b004SRick Macklem 		if (!nd->nd_repstat) {
4609ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
4619ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
4629ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
4639ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
4649ec7b004SRick Macklem 		}
4659ec7b004SRick Macklem 	    }
4669ec7b004SRick Macklem 	    if (!nd->nd_repstat &&
4679ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
4689ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
4699ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
4709ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4719ec7b004SRick Macklem 		    exp);
4729ec7b004SRick Macklem 		if (!nd->nd_repstat)
4739ec7b004SRick Macklem 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
4749ec7b004SRick Macklem 	    }
4759ec7b004SRick Macklem 
4769ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
4779ec7b004SRick Macklem 	    if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
4789ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
4799ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
4809ec7b004SRick Macklem 		if (!nd->nd_repstat)
4819ec7b004SRick Macklem 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
4829ec7b004SRick Macklem 	    }
4839ec7b004SRick Macklem #endif
4849ec7b004SRick Macklem 	} else if (!nd->nd_repstat) {
4859ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
4869ec7b004SRick Macklem 		    exp);
4879ec7b004SRick Macklem 	}
4889ec7b004SRick Macklem 	if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
48990d2dfabSRick Macklem 		postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
4909ec7b004SRick Macklem 		if (!nd->nd_repstat)
4919ec7b004SRick Macklem 			nd->nd_repstat = postat_ret;
4929ec7b004SRick Macklem 	}
4939ec7b004SRick Macklem 	vput(vp);
4949ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
4959ec7b004SRick Macklem 	acl_free(aclp);
4969ec7b004SRick Macklem #endif
4979ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
4989ec7b004SRick Macklem 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
4999ec7b004SRick Macklem 	else if (nd->nd_flag & ND_NFSV4)
5009ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, &retbits);
5019ec7b004SRick Macklem 	else if (!nd->nd_repstat)
5029ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
503a9285ae5SZack Kirsch 
504a9285ae5SZack Kirsch out:
505a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
5069ec7b004SRick Macklem 	return (0);
5079ec7b004SRick Macklem nfsmout:
5089ec7b004SRick Macklem 	vput(vp);
5099ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
5109ec7b004SRick Macklem 	acl_free(aclp);
5119ec7b004SRick Macklem #endif
5129ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
5139ec7b004SRick Macklem 		/*
5149ec7b004SRick Macklem 		 * For all nd_repstat, the V4 reply includes a bitmap,
5159ec7b004SRick Macklem 		 * even NFSERR_BADXDR, which is what this will end up
5169ec7b004SRick Macklem 		 * returning.
5179ec7b004SRick Macklem 		 */
5189ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, &retbits);
5199ec7b004SRick Macklem 	}
520a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
5219ec7b004SRick Macklem 	return (error);
5229ec7b004SRick Macklem }
5239ec7b004SRick Macklem 
5249ec7b004SRick Macklem /*
5259ec7b004SRick Macklem  * nfs lookup rpc
5269ec7b004SRick Macklem  * (Also performs lookup parent for v4)
5279ec7b004SRick Macklem  */
5289ec7b004SRick Macklem APPLESTATIC int
5299ec7b004SRick Macklem nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
530af444b18SEdward Tomasz Napierala     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
5319ec7b004SRick Macklem {
5329ec7b004SRick Macklem 	struct nameidata named;
5339ec7b004SRick Macklem 	vnode_t vp, dirp = NULL;
534a9285ae5SZack Kirsch 	int error = 0, dattr_ret = 1;
5359ec7b004SRick Macklem 	struct nfsvattr nva, dattr;
5369ec7b004SRick Macklem 	char *bufp;
5379ec7b004SRick Macklem 	u_long *hashp;
538af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
5399ec7b004SRick Macklem 
5409ec7b004SRick Macklem 	if (nd->nd_repstat) {
5419ec7b004SRick Macklem 		nfsrv_postopattr(nd, dattr_ret, &dattr);
542a9285ae5SZack Kirsch 		goto out;
5439ec7b004SRick Macklem 	}
5449ec7b004SRick Macklem 
5459ec7b004SRick Macklem 	/*
5469ec7b004SRick Macklem 	 * For some reason, if dp is a symlink, the error
5479ec7b004SRick Macklem 	 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
5489ec7b004SRick Macklem 	 */
5499ec7b004SRick Macklem 	if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
5509ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_SYMLINK;
5519ec7b004SRick Macklem 		vrele(dp);
552a9285ae5SZack Kirsch 		goto out;
5539ec7b004SRick Macklem 	}
5549ec7b004SRick Macklem 
5559ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
5569ec7b004SRick Macklem 	    LOCKLEAF | SAVESTART);
5579ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
5589ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
5599ec7b004SRick Macklem 	if (error) {
5609ec7b004SRick Macklem 		vrele(dp);
5619ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
562a9285ae5SZack Kirsch 		goto out;
5639ec7b004SRick Macklem 	}
5649ec7b004SRick Macklem 	if (!nd->nd_repstat) {
5659ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
5669ec7b004SRick Macklem 	} else {
5679ec7b004SRick Macklem 		vrele(dp);
5689ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
5699ec7b004SRick Macklem 	}
5709ec7b004SRick Macklem 	if (nd->nd_repstat) {
5719ec7b004SRick Macklem 		if (dirp) {
5729ec7b004SRick Macklem 			if (nd->nd_flag & ND_NFSV3)
57390d2dfabSRick Macklem 				dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
57490d2dfabSRick Macklem 				    0, NULL);
5759ec7b004SRick Macklem 			vrele(dirp);
5769ec7b004SRick Macklem 		}
5779ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
5789ec7b004SRick Macklem 			nfsrv_postopattr(nd, dattr_ret, &dattr);
579a9285ae5SZack Kirsch 		goto out;
5809ec7b004SRick Macklem 	}
5819ec7b004SRick Macklem 	if (named.ni_startdir)
5829ec7b004SRick Macklem 		vrele(named.ni_startdir);
5839ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
5849ec7b004SRick Macklem 	vp = named.ni_vp;
58537b88c2dSRick Macklem 	if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
58637b88c2dSRick Macklem 	    vp->v_type != VDIR && vp->v_type != VLNK)
58737b88c2dSRick Macklem 		/*
58837b88c2dSRick Macklem 		 * Only allow lookup of VDIR and VLNK for traversal of
58937b88c2dSRick Macklem 		 * non-exported volumes during NFSv4 mounting.
59037b88c2dSRick Macklem 		 */
59137b88c2dSRick Macklem 		nd->nd_repstat = ENOENT;
59237b88c2dSRick Macklem 	if (nd->nd_repstat == 0)
5939ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
5949ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
59590d2dfabSRick Macklem 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
59681f78d99SRick Macklem 	if (vpp != NULL && nd->nd_repstat == 0)
5979ec7b004SRick Macklem 		*vpp = vp;
59881f78d99SRick Macklem 	else
5999ec7b004SRick Macklem 		vput(vp);
6009ec7b004SRick Macklem 	if (dirp) {
6019ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
60290d2dfabSRick Macklem 			dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
60390d2dfabSRick Macklem 			    NULL);
6049ec7b004SRick Macklem 		vrele(dirp);
6059ec7b004SRick Macklem 	}
6069ec7b004SRick Macklem 	if (nd->nd_repstat) {
6079ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
6089ec7b004SRick Macklem 			nfsrv_postopattr(nd, dattr_ret, &dattr);
609a9285ae5SZack Kirsch 		goto out;
6109ec7b004SRick Macklem 	}
6119ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
6129ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
6139ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
6149ec7b004SRick Macklem 	} else if (nd->nd_flag & ND_NFSV3) {
6159ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
6169ec7b004SRick Macklem 		nfsrv_postopattr(nd, 0, &nva);
6179ec7b004SRick Macklem 		nfsrv_postopattr(nd, dattr_ret, &dattr);
6189ec7b004SRick Macklem 	}
619a9285ae5SZack Kirsch 
620a9285ae5SZack Kirsch out:
621a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
622a9285ae5SZack Kirsch 	return (error);
6239ec7b004SRick Macklem }
6249ec7b004SRick Macklem 
6259ec7b004SRick Macklem /*
6269ec7b004SRick Macklem  * nfs readlink service
6279ec7b004SRick Macklem  */
6289ec7b004SRick Macklem APPLESTATIC int
6299ec7b004SRick Macklem nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
630af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
6319ec7b004SRick Macklem {
6329ec7b004SRick Macklem 	u_int32_t *tl;
6339ec7b004SRick Macklem 	mbuf_t mp = NULL, mpend = NULL;
6349ec7b004SRick Macklem 	int getret = 1, len;
6359ec7b004SRick Macklem 	struct nfsvattr nva;
636af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
6379ec7b004SRick Macklem 
6389ec7b004SRick Macklem 	if (nd->nd_repstat) {
6399ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
640a9285ae5SZack Kirsch 		goto out;
6419ec7b004SRick Macklem 	}
6429ec7b004SRick Macklem 	if (vnode_vtype(vp) != VLNK) {
6439ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2)
6449ec7b004SRick Macklem 			nd->nd_repstat = ENXIO;
6459ec7b004SRick Macklem 		else
6469ec7b004SRick Macklem 			nd->nd_repstat = EINVAL;
6479ec7b004SRick Macklem 	}
6489ec7b004SRick Macklem 	if (!nd->nd_repstat)
6499ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
6509ec7b004SRick Macklem 		    &mp, &mpend, &len);
6519ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
65290d2dfabSRick Macklem 		getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
6539ec7b004SRick Macklem 	vput(vp);
6549ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
6559ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
6569ec7b004SRick Macklem 	if (nd->nd_repstat)
657a9285ae5SZack Kirsch 		goto out;
6589ec7b004SRick Macklem 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6599ec7b004SRick Macklem 	*tl = txdr_unsigned(len);
6609ec7b004SRick Macklem 	mbuf_setnext(nd->nd_mb, mp);
6619ec7b004SRick Macklem 	nd->nd_mb = mpend;
6629ec7b004SRick Macklem 	nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
663a9285ae5SZack Kirsch 
664a9285ae5SZack Kirsch out:
665a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
6669ec7b004SRick Macklem 	return (0);
6679ec7b004SRick Macklem }
6689ec7b004SRick Macklem 
6699ec7b004SRick Macklem /*
6709ec7b004SRick Macklem  * nfs read service
6719ec7b004SRick Macklem  */
6729ec7b004SRick Macklem APPLESTATIC int
6739ec7b004SRick Macklem nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
674af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
6759ec7b004SRick Macklem {
6769ec7b004SRick Macklem 	u_int32_t *tl;
67790d2dfabSRick Macklem 	int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
6789ec7b004SRick Macklem 	mbuf_t m2, m3;
6799ec7b004SRick Macklem 	struct nfsvattr nva;
6809ec7b004SRick Macklem 	off_t off = 0x0;
6819ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
6829ec7b004SRick Macklem 	struct nfslock lo, *lop = &lo;
6839ec7b004SRick Macklem 	nfsv4stateid_t stateid;
6849ec7b004SRick Macklem 	nfsquad_t clientid;
685af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
6869ec7b004SRick Macklem 
6879ec7b004SRick Macklem 	if (nd->nd_repstat) {
6889ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
689a9285ae5SZack Kirsch 		goto out;
6909ec7b004SRick Macklem 	}
6919ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
6929ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6939ec7b004SRick Macklem 		off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
6949ec7b004SRick Macklem 		reqlen = fxdr_unsigned(int, *tl);
6959ec7b004SRick Macklem 	} else if (nd->nd_flag & ND_NFSV3) {
6969ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
6979ec7b004SRick Macklem 		off = fxdr_hyper(tl);
6989ec7b004SRick Macklem 		tl += 2;
6999ec7b004SRick Macklem 		reqlen = fxdr_unsigned(int, *tl);
7009ec7b004SRick Macklem 	} else {
7019ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
7029ec7b004SRick Macklem 		reqlen = fxdr_unsigned(int, *(tl + 6));
7039ec7b004SRick Macklem 	}
7049ec7b004SRick Macklem 	if (reqlen > NFS_SRVMAXDATA(nd)) {
7059ec7b004SRick Macklem 		reqlen = NFS_SRVMAXDATA(nd);
7069ec7b004SRick Macklem 	} else if (reqlen < 0) {
7079ec7b004SRick Macklem 		error = EBADRPC;
7089ec7b004SRick Macklem 		goto nfsmout;
7099ec7b004SRick Macklem 	}
71090d2dfabSRick Macklem 	gotproxystateid = 0;
7119ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
7129ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
7139ec7b004SRick Macklem 		lop->lo_flags = NFSLCK_READ;
7149ec7b004SRick Macklem 		stp->ls_ownerlen = 0;
7159ec7b004SRick Macklem 		stp->ls_op = NULL;
7169ec7b004SRick Macklem 		stp->ls_uid = nd->nd_cred->cr_uid;
7179ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
7189ec7b004SRick Macklem 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
7199ec7b004SRick Macklem 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
720c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
721c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
722c59e4cc3SRick Macklem 				clientid.qval = nd->nd_clientid.qval;
723c59e4cc3SRick Macklem 			else if (nd->nd_clientid.qval != clientid.qval)
724c59e4cc3SRick Macklem 				printf("EEK1 multiple clids\n");
7259ec7b004SRick Macklem 		} else {
726c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
727c59e4cc3SRick Macklem 				printf("EEK! no clientid from session\n");
7289ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
7299ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
7309ec7b004SRick Macklem 		}
7319ec7b004SRick Macklem 		stp->ls_stateid.other[2] = *tl++;
73290d2dfabSRick Macklem 		/*
73390d2dfabSRick Macklem 		 * Don't allow the client to use a special stateid for a DS op.
73490d2dfabSRick Macklem 		 */
73590d2dfabSRick Macklem 		if ((nd->nd_flag & ND_DSSERVER) != 0 &&
73690d2dfabSRick Macklem 		    ((stp->ls_stateid.other[0] == 0x0 &&
73790d2dfabSRick Macklem 		    stp->ls_stateid.other[1] == 0x0 &&
73890d2dfabSRick Macklem 		    stp->ls_stateid.other[2] == 0x0) ||
73990d2dfabSRick Macklem 		    (stp->ls_stateid.other[0] == 0xffffffff &&
74090d2dfabSRick Macklem 		    stp->ls_stateid.other[1] == 0xffffffff &&
74190d2dfabSRick Macklem 		    stp->ls_stateid.other[2] == 0xffffffff) ||
74290d2dfabSRick Macklem 		    stp->ls_stateid.seqid != 0))
74390d2dfabSRick Macklem 			nd->nd_repstat = NFSERR_BADSTATEID;
74490d2dfabSRick Macklem 		/* However, allow the proxy stateid. */
74590d2dfabSRick Macklem 		if (stp->ls_stateid.seqid == 0xffffffff &&
74690d2dfabSRick Macklem 		    stp->ls_stateid.other[0] == 0x55555555 &&
74790d2dfabSRick Macklem 		    stp->ls_stateid.other[1] == 0x55555555 &&
74890d2dfabSRick Macklem 		    stp->ls_stateid.other[2] == 0x55555555)
74990d2dfabSRick Macklem 			gotproxystateid = 1;
7509ec7b004SRick Macklem 		off = fxdr_hyper(tl);
7519ec7b004SRick Macklem 		lop->lo_first = off;
7529ec7b004SRick Macklem 		tl += 2;
7539ec7b004SRick Macklem 		lop->lo_end = off + reqlen;
7549ec7b004SRick Macklem 		/*
7559ec7b004SRick Macklem 		 * Paranoia, just in case it wraps around.
7569ec7b004SRick Macklem 		 */
7579ec7b004SRick Macklem 		if (lop->lo_end < off)
7589ec7b004SRick Macklem 			lop->lo_end = NFS64BITSSET;
7599ec7b004SRick Macklem 	}
7609ec7b004SRick Macklem 	if (vnode_vtype(vp) != VREG) {
7619ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
7629ec7b004SRick Macklem 			nd->nd_repstat = EINVAL;
7639ec7b004SRick Macklem 		else
7649ec7b004SRick Macklem 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
7659ec7b004SRick Macklem 			    EINVAL;
7669ec7b004SRick Macklem 	}
76790d2dfabSRick Macklem 	getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
7689ec7b004SRick Macklem 	if (!nd->nd_repstat)
7699ec7b004SRick Macklem 		nd->nd_repstat = getret;
7709ec7b004SRick Macklem 	if (!nd->nd_repstat &&
7719ec7b004SRick Macklem 	    (nva.na_uid != nd->nd_cred->cr_uid ||
7729ec7b004SRick Macklem 	     NFSVNO_EXSTRICTACCESS(exp))) {
7738da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
7749ec7b004SRick Macklem 		    nd->nd_cred, exp, p,
7758da45f2cSRick Macklem 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
7769ec7b004SRick Macklem 		if (nd->nd_repstat)
7778da45f2cSRick Macklem 			nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
7788da45f2cSRick Macklem 			    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
7798da45f2cSRick Macklem 			    NFSACCCHK_VPISLOCKED, NULL);
7809ec7b004SRick Macklem 	}
78190d2dfabSRick Macklem 	/*
78290d2dfabSRick Macklem 	 * DS reads are marked by ND_DSSERVER or use the proxy special
78390d2dfabSRick Macklem 	 * stateid.
78490d2dfabSRick Macklem 	 */
78590d2dfabSRick Macklem 	if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
78690d2dfabSRick Macklem 	    ND_NFSV4 && gotproxystateid == 0)
7879ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
7889ec7b004SRick Macklem 		    &stateid, exp, nd, p);
7899ec7b004SRick Macklem 	if (nd->nd_repstat) {
7909ec7b004SRick Macklem 		vput(vp);
7919ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
7929ec7b004SRick Macklem 			nfsrv_postopattr(nd, getret, &nva);
793a9285ae5SZack Kirsch 		goto out;
7949ec7b004SRick Macklem 	}
7959ec7b004SRick Macklem 	if (off >= nva.na_size) {
7969ec7b004SRick Macklem 		cnt = 0;
7979ec7b004SRick Macklem 		eof = 1;
7989ec7b004SRick Macklem 	} else if (reqlen == 0)
7999ec7b004SRick Macklem 		cnt = 0;
80006521fbbSZack Kirsch 	else if ((off + reqlen) >= nva.na_size) {
8019ec7b004SRick Macklem 		cnt = nva.na_size - off;
80206521fbbSZack Kirsch 		eof = 1;
80306521fbbSZack Kirsch 	} else
8049ec7b004SRick Macklem 		cnt = reqlen;
8059ec7b004SRick Macklem 	m3 = NULL;
8069ec7b004SRick Macklem 	if (cnt > 0) {
8079ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
8089ec7b004SRick Macklem 		    &m3, &m2);
8099ec7b004SRick Macklem 		if (!(nd->nd_flag & ND_NFSV4)) {
81090d2dfabSRick Macklem 			getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
8119ec7b004SRick Macklem 			if (!nd->nd_repstat)
8129ec7b004SRick Macklem 				nd->nd_repstat = getret;
8139ec7b004SRick Macklem 		}
8149ec7b004SRick Macklem 		if (nd->nd_repstat) {
8159ec7b004SRick Macklem 			vput(vp);
8169ec7b004SRick Macklem 			if (m3)
8179ec7b004SRick Macklem 				mbuf_freem(m3);
8189ec7b004SRick Macklem 			if (nd->nd_flag & ND_NFSV3)
8199ec7b004SRick Macklem 				nfsrv_postopattr(nd, getret, &nva);
820a9285ae5SZack Kirsch 			goto out;
8219ec7b004SRick Macklem 		}
8229ec7b004SRick Macklem 	}
8239ec7b004SRick Macklem 	vput(vp);
8249ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
8259ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
8269ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
8279ec7b004SRick Macklem 	} else {
8289ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
8299ec7b004SRick Macklem 			nfsrv_postopattr(nd, getret, &nva);
8309ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
8319ec7b004SRick Macklem 			*tl++ = txdr_unsigned(cnt);
8329ec7b004SRick Macklem 		} else
8339ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
83406521fbbSZack Kirsch 		if (eof)
8359ec7b004SRick Macklem 			*tl++ = newnfs_true;
8369ec7b004SRick Macklem 		else
8379ec7b004SRick Macklem 			*tl++ = newnfs_false;
8389ec7b004SRick Macklem 	}
8399ec7b004SRick Macklem 	*tl = txdr_unsigned(cnt);
8409ec7b004SRick Macklem 	if (m3) {
8419ec7b004SRick Macklem 		mbuf_setnext(nd->nd_mb, m3);
8429ec7b004SRick Macklem 		nd->nd_mb = m2;
8439ec7b004SRick Macklem 		nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
8449ec7b004SRick Macklem 	}
845a9285ae5SZack Kirsch 
846a9285ae5SZack Kirsch out:
847a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
8489ec7b004SRick Macklem 	return (0);
8499ec7b004SRick Macklem nfsmout:
8509ec7b004SRick Macklem 	vput(vp);
851a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
8529ec7b004SRick Macklem 	return (error);
8539ec7b004SRick Macklem }
8549ec7b004SRick Macklem 
8559ec7b004SRick Macklem /*
8569ec7b004SRick Macklem  * nfs write service
8579ec7b004SRick Macklem  */
8589ec7b004SRick Macklem APPLESTATIC int
8599ec7b004SRick Macklem nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
860af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
8619ec7b004SRick Macklem {
8629ec7b004SRick Macklem 	int i, cnt;
8639ec7b004SRick Macklem 	u_int32_t *tl;
8649ec7b004SRick Macklem 	mbuf_t mp;
8659ec7b004SRick Macklem 	struct nfsvattr nva, forat;
8669ec7b004SRick Macklem 	int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
86790d2dfabSRick Macklem 	int gotproxystateid, stable = NFSWRITE_FILESYNC;
8689ec7b004SRick Macklem 	off_t off;
8699ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
8709ec7b004SRick Macklem 	struct nfslock lo, *lop = &lo;
8719ec7b004SRick Macklem 	nfsv4stateid_t stateid;
8729ec7b004SRick Macklem 	nfsquad_t clientid;
87390d2dfabSRick Macklem 	nfsattrbit_t attrbits;
874af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
8759ec7b004SRick Macklem 
8769ec7b004SRick Macklem 	if (nd->nd_repstat) {
8779ec7b004SRick Macklem 		nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
878a9285ae5SZack Kirsch 		goto out;
8799ec7b004SRick Macklem 	}
88090d2dfabSRick Macklem 	gotproxystateid = 0;
8819ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
8829ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
8839ec7b004SRick Macklem 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
8849ec7b004SRick Macklem 		tl += 2;
8859ec7b004SRick Macklem 		retlen = len = fxdr_unsigned(int32_t, *tl);
8869ec7b004SRick Macklem 	} else if (nd->nd_flag & ND_NFSV3) {
8879ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
8889ec7b004SRick Macklem 		off = fxdr_hyper(tl);
8899ec7b004SRick Macklem 		tl += 3;
8909ec7b004SRick Macklem 		stable = fxdr_unsigned(int, *tl++);
8919ec7b004SRick Macklem 		retlen = len = fxdr_unsigned(int32_t, *tl);
8929ec7b004SRick Macklem 	} else {
8939ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
8949ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
8959ec7b004SRick Macklem 		lop->lo_flags = NFSLCK_WRITE;
8969ec7b004SRick Macklem 		stp->ls_ownerlen = 0;
8979ec7b004SRick Macklem 		stp->ls_op = NULL;
8989ec7b004SRick Macklem 		stp->ls_uid = nd->nd_cred->cr_uid;
8999ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
9009ec7b004SRick Macklem 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
9019ec7b004SRick Macklem 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
902c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
903c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
904c59e4cc3SRick Macklem 				clientid.qval = nd->nd_clientid.qval;
905c59e4cc3SRick Macklem 			else if (nd->nd_clientid.qval != clientid.qval)
906c59e4cc3SRick Macklem 				printf("EEK2 multiple clids\n");
9079ec7b004SRick Macklem 		} else {
908c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
909c59e4cc3SRick Macklem 				printf("EEK! no clientid from session\n");
9109ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
9119ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
9129ec7b004SRick Macklem 		}
9139ec7b004SRick Macklem 		stp->ls_stateid.other[2] = *tl++;
91490d2dfabSRick Macklem 		/*
91590d2dfabSRick Macklem 		 * Don't allow the client to use a special stateid for a DS op.
91690d2dfabSRick Macklem 		 */
91790d2dfabSRick Macklem 		if ((nd->nd_flag & ND_DSSERVER) != 0 &&
91890d2dfabSRick Macklem 		    ((stp->ls_stateid.other[0] == 0x0 &&
91990d2dfabSRick Macklem 		    stp->ls_stateid.other[1] == 0x0 &&
92090d2dfabSRick Macklem 		    stp->ls_stateid.other[2] == 0x0) ||
92190d2dfabSRick Macklem 		    (stp->ls_stateid.other[0] == 0xffffffff &&
92290d2dfabSRick Macklem 		    stp->ls_stateid.other[1] == 0xffffffff &&
92390d2dfabSRick Macklem 		    stp->ls_stateid.other[2] == 0xffffffff) ||
92490d2dfabSRick Macklem 		    stp->ls_stateid.seqid != 0))
92590d2dfabSRick Macklem 			nd->nd_repstat = NFSERR_BADSTATEID;
92690d2dfabSRick Macklem 		/* However, allow the proxy stateid. */
92790d2dfabSRick Macklem 		if (stp->ls_stateid.seqid == 0xffffffff &&
92890d2dfabSRick Macklem 		    stp->ls_stateid.other[0] == 0x55555555 &&
92990d2dfabSRick Macklem 		    stp->ls_stateid.other[1] == 0x55555555 &&
93090d2dfabSRick Macklem 		    stp->ls_stateid.other[2] == 0x55555555)
93190d2dfabSRick Macklem 			gotproxystateid = 1;
9329ec7b004SRick Macklem 		off = fxdr_hyper(tl);
9339ec7b004SRick Macklem 		lop->lo_first = off;
9349ec7b004SRick Macklem 		tl += 2;
9359ec7b004SRick Macklem 		stable = fxdr_unsigned(int, *tl++);
9369ec7b004SRick Macklem 		retlen = len = fxdr_unsigned(int32_t, *tl);
9379ec7b004SRick Macklem 		lop->lo_end = off + len;
9389ec7b004SRick Macklem 		/*
9399ec7b004SRick Macklem 		 * Paranoia, just in case it wraps around, which shouldn't
9409ec7b004SRick Macklem 		 * ever happen anyhow.
9419ec7b004SRick Macklem 		 */
9429ec7b004SRick Macklem 		if (lop->lo_end < lop->lo_first)
9439ec7b004SRick Macklem 			lop->lo_end = NFS64BITSSET;
9449ec7b004SRick Macklem 	}
9459ec7b004SRick Macklem 
9469ec7b004SRick Macklem 	/*
9479ec7b004SRick Macklem 	 * Loop through the mbuf chain, counting how many mbufs are a
9489ec7b004SRick Macklem 	 * part of this write operation, so the iovec size is known.
9499ec7b004SRick Macklem 	 */
9509ec7b004SRick Macklem 	cnt = 0;
9519ec7b004SRick Macklem 	mp = nd->nd_md;
9529ec7b004SRick Macklem 	i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
9539ec7b004SRick Macklem 	while (len > 0) {
9549ec7b004SRick Macklem 		if (i > 0) {
9559ec7b004SRick Macklem 			len -= i;
9569ec7b004SRick Macklem 			cnt++;
9579ec7b004SRick Macklem 		}
9589ec7b004SRick Macklem 		mp = mbuf_next(mp);
9599ec7b004SRick Macklem 		if (!mp) {
9609ec7b004SRick Macklem 			if (len > 0) {
9619ec7b004SRick Macklem 				error = EBADRPC;
9629ec7b004SRick Macklem 				goto nfsmout;
9639ec7b004SRick Macklem 			}
9649ec7b004SRick Macklem 		} else
9659ec7b004SRick Macklem 			i = mbuf_len(mp);
9669ec7b004SRick Macklem 	}
9679ec7b004SRick Macklem 
96866e80f77SRick Macklem 	if (retlen > NFS_SRVMAXIO || retlen < 0)
9699ec7b004SRick Macklem 		nd->nd_repstat = EIO;
9709ec7b004SRick Macklem 	if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
9719ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
9729ec7b004SRick Macklem 			nd->nd_repstat = EINVAL;
9739ec7b004SRick Macklem 		else
9749ec7b004SRick Macklem 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
9759ec7b004SRick Macklem 			    EINVAL;
9769ec7b004SRick Macklem 	}
97790d2dfabSRick Macklem 	NFSZERO_ATTRBIT(&attrbits);
97890d2dfabSRick Macklem 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
97990d2dfabSRick Macklem 	forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
9809ec7b004SRick Macklem 	if (!nd->nd_repstat)
9819ec7b004SRick Macklem 		nd->nd_repstat = forat_ret;
9829ec7b004SRick Macklem 	if (!nd->nd_repstat &&
9839ec7b004SRick Macklem 	    (forat.na_uid != nd->nd_cred->cr_uid ||
9849ec7b004SRick Macklem 	     NFSVNO_EXSTRICTACCESS(exp)))
9858da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
9869ec7b004SRick Macklem 		    nd->nd_cred, exp, p,
9878da45f2cSRick Macklem 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
98890d2dfabSRick Macklem 	/*
98990d2dfabSRick Macklem 	 * DS reads are marked by ND_DSSERVER or use the proxy special
99090d2dfabSRick Macklem 	 * stateid.
99190d2dfabSRick Macklem 	 */
99290d2dfabSRick Macklem 	if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
99390d2dfabSRick Macklem 	    ND_NFSV4 && gotproxystateid == 0)
9949ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
9959ec7b004SRick Macklem 		    &stateid, exp, nd, p);
9969ec7b004SRick Macklem 	if (nd->nd_repstat) {
9979ec7b004SRick Macklem 		vput(vp);
9989ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
9999ec7b004SRick Macklem 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1000a9285ae5SZack Kirsch 		goto out;
10019ec7b004SRick Macklem 	}
10029ec7b004SRick Macklem 
10039ec7b004SRick Macklem 	/*
10049ec7b004SRick Macklem 	 * For NFS Version 2, it is not obvious what a write of zero length
10059ec7b004SRick Macklem 	 * should do, but I might as well be consistent with Version 3,
10069ec7b004SRick Macklem 	 * which is to return ok so long as there are no permission problems.
10079ec7b004SRick Macklem 	 */
10089ec7b004SRick Macklem 	if (retlen > 0) {
100990d2dfabSRick Macklem 		nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, &stable,
10109ec7b004SRick Macklem 		    nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
10119ec7b004SRick Macklem 		error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
10129ec7b004SRick Macklem 		if (error)
1013ce8d06feSRick Macklem 			goto nfsmout;
10149ec7b004SRick Macklem 	}
10159ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4)
10169ec7b004SRick Macklem 		aftat_ret = 0;
10179ec7b004SRick Macklem 	else
101890d2dfabSRick Macklem 		aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
10199ec7b004SRick Macklem 	vput(vp);
10209ec7b004SRick Macklem 	if (!nd->nd_repstat)
10219ec7b004SRick Macklem 		nd->nd_repstat = aftat_ret;
10229ec7b004SRick Macklem 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
10239ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
10249ec7b004SRick Macklem 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
10259ec7b004SRick Macklem 		if (nd->nd_repstat)
1026a9285ae5SZack Kirsch 			goto out;
10279ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
10289ec7b004SRick Macklem 		*tl++ = txdr_unsigned(retlen);
1029e4558aacSXin LI 		/*
1030e4558aacSXin LI 		 * If nfs_async is set, then pretend the write was FILESYNC.
1031e4558aacSXin LI 		 * Warning: Doing this violates RFC1813 and runs a risk
1032e4558aacSXin LI 		 * of data written by a client being lost when the server
1033e4558aacSXin LI 		 * crashes/reboots.
1034e4558aacSXin LI 		 */
1035e4558aacSXin LI 		if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
10369ec7b004SRick Macklem 			*tl++ = txdr_unsigned(stable);
10379ec7b004SRick Macklem 		else
10389ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
10399ec7b004SRick Macklem 		/*
10409ec7b004SRick Macklem 		 * Actually, there is no need to txdr these fields,
10419ec7b004SRick Macklem 		 * but it may make the values more human readable,
10429ec7b004SRick Macklem 		 * for debugging purposes.
10439ec7b004SRick Macklem 		 */
10449ec7b004SRick Macklem 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
10459ec7b004SRick Macklem 		*tl = txdr_unsigned(nfsboottime.tv_usec);
10469ec7b004SRick Macklem 	} else if (!nd->nd_repstat)
10479ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
1048a9285ae5SZack Kirsch 
1049a9285ae5SZack Kirsch out:
1050a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
10519ec7b004SRick Macklem 	return (0);
10529ec7b004SRick Macklem nfsmout:
10539ec7b004SRick Macklem 	vput(vp);
1054a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
10559ec7b004SRick Macklem 	return (error);
10569ec7b004SRick Macklem }
10579ec7b004SRick Macklem 
10589ec7b004SRick Macklem /*
10599ec7b004SRick Macklem  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
10609ec7b004SRick Macklem  * now does a truncate to 0 length via. setattr if it already exists
10619ec7b004SRick Macklem  * The core creation routine has been extracted out into nfsrv_creatsub(),
10629ec7b004SRick Macklem  * so it can also be used by nfsrv_open() for V4.
10639ec7b004SRick Macklem  */
10649ec7b004SRick Macklem APPLESTATIC int
10659ec7b004SRick Macklem nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1066af444b18SEdward Tomasz Napierala     vnode_t dp, struct nfsexstuff *exp)
10679ec7b004SRick Macklem {
10689ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
10699ec7b004SRick Macklem 	struct nfsv2_sattr *sp;
10709ec7b004SRick Macklem 	struct nameidata named;
10719ec7b004SRick Macklem 	u_int32_t *tl;
10729ec7b004SRick Macklem 	int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
10739ec7b004SRick Macklem 	int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
10749ec7b004SRick Macklem 	NFSDEV_T rdev = 0;
10759ec7b004SRick Macklem 	vnode_t vp = NULL, dirp = NULL;
10769ec7b004SRick Macklem 	fhandle_t fh;
10779ec7b004SRick Macklem 	char *bufp;
10789ec7b004SRick Macklem 	u_long *hashp;
10799ec7b004SRick Macklem 	enum vtype vtyp;
1080086f6e0cSRick Macklem 	int32_t cverf[2], tverf[2] = { 0, 0 };
1081af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
10829ec7b004SRick Macklem 
10839ec7b004SRick Macklem 	if (nd->nd_repstat) {
10849ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1085a9285ae5SZack Kirsch 		goto out;
10869ec7b004SRick Macklem 	}
10879ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
10886c21f6edSKonstantin Belousov 	    LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
10899ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
10909ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1091a9285ae5SZack Kirsch 	if (error)
1092a9285ae5SZack Kirsch 		goto nfsmout;
10939ec7b004SRick Macklem 	if (!nd->nd_repstat) {
10949ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva);
10959ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2) {
10969ec7b004SRick Macklem 			NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
10979ec7b004SRick Macklem 			vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
10989ec7b004SRick Macklem 			if (vtyp == VNON)
10999ec7b004SRick Macklem 				vtyp = VREG;
11009ec7b004SRick Macklem 			NFSVNO_SETATTRVAL(&nva, type, vtyp);
11019ec7b004SRick Macklem 			NFSVNO_SETATTRVAL(&nva, mode,
11029ec7b004SRick Macklem 			    nfstov_mode(sp->sa_mode));
11039ec7b004SRick Macklem 			switch (nva.na_type) {
11049ec7b004SRick Macklem 			case VREG:
11059ec7b004SRick Macklem 				tsize = fxdr_unsigned(int32_t, sp->sa_size);
11069ec7b004SRick Macklem 				if (tsize != -1)
11079ec7b004SRick Macklem 					NFSVNO_SETATTRVAL(&nva, size,
11089ec7b004SRick Macklem 					    (u_quad_t)tsize);
11099ec7b004SRick Macklem 				break;
11109ec7b004SRick Macklem 			case VCHR:
11119ec7b004SRick Macklem 			case VBLK:
11129ec7b004SRick Macklem 			case VFIFO:
11139ec7b004SRick Macklem 				rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
11149ec7b004SRick Macklem 				break;
11159ec7b004SRick Macklem 			default:
11169ec7b004SRick Macklem 				break;
111774b8d63dSPedro F. Giffuni 			}
11189ec7b004SRick Macklem 		} else {
11199ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
11209ec7b004SRick Macklem 			how = fxdr_unsigned(int, *tl);
11219ec7b004SRick Macklem 			switch (how) {
11229ec7b004SRick Macklem 			case NFSCREATE_GUARDED:
11239ec7b004SRick Macklem 			case NFSCREATE_UNCHECKED:
1124d8a5961fSMarcelo Araujo 				error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
11259ec7b004SRick Macklem 				if (error)
11269ec7b004SRick Macklem 					goto nfsmout;
11279ec7b004SRick Macklem 				break;
11289ec7b004SRick Macklem 			case NFSCREATE_EXCLUSIVE:
1129086f6e0cSRick Macklem 				NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1130086f6e0cSRick Macklem 				cverf[0] = *tl++;
1131086f6e0cSRick Macklem 				cverf[1] = *tl;
11329ec7b004SRick Macklem 				exclusive_flag = 1;
11339ec7b004SRick Macklem 				break;
113474b8d63dSPedro F. Giffuni 			}
11359ec7b004SRick Macklem 			NFSVNO_SETATTRVAL(&nva, type, VREG);
11369ec7b004SRick Macklem 		}
11379ec7b004SRick Macklem 	}
11389ec7b004SRick Macklem 	if (nd->nd_repstat) {
11399ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
11409ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
114190d2dfabSRick Macklem 			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
114290d2dfabSRick Macklem 			    NULL);
11439ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
11449ec7b004SRick Macklem 			    &diraft);
11459ec7b004SRick Macklem 		}
11469ec7b004SRick Macklem 		vput(dp);
1147a9285ae5SZack Kirsch 		goto out;
11489ec7b004SRick Macklem 	}
11499ec7b004SRick Macklem 
11509ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
11519ec7b004SRick Macklem 	if (dirp) {
11529ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2) {
11539ec7b004SRick Macklem 			vrele(dirp);
11549ec7b004SRick Macklem 			dirp = NULL;
11559ec7b004SRick Macklem 		} else {
115690d2dfabSRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
115790d2dfabSRick Macklem 			    NULL);
11589ec7b004SRick Macklem 		}
11599ec7b004SRick Macklem 	}
11609ec7b004SRick Macklem 	if (nd->nd_repstat) {
11619ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
11629ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
11639ec7b004SRick Macklem 			    &diraft);
11649ec7b004SRick Macklem 		if (dirp)
11659ec7b004SRick Macklem 			vrele(dirp);
1166a9285ae5SZack Kirsch 		goto out;
11679ec7b004SRick Macklem 	}
11689ec7b004SRick Macklem 
11699ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV2)) {
11709ec7b004SRick Macklem 		switch (how) {
11719ec7b004SRick Macklem 		case NFSCREATE_GUARDED:
11729ec7b004SRick Macklem 			if (named.ni_vp)
11739ec7b004SRick Macklem 				nd->nd_repstat = EEXIST;
11749ec7b004SRick Macklem 			break;
11759ec7b004SRick Macklem 		case NFSCREATE_UNCHECKED:
11769ec7b004SRick Macklem 			break;
11779ec7b004SRick Macklem 		case NFSCREATE_EXCLUSIVE:
11789ec7b004SRick Macklem 			if (named.ni_vp == NULL)
11799ec7b004SRick Macklem 				NFSVNO_SETATTRVAL(&nva, mode, 0);
11809ec7b004SRick Macklem 			break;
118174b8d63dSPedro F. Giffuni 		}
11829ec7b004SRick Macklem 	}
11839ec7b004SRick Macklem 
11849ec7b004SRick Macklem 	/*
11859ec7b004SRick Macklem 	 * Iff doesn't exist, create it
11869ec7b004SRick Macklem 	 * otherwise just truncate to 0 length
11879ec7b004SRick Macklem 	 *   should I set the mode too ?
11889ec7b004SRick Macklem 	 */
11899ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1190127152feSEdward Tomasz Napierala 	    &exclusive_flag, cverf, rdev, exp);
11919ec7b004SRick Macklem 
11929ec7b004SRick Macklem 	if (!nd->nd_repstat) {
11939ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
11949ec7b004SRick Macklem 		if (!nd->nd_repstat)
119590d2dfabSRick Macklem 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
119690d2dfabSRick Macklem 			    NULL);
11979ec7b004SRick Macklem 		vput(vp);
1198086f6e0cSRick Macklem 		if (!nd->nd_repstat) {
1199086f6e0cSRick Macklem 			tverf[0] = nva.na_atime.tv_sec;
1200086f6e0cSRick Macklem 			tverf[1] = nva.na_atime.tv_nsec;
1201086f6e0cSRick Macklem 		}
12029ec7b004SRick Macklem 	}
12039ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
12049ec7b004SRick Macklem 		if (!nd->nd_repstat) {
12059ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
12069ec7b004SRick Macklem 			nfsrv_fillattr(nd, &nva);
12079ec7b004SRick Macklem 		}
12089ec7b004SRick Macklem 	} else {
1209086f6e0cSRick Macklem 		if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1210086f6e0cSRick Macklem 		    || cverf[1] != tverf[1]))
12119ec7b004SRick Macklem 			nd->nd_repstat = EEXIST;
121290d2dfabSRick Macklem 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
12139ec7b004SRick Macklem 		vrele(dirp);
12149ec7b004SRick Macklem 		if (!nd->nd_repstat) {
12159ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
12169ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
12179ec7b004SRick Macklem 		}
12189ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
12199ec7b004SRick Macklem 	}
1220a9285ae5SZack Kirsch 
1221a9285ae5SZack Kirsch out:
1222a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
12239ec7b004SRick Macklem 	return (0);
12249ec7b004SRick Macklem nfsmout:
12259ec7b004SRick Macklem 	vput(dp);
12269ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
1227a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
12289ec7b004SRick Macklem 	return (error);
12299ec7b004SRick Macklem }
12309ec7b004SRick Macklem 
12319ec7b004SRick Macklem /*
12329ec7b004SRick Macklem  * nfs v3 mknod service (and v4 create)
12339ec7b004SRick Macklem  */
12349ec7b004SRick Macklem APPLESTATIC int
12359ec7b004SRick Macklem nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1236af444b18SEdward Tomasz Napierala     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
12379ec7b004SRick Macklem {
12389ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
12399ec7b004SRick Macklem 	u_int32_t *tl;
12409ec7b004SRick Macklem 	struct nameidata named;
12419ec7b004SRick Macklem 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
12429ec7b004SRick Macklem 	u_int32_t major, minor;
12439ec7b004SRick Macklem 	enum vtype vtyp = VNON;
12449ec7b004SRick Macklem 	nfstype nfs4type = NFNON;
12459ec7b004SRick Macklem 	vnode_t vp, dirp = NULL;
12469ec7b004SRick Macklem 	nfsattrbit_t attrbits;
12479ec7b004SRick Macklem 	char *bufp = NULL, *pathcp = NULL;
12489ec7b004SRick Macklem 	u_long *hashp, cnflags;
12499ec7b004SRick Macklem 	NFSACL_T *aclp = NULL;
1250af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
12519ec7b004SRick Macklem 
12529ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
12539ec7b004SRick Macklem 	cnflags = (LOCKPARENT | SAVESTART);
12549ec7b004SRick Macklem 	if (nd->nd_repstat) {
12559ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1256a9285ae5SZack Kirsch 		goto out;
12579ec7b004SRick Macklem 	}
12589ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
1259c3e22f83SRick Macklem 	aclp = acl_alloc(M_WAITOK);
12609ec7b004SRick Macklem 	aclp->acl_cnt = 0;
12619ec7b004SRick Macklem #endif
12629ec7b004SRick Macklem 
12639ec7b004SRick Macklem 	/*
12649ec7b004SRick Macklem 	 * For V4, the creation stuff is here, Yuck!
12659ec7b004SRick Macklem 	 */
12669ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
12679ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
12689ec7b004SRick Macklem 		vtyp = nfsv34tov_type(*tl);
12699ec7b004SRick Macklem 		nfs4type = fxdr_unsigned(nfstype, *tl);
12709ec7b004SRick Macklem 		switch (nfs4type) {
12719ec7b004SRick Macklem 		case NFLNK:
12729ec7b004SRick Macklem 			error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
12739ec7b004SRick Macklem 			    &pathlen);
1274a9285ae5SZack Kirsch 			if (error)
1275a9285ae5SZack Kirsch 				goto nfsmout;
12769ec7b004SRick Macklem 			break;
12779ec7b004SRick Macklem 		case NFCHR:
12789ec7b004SRick Macklem 		case NFBLK:
12799ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
12809ec7b004SRick Macklem 			major = fxdr_unsigned(u_int32_t, *tl++);
12819ec7b004SRick Macklem 			minor = fxdr_unsigned(u_int32_t, *tl);
12829ec7b004SRick Macklem 			nva.na_rdev = NFSMAKEDEV(major, minor);
12839ec7b004SRick Macklem 			break;
12849ec7b004SRick Macklem 		case NFSOCK:
12859ec7b004SRick Macklem 		case NFFIFO:
12869ec7b004SRick Macklem 			break;
12879ec7b004SRick Macklem 		case NFDIR:
1288f61786cbSRick Macklem 			cnflags = (LOCKPARENT | SAVENAME);
12899ec7b004SRick Macklem 			break;
12909ec7b004SRick Macklem 		default:
12919ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_BADTYPE;
12929ec7b004SRick Macklem 			vrele(dp);
12939ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
12949ec7b004SRick Macklem 			acl_free(aclp);
12959ec7b004SRick Macklem #endif
1296a9285ae5SZack Kirsch 			goto out;
1297a9285ae5SZack Kirsch 		}
12989ec7b004SRick Macklem 	}
12996c21f6edSKonstantin Belousov 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
13009ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
13019ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1302a9285ae5SZack Kirsch 	if (error)
1303a9285ae5SZack Kirsch 		goto nfsmout;
13049ec7b004SRick Macklem 	if (!nd->nd_repstat) {
13059ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
13069ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
13079ec7b004SRick Macklem 			vtyp = nfsv34tov_type(*tl);
13089ec7b004SRick Macklem 		}
1309d8a5961fSMarcelo Araujo 		error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1310a9285ae5SZack Kirsch 		if (error)
1311a9285ae5SZack Kirsch 			goto nfsmout;
13129ec7b004SRick Macklem 		nva.na_type = vtyp;
13139ec7b004SRick Macklem 		if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
13149ec7b004SRick Macklem 		    (vtyp == VCHR || vtyp == VBLK)) {
13159ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
13169ec7b004SRick Macklem 			major = fxdr_unsigned(u_int32_t, *tl++);
13179ec7b004SRick Macklem 			minor = fxdr_unsigned(u_int32_t, *tl);
13189ec7b004SRick Macklem 			nva.na_rdev = NFSMAKEDEV(major, minor);
13199ec7b004SRick Macklem 		}
13209ec7b004SRick Macklem 	}
13219ec7b004SRick Macklem 
132290d2dfabSRick Macklem 	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
13239ec7b004SRick Macklem 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
13249ec7b004SRick Macklem 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
13259ec7b004SRick Macklem 		    dirfor.na_gid == nva.na_gid)
13269ec7b004SRick Macklem 			NFSVNO_UNSET(&nva, gid);
13279ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
13289ec7b004SRick Macklem 	}
13299ec7b004SRick Macklem 	if (nd->nd_repstat) {
13309ec7b004SRick Macklem 		vrele(dp);
13319ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
13329ec7b004SRick Macklem 		acl_free(aclp);
13339ec7b004SRick Macklem #endif
13349ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
13359ec7b004SRick Macklem 		if (pathcp)
1336222daa42SConrad Meyer 			free(pathcp, M_TEMP);
13379ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
13389ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
13399ec7b004SRick Macklem 			    &diraft);
1340a9285ae5SZack Kirsch 		goto out;
13419ec7b004SRick Macklem 	}
13429ec7b004SRick Macklem 
13439ec7b004SRick Macklem 	/*
13449ec7b004SRick Macklem 	 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
13459ec7b004SRick Macklem 	 * in va_mode, so we'll have to set a default here.
13469ec7b004SRick Macklem 	 */
13479ec7b004SRick Macklem 	if (NFSVNO_NOTSETMODE(&nva)) {
13489ec7b004SRick Macklem 		if (vtyp == VLNK)
13499ec7b004SRick Macklem 			nva.na_mode = 0755;
13509ec7b004SRick Macklem 		else
13519ec7b004SRick Macklem 			nva.na_mode = 0400;
13529ec7b004SRick Macklem 	}
13539ec7b004SRick Macklem 
13549ec7b004SRick Macklem 	if (vtyp == VDIR)
13559ec7b004SRick Macklem 		named.ni_cnd.cn_flags |= WILLBEDIR;
13569ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
13579ec7b004SRick Macklem 	if (nd->nd_repstat) {
13589ec7b004SRick Macklem 		if (dirp) {
13599ec7b004SRick Macklem 			if (nd->nd_flag & ND_NFSV3)
136090d2dfabSRick Macklem 				dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
136190d2dfabSRick Macklem 				    p, 0, NULL);
13629ec7b004SRick Macklem 			vrele(dirp);
13639ec7b004SRick Macklem 		}
13649ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
13659ec7b004SRick Macklem 		acl_free(aclp);
13669ec7b004SRick Macklem #endif
13679ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
13689ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
13699ec7b004SRick Macklem 			    &diraft);
1370a9285ae5SZack Kirsch 		goto out;
13719ec7b004SRick Macklem 	}
13729ec7b004SRick Macklem 	if (dirp)
137390d2dfabSRick Macklem 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
13749ec7b004SRick Macklem 
13759ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
13769ec7b004SRick Macklem 		if (vtyp == VDIR) {
13779ec7b004SRick Macklem 			nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
13789ec7b004SRick Macklem 			    &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
13799ec7b004SRick Macklem 			    exp);
13809ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
13819ec7b004SRick Macklem 			acl_free(aclp);
13829ec7b004SRick Macklem #endif
1383a9285ae5SZack Kirsch 			goto out;
13849ec7b004SRick Macklem 		} else if (vtyp == VLNK) {
13859ec7b004SRick Macklem 			nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
13869ec7b004SRick Macklem 			    &dirfor, &diraft, &diraft_ret, &attrbits,
13879ec7b004SRick Macklem 			    aclp, p, exp, pathcp, pathlen);
13889ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
13899ec7b004SRick Macklem 			acl_free(aclp);
13909ec7b004SRick Macklem #endif
1391222daa42SConrad Meyer 			free(pathcp, M_TEMP);
1392a9285ae5SZack Kirsch 			goto out;
13939ec7b004SRick Macklem 		}
13949ec7b004SRick Macklem 	}
13959ec7b004SRick Macklem 
13969ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
13979ec7b004SRick Macklem 	if (!nd->nd_repstat) {
13989ec7b004SRick Macklem 		vp = named.ni_vp;
13999ec7b004SRick Macklem 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
14009ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
14019ec7b004SRick Macklem 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
140290d2dfabSRick Macklem 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
140390d2dfabSRick Macklem 			    NULL);
140481f78d99SRick Macklem 		if (vpp != NULL && nd->nd_repstat == 0) {
1405a9989634SZack Kirsch 			NFSVOPUNLOCK(vp, 0);
14069ec7b004SRick Macklem 			*vpp = vp;
140781f78d99SRick Macklem 		} else
14089ec7b004SRick Macklem 			vput(vp);
14099ec7b004SRick Macklem 	}
14109ec7b004SRick Macklem 
141190d2dfabSRick Macklem 	diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
14129ec7b004SRick Macklem 	vrele(dirp);
14139ec7b004SRick Macklem 	if (!nd->nd_repstat) {
14149ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
14159ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
14169ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
14179ec7b004SRick Macklem 		} else {
14189ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
14199ec7b004SRick Macklem 			*tl++ = newnfs_false;
14209ec7b004SRick Macklem 			txdr_hyper(dirfor.na_filerev, tl);
14219ec7b004SRick Macklem 			tl += 2;
14229ec7b004SRick Macklem 			txdr_hyper(diraft.na_filerev, tl);
14239ec7b004SRick Macklem 			(void) nfsrv_putattrbit(nd, &attrbits);
14249ec7b004SRick Macklem 		}
14259ec7b004SRick Macklem 	}
14269ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
14279ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
14289ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
14299ec7b004SRick Macklem 	acl_free(aclp);
14309ec7b004SRick Macklem #endif
1431a9285ae5SZack Kirsch 
1432a9285ae5SZack Kirsch out:
1433a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
14349ec7b004SRick Macklem 	return (0);
14359ec7b004SRick Macklem nfsmout:
14369ec7b004SRick Macklem 	vrele(dp);
14379ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
14389ec7b004SRick Macklem 	acl_free(aclp);
14399ec7b004SRick Macklem #endif
14409ec7b004SRick Macklem 	if (bufp)
14419ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
14429ec7b004SRick Macklem 	if (pathcp)
1443222daa42SConrad Meyer 		free(pathcp, M_TEMP);
1444a9285ae5SZack Kirsch 
1445a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
14469ec7b004SRick Macklem 	return (error);
14479ec7b004SRick Macklem }
14489ec7b004SRick Macklem 
14499ec7b004SRick Macklem /*
14509ec7b004SRick Macklem  * nfs remove service
14519ec7b004SRick Macklem  */
14529ec7b004SRick Macklem APPLESTATIC int
14539ec7b004SRick Macklem nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1454af444b18SEdward Tomasz Napierala     vnode_t dp, struct nfsexstuff *exp)
14559ec7b004SRick Macklem {
14569ec7b004SRick Macklem 	struct nameidata named;
14579ec7b004SRick Macklem 	u_int32_t *tl;
1458a9285ae5SZack Kirsch 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
14599ec7b004SRick Macklem 	vnode_t dirp = NULL;
14609ec7b004SRick Macklem 	struct nfsvattr dirfor, diraft;
14619ec7b004SRick Macklem 	char *bufp;
14629ec7b004SRick Macklem 	u_long *hashp;
1463af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
14649ec7b004SRick Macklem 
14659ec7b004SRick Macklem 	if (nd->nd_repstat) {
14669ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1467a9285ae5SZack Kirsch 		goto out;
14689ec7b004SRick Macklem 	}
14699ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
14709ec7b004SRick Macklem 	    LOCKPARENT | LOCKLEAF);
14719ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
14729ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
14739ec7b004SRick Macklem 	if (error) {
14749ec7b004SRick Macklem 		vput(dp);
14759ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
1476a9285ae5SZack Kirsch 		goto out;
14779ec7b004SRick Macklem 	}
14789ec7b004SRick Macklem 	if (!nd->nd_repstat) {
14799ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
14809ec7b004SRick Macklem 	} else {
14819ec7b004SRick Macklem 		vput(dp);
14829ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
14839ec7b004SRick Macklem 	}
14849ec7b004SRick Macklem 	if (dirp) {
14859ec7b004SRick Macklem 		if (!(nd->nd_flag & ND_NFSV2)) {
148690d2dfabSRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
148790d2dfabSRick Macklem 			    NULL);
14889ec7b004SRick Macklem 		} else {
14899ec7b004SRick Macklem 			vrele(dirp);
14909ec7b004SRick Macklem 			dirp = NULL;
14919ec7b004SRick Macklem 		}
14929ec7b004SRick Macklem 	}
14939ec7b004SRick Macklem 	if (!nd->nd_repstat) {
14949ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
14959ec7b004SRick Macklem 			if (vnode_vtype(named.ni_vp) == VDIR)
14969ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
14979ec7b004SRick Macklem 				    nd->nd_cred, p, exp);
14989ec7b004SRick Macklem 			else
14999ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_removesub(&named, 1,
15009ec7b004SRick Macklem 				    nd->nd_cred, p, exp);
15019ec7b004SRick Macklem 		} else if (nd->nd_procnum == NFSPROC_RMDIR) {
15029ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
15039ec7b004SRick Macklem 			    nd->nd_cred, p, exp);
15049ec7b004SRick Macklem 		} else {
15059ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_removesub(&named, 0,
15069ec7b004SRick Macklem 			    nd->nd_cred, p, exp);
15079ec7b004SRick Macklem 		}
15089ec7b004SRick Macklem 	}
15099ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV2)) {
15109ec7b004SRick Macklem 		if (dirp) {
151190d2dfabSRick Macklem 			diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
151290d2dfabSRick Macklem 			    NULL);
15139ec7b004SRick Macklem 			vrele(dirp);
15149ec7b004SRick Macklem 		}
15159ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
15169ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
15179ec7b004SRick Macklem 			    &diraft);
15189ec7b004SRick Macklem 		} else if (!nd->nd_repstat) {
15199ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
15209ec7b004SRick Macklem 			*tl++ = newnfs_false;
15219ec7b004SRick Macklem 			txdr_hyper(dirfor.na_filerev, tl);
15229ec7b004SRick Macklem 			tl += 2;
15239ec7b004SRick Macklem 			txdr_hyper(diraft.na_filerev, tl);
15249ec7b004SRick Macklem 		}
15259ec7b004SRick Macklem 	}
1526a9285ae5SZack Kirsch 
1527a9285ae5SZack Kirsch out:
1528a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1529a9285ae5SZack Kirsch 	return (error);
15309ec7b004SRick Macklem }
15319ec7b004SRick Macklem 
15329ec7b004SRick Macklem /*
15339ec7b004SRick Macklem  * nfs rename service
15349ec7b004SRick Macklem  */
15359ec7b004SRick Macklem APPLESTATIC int
15369ec7b004SRick Macklem nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1537af444b18SEdward Tomasz Napierala     vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
15389ec7b004SRick Macklem {
15399ec7b004SRick Macklem 	u_int32_t *tl;
1540a9285ae5SZack Kirsch 	int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
15419ec7b004SRick Macklem 	int tdirfor_ret = 1, tdiraft_ret = 1;
15429ec7b004SRick Macklem 	struct nameidata fromnd, tond;
15439ec7b004SRick Macklem 	vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
15449ec7b004SRick Macklem 	struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
15459ec7b004SRick Macklem 	struct nfsexstuff tnes;
15469ec7b004SRick Macklem 	struct nfsrvfh tfh;
15479ec7b004SRick Macklem 	char *bufp, *tbufp = NULL;
15489ec7b004SRick Macklem 	u_long *hashp;
15496b3dfc6aSRick Macklem 	fhandle_t fh;
1550af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
15519ec7b004SRick Macklem 
15529ec7b004SRick Macklem 	if (nd->nd_repstat) {
15539ec7b004SRick Macklem 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
15549ec7b004SRick Macklem 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1555a9285ae5SZack Kirsch 		goto out;
15569ec7b004SRick Macklem 	}
15579ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV2))
155890d2dfabSRick Macklem 		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
15599ec7b004SRick Macklem 	tond.ni_cnd.cn_nameiop = 0;
15609ec7b004SRick Macklem 	tond.ni_startdir = NULL;
15619ec7b004SRick Macklem 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
15629ec7b004SRick Macklem 	nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
15639ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
15649ec7b004SRick Macklem 	if (error) {
15659ec7b004SRick Macklem 		vput(dp);
15669ec7b004SRick Macklem 		if (todp)
15679ec7b004SRick Macklem 			vrele(todp);
15689ec7b004SRick Macklem 		nfsvno_relpathbuf(&fromnd);
1569a9285ae5SZack Kirsch 		goto out;
15709ec7b004SRick Macklem 	}
157125bfde79SXin LI 	/*
157225bfde79SXin LI 	 * Unlock dp in this code section, so it is unlocked before
157325bfde79SXin LI 	 * tdp gets locked. This avoids a potential LOR if tdp is the
157425bfde79SXin LI 	 * parent directory of dp.
157525bfde79SXin LI 	 */
15769ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
15779ec7b004SRick Macklem 		tdp = todp;
15789ec7b004SRick Macklem 		tnes = *toexp;
157925bfde79SXin LI 		if (dp != tdp) {
158025bfde79SXin LI 			NFSVOPUNLOCK(dp, 0);
158190d2dfabSRick Macklem 			/* Might lock tdp. */
158290d2dfabSRick Macklem 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
158390d2dfabSRick Macklem 			    NULL);
158425bfde79SXin LI 		} else {
158590d2dfabSRick Macklem 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
158690d2dfabSRick Macklem 			    NULL);
158725bfde79SXin LI 			NFSVOPUNLOCK(dp, 0);
158825bfde79SXin LI 		}
15899ec7b004SRick Macklem 	} else {
15906b3dfc6aSRick Macklem 		tfh.nfsrvfh_len = 0;
15919ec7b004SRick Macklem 		error = nfsrv_mtofh(nd, &tfh);
15926b3dfc6aSRick Macklem 		if (error == 0)
15936b3dfc6aSRick Macklem 			error = nfsvno_getfh(dp, &fh, p);
15949ec7b004SRick Macklem 		if (error) {
15959ec7b004SRick Macklem 			vput(dp);
15969ec7b004SRick Macklem 			/* todp is always NULL except NFSv4 */
15979ec7b004SRick Macklem 			nfsvno_relpathbuf(&fromnd);
1598a9285ae5SZack Kirsch 			goto out;
15999ec7b004SRick Macklem 		}
16006b3dfc6aSRick Macklem 
16016b3dfc6aSRick Macklem 		/* If this is the same file handle, just VREF() the vnode. */
16026b3dfc6aSRick Macklem 		if (tfh.nfsrvfh_len == NFSX_MYFH &&
16036b3dfc6aSRick Macklem 		    !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
16046b3dfc6aSRick Macklem 			VREF(dp);
16056b3dfc6aSRick Macklem 			tdp = dp;
16066b3dfc6aSRick Macklem 			tnes = *exp;
160790d2dfabSRick Macklem 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
160890d2dfabSRick Macklem 			    NULL);
160925bfde79SXin LI 			NFSVOPUNLOCK(dp, 0);
16106b3dfc6aSRick Macklem 		} else {
161125bfde79SXin LI 			NFSVOPUNLOCK(dp, 0);
16126b3dfc6aSRick Macklem 			nd->nd_cred->cr_uid = nd->nd_saveduid;
16136b3dfc6aSRick Macklem 			nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
16145edc9102SEdward Tomasz Napierala 			    0);	/* Locks tdp. */
16156b3dfc6aSRick Macklem 			if (tdp) {
161690d2dfabSRick Macklem 				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
161790d2dfabSRick Macklem 				    p, 1, NULL);
1618c383087cSZack Kirsch 				NFSVOPUNLOCK(tdp, 0);
16199ec7b004SRick Macklem 			}
16209ec7b004SRick Macklem 		}
16216b3dfc6aSRick Macklem 	}
16229ec7b004SRick Macklem 	NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
16239ec7b004SRick Macklem 	nfsvno_setpathbuf(&tond, &tbufp, &hashp);
16249ec7b004SRick Macklem 	if (!nd->nd_repstat) {
16259ec7b004SRick Macklem 		error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
16269ec7b004SRick Macklem 		if (error) {
16278974bc2fSRick Macklem 			if (tdp)
16289ec7b004SRick Macklem 				vrele(tdp);
162925bfde79SXin LI 			vrele(dp);
16309ec7b004SRick Macklem 			nfsvno_relpathbuf(&fromnd);
16319ec7b004SRick Macklem 			nfsvno_relpathbuf(&tond);
1632a9285ae5SZack Kirsch 			goto out;
16339ec7b004SRick Macklem 		}
16349ec7b004SRick Macklem 	}
16359ec7b004SRick Macklem 	if (nd->nd_repstat) {
16369ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
16379ec7b004SRick Macklem 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
16389ec7b004SRick Macklem 			    &fdiraft);
16399ec7b004SRick Macklem 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
16409ec7b004SRick Macklem 			    &tdiraft);
16419ec7b004SRick Macklem 		}
16428974bc2fSRick Macklem 		if (tdp)
16439ec7b004SRick Macklem 			vrele(tdp);
164425bfde79SXin LI 		vrele(dp);
16459ec7b004SRick Macklem 		nfsvno_relpathbuf(&fromnd);
16469ec7b004SRick Macklem 		nfsvno_relpathbuf(&tond);
1647a9285ae5SZack Kirsch 		goto out;
16489ec7b004SRick Macklem 	}
16499ec7b004SRick Macklem 
16509ec7b004SRick Macklem 	/*
16519ec7b004SRick Macklem 	 * Done parsing, now down to business.
16529ec7b004SRick Macklem 	 */
165325bfde79SXin LI 	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
16549ec7b004SRick Macklem 	if (nd->nd_repstat) {
16559ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
16569ec7b004SRick Macklem 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
16579ec7b004SRick Macklem 			    &fdiraft);
16589ec7b004SRick Macklem 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
16599ec7b004SRick Macklem 			    &tdiraft);
16609ec7b004SRick Macklem 		}
16619ec7b004SRick Macklem 		if (fdirp)
16629ec7b004SRick Macklem 			vrele(fdirp);
16638974bc2fSRick Macklem 		if (tdp)
16649ec7b004SRick Macklem 			vrele(tdp);
16659ec7b004SRick Macklem 		nfsvno_relpathbuf(&tond);
1666a9285ae5SZack Kirsch 		goto out;
16679ec7b004SRick Macklem 	}
16689ec7b004SRick Macklem 	if (vnode_vtype(fromnd.ni_vp) == VDIR)
16699ec7b004SRick Macklem 		tond.ni_cnd.cn_flags |= WILLBEDIR;
16709ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
16719ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
16729ec7b004SRick Macklem 	    nd->nd_flag, nd->nd_cred, p);
16739ec7b004SRick Macklem 	if (fdirp)
167490d2dfabSRick Macklem 		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
16759ec7b004SRick Macklem 	if (tdirp)
167690d2dfabSRick Macklem 		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
16779ec7b004SRick Macklem 	if (fdirp)
16789ec7b004SRick Macklem 		vrele(fdirp);
16799ec7b004SRick Macklem 	if (tdirp)
16809ec7b004SRick Macklem 		vrele(tdirp);
16819ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
16829ec7b004SRick Macklem 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
16839ec7b004SRick Macklem 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
16849ec7b004SRick Macklem 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
16859ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
16869ec7b004SRick Macklem 		*tl++ = newnfs_false;
16879ec7b004SRick Macklem 		txdr_hyper(fdirfor.na_filerev, tl);
16889ec7b004SRick Macklem 		tl += 2;
16899ec7b004SRick Macklem 		txdr_hyper(fdiraft.na_filerev, tl);
16909ec7b004SRick Macklem 		tl += 2;
16919ec7b004SRick Macklem 		*tl++ = newnfs_false;
16929ec7b004SRick Macklem 		txdr_hyper(tdirfor.na_filerev, tl);
16939ec7b004SRick Macklem 		tl += 2;
16949ec7b004SRick Macklem 		txdr_hyper(tdiraft.na_filerev, tl);
16959ec7b004SRick Macklem 	}
1696a9285ae5SZack Kirsch 
1697a9285ae5SZack Kirsch out:
1698a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1699a9285ae5SZack Kirsch 	return (error);
17009ec7b004SRick Macklem }
17019ec7b004SRick Macklem 
17029ec7b004SRick Macklem /*
17039ec7b004SRick Macklem  * nfs link service
17049ec7b004SRick Macklem  */
17059ec7b004SRick Macklem APPLESTATIC int
17069ec7b004SRick Macklem nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1707af444b18SEdward Tomasz Napierala     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
17089ec7b004SRick Macklem {
17099ec7b004SRick Macklem 	struct nameidata named;
17109ec7b004SRick Macklem 	u_int32_t *tl;
17119ec7b004SRick Macklem 	int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
17129ec7b004SRick Macklem 	vnode_t dirp = NULL, dp = NULL;
17139ec7b004SRick Macklem 	struct nfsvattr dirfor, diraft, at;
17149ec7b004SRick Macklem 	struct nfsexstuff tnes;
17159ec7b004SRick Macklem 	struct nfsrvfh dfh;
17169ec7b004SRick Macklem 	char *bufp;
17179ec7b004SRick Macklem 	u_long *hashp;
1718af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
17199ec7b004SRick Macklem 
17209ec7b004SRick Macklem 	if (nd->nd_repstat) {
17219ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
17229ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1723a9285ae5SZack Kirsch 		goto out;
17249ec7b004SRick Macklem 	}
1725c383087cSZack Kirsch 	NFSVOPUNLOCK(vp, 0);
17269ec7b004SRick Macklem 	if (vnode_vtype(vp) == VDIR) {
17279ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4)
17289ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_ISDIR;
17299ec7b004SRick Macklem 		else
17309ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
17319ec7b004SRick Macklem 		if (tovp)
17329ec7b004SRick Macklem 			vrele(tovp);
17339ec7b004SRick Macklem 	}
17349ec7b004SRick Macklem 	if (!nd->nd_repstat) {
17359ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
17369ec7b004SRick Macklem 			dp = tovp;
17379ec7b004SRick Macklem 			tnes = *toexp;
17389ec7b004SRick Macklem 		} else {
17399ec7b004SRick Macklem 			error = nfsrv_mtofh(nd, &dfh);
17409ec7b004SRick Macklem 			if (error) {
17419ec7b004SRick Macklem 				vrele(vp);
17429ec7b004SRick Macklem 				/* tovp is always NULL unless NFSv4 */
1743a9285ae5SZack Kirsch 				goto out;
17449ec7b004SRick Macklem 			}
17455edc9102SEdward Tomasz Napierala 			nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0);
17469ec7b004SRick Macklem 			if (dp)
1747c383087cSZack Kirsch 				NFSVOPUNLOCK(dp, 0);
17489ec7b004SRick Macklem 		}
17499ec7b004SRick Macklem 	}
1750f61786cbSRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
17516c21f6edSKonstantin Belousov 	    LOCKPARENT | SAVENAME | NOCACHE);
17529ec7b004SRick Macklem 	if (!nd->nd_repstat) {
17539ec7b004SRick Macklem 		nfsvno_setpathbuf(&named, &bufp, &hashp);
17549ec7b004SRick Macklem 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
17559ec7b004SRick Macklem 		if (error) {
17569ec7b004SRick Macklem 			vrele(vp);
17578974bc2fSRick Macklem 			if (dp)
17589ec7b004SRick Macklem 				vrele(dp);
17599ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
1760a9285ae5SZack Kirsch 			goto out;
17619ec7b004SRick Macklem 		}
17629ec7b004SRick Macklem 		if (!nd->nd_repstat) {
17639ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
17649ec7b004SRick Macklem 			    p, &dirp);
17659ec7b004SRick Macklem 		} else {
17669ec7b004SRick Macklem 			if (dp)
17679ec7b004SRick Macklem 				vrele(dp);
17689ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
17699ec7b004SRick Macklem 		}
17709ec7b004SRick Macklem 	}
17719ec7b004SRick Macklem 	if (dirp) {
17729ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2) {
17739ec7b004SRick Macklem 			vrele(dirp);
17749ec7b004SRick Macklem 			dirp = NULL;
17759ec7b004SRick Macklem 		} else {
177690d2dfabSRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
177790d2dfabSRick Macklem 			    NULL);
17789ec7b004SRick Macklem 		}
17799ec7b004SRick Macklem 	}
17809ec7b004SRick Macklem 	if (!nd->nd_repstat)
17819ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
17829ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
178390d2dfabSRick Macklem 		getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
17849ec7b004SRick Macklem 	if (dirp) {
178590d2dfabSRick Macklem 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
17869ec7b004SRick Macklem 		vrele(dirp);
17879ec7b004SRick Macklem 	}
17889ec7b004SRick Macklem 	vrele(vp);
17899ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
17909ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
17919ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
17929ec7b004SRick Macklem 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
17939ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
17949ec7b004SRick Macklem 		*tl++ = newnfs_false;
17959ec7b004SRick Macklem 		txdr_hyper(dirfor.na_filerev, tl);
17969ec7b004SRick Macklem 		tl += 2;
17979ec7b004SRick Macklem 		txdr_hyper(diraft.na_filerev, tl);
17989ec7b004SRick Macklem 	}
1799a9285ae5SZack Kirsch 
1800a9285ae5SZack Kirsch out:
1801a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1802a9285ae5SZack Kirsch 	return (error);
18039ec7b004SRick Macklem }
18049ec7b004SRick Macklem 
18059ec7b004SRick Macklem /*
18069ec7b004SRick Macklem  * nfs symbolic link service
18079ec7b004SRick Macklem  */
18089ec7b004SRick Macklem APPLESTATIC int
18099ec7b004SRick Macklem nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1810af444b18SEdward Tomasz Napierala     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
18119ec7b004SRick Macklem {
18129ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
18139ec7b004SRick Macklem 	struct nameidata named;
1814a9285ae5SZack Kirsch 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
18159ec7b004SRick Macklem 	vnode_t dirp = NULL;
18169ec7b004SRick Macklem 	char *bufp, *pathcp = NULL;
18179ec7b004SRick Macklem 	u_long *hashp;
1818af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
18199ec7b004SRick Macklem 
18209ec7b004SRick Macklem 	if (nd->nd_repstat) {
18219ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1822a9285ae5SZack Kirsch 		goto out;
18239ec7b004SRick Macklem 	}
18249ec7b004SRick Macklem 	if (vpp)
18259ec7b004SRick Macklem 		*vpp = NULL;
18269ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
18279ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
18286c21f6edSKonstantin Belousov 	    LOCKPARENT | SAVESTART | NOCACHE);
18299ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
18309ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
18319ec7b004SRick Macklem 	if (!error && !nd->nd_repstat)
18329ec7b004SRick Macklem 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
18339ec7b004SRick Macklem 	if (error) {
18349ec7b004SRick Macklem 		vrele(dp);
18359ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
1836a9285ae5SZack Kirsch 		goto out;
18379ec7b004SRick Macklem 	}
18389ec7b004SRick Macklem 	if (!nd->nd_repstat) {
18399ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
18409ec7b004SRick Macklem 	} else {
18419ec7b004SRick Macklem 		vrele(dp);
18429ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
18439ec7b004SRick Macklem 	}
18449ec7b004SRick Macklem 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
18459ec7b004SRick Macklem 		vrele(dirp);
18469ec7b004SRick Macklem 		dirp = NULL;
18479ec7b004SRick Macklem 	}
18489ec7b004SRick Macklem 
18499ec7b004SRick Macklem 	/*
18509ec7b004SRick Macklem 	 * And call nfsrvd_symlinksub() to do the common code. It will
18519ec7b004SRick Macklem 	 * return EBADRPC upon a parsing error, 0 otherwise.
18529ec7b004SRick Macklem 	 */
18539ec7b004SRick Macklem 	if (!nd->nd_repstat) {
18549ec7b004SRick Macklem 		if (dirp != NULL)
185590d2dfabSRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
185690d2dfabSRick Macklem 			    NULL);
18579ec7b004SRick Macklem 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
18589ec7b004SRick Macklem 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
18599ec7b004SRick Macklem 		    pathcp, pathlen);
18609ec7b004SRick Macklem 	} else if (dirp != NULL) {
186190d2dfabSRick Macklem 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
18629ec7b004SRick Macklem 		vrele(dirp);
18639ec7b004SRick Macklem 	}
18649ec7b004SRick Macklem 	if (pathcp)
1865222daa42SConrad Meyer 		free(pathcp, M_TEMP);
18669ec7b004SRick Macklem 
18679ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
18689ec7b004SRick Macklem 		if (!nd->nd_repstat) {
18699ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
18709ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
18719ec7b004SRick Macklem 		}
18729ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
18739ec7b004SRick Macklem 	}
1874a9285ae5SZack Kirsch 
1875a9285ae5SZack Kirsch out:
1876a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1877a9285ae5SZack Kirsch 	return (error);
18789ec7b004SRick Macklem }
18799ec7b004SRick Macklem 
18809ec7b004SRick Macklem /*
18819ec7b004SRick Macklem  * Common code for creating a symbolic link.
18829ec7b004SRick Macklem  */
18839ec7b004SRick Macklem static void
18849ec7b004SRick Macklem nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
18859ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
18869ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
18879ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp,
18889ec7b004SRick Macklem     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
18899ec7b004SRick Macklem     int pathlen)
18909ec7b004SRick Macklem {
18919ec7b004SRick Macklem 	u_int32_t *tl;
18929ec7b004SRick Macklem 
18939ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
18949ec7b004SRick Macklem 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
18959ec7b004SRick Macklem 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
18969ec7b004SRick Macklem 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
18979ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
18989ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
18999ec7b004SRick Macklem 			if (!nd->nd_repstat)
19009ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
190190d2dfabSRick Macklem 				    nvap, nd, p, 1, NULL);
19029ec7b004SRick Macklem 		}
190381f78d99SRick Macklem 		if (vpp != NULL && nd->nd_repstat == 0) {
1904a9989634SZack Kirsch 			NFSVOPUNLOCK(ndp->ni_vp, 0);
19059ec7b004SRick Macklem 			*vpp = ndp->ni_vp;
190681f78d99SRick Macklem 		} else
19079ec7b004SRick Macklem 			vput(ndp->ni_vp);
19089ec7b004SRick Macklem 	}
19099ec7b004SRick Macklem 	if (dirp) {
191090d2dfabSRick Macklem 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
19119ec7b004SRick Macklem 		vrele(dirp);
19129ec7b004SRick Macklem 	}
19139ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
19149ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
19159ec7b004SRick Macklem 		*tl++ = newnfs_false;
19169ec7b004SRick Macklem 		txdr_hyper(dirforp->na_filerev, tl);
19179ec7b004SRick Macklem 		tl += 2;
19189ec7b004SRick Macklem 		txdr_hyper(diraftp->na_filerev, tl);
19199ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, attrbitp);
19209ec7b004SRick Macklem 	}
1921a9285ae5SZack Kirsch 
1922a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
19239ec7b004SRick Macklem }
19249ec7b004SRick Macklem 
19259ec7b004SRick Macklem /*
19269ec7b004SRick Macklem  * nfs mkdir service
19279ec7b004SRick Macklem  */
19289ec7b004SRick Macklem APPLESTATIC int
19299ec7b004SRick Macklem nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1930af444b18SEdward Tomasz Napierala     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
19319ec7b004SRick Macklem {
19329ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
19339ec7b004SRick Macklem 	struct nameidata named;
19349ec7b004SRick Macklem 	u_int32_t *tl;
1935a9285ae5SZack Kirsch 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
19369ec7b004SRick Macklem 	vnode_t dirp = NULL;
19379ec7b004SRick Macklem 	char *bufp;
19389ec7b004SRick Macklem 	u_long *hashp;
1939af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
19409ec7b004SRick Macklem 
19419ec7b004SRick Macklem 	if (nd->nd_repstat) {
19429ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1943a9285ae5SZack Kirsch 		goto out;
19449ec7b004SRick Macklem 	}
1945f61786cbSRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
19466c21f6edSKonstantin Belousov 	    LOCKPARENT | SAVENAME | NOCACHE);
19479ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
19489ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1949a9285ae5SZack Kirsch 	if (error)
1950a9285ae5SZack Kirsch 		goto nfsmout;
19519ec7b004SRick Macklem 	if (!nd->nd_repstat) {
19529ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva);
19539ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
1954d8a5961fSMarcelo Araujo 			error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1955a9285ae5SZack Kirsch 			if (error)
1956a9285ae5SZack Kirsch 				goto nfsmout;
19579ec7b004SRick Macklem 		} else {
19589ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
19599ec7b004SRick Macklem 			nva.na_mode = nfstov_mode(*tl++);
19609ec7b004SRick Macklem 		}
19619ec7b004SRick Macklem 	}
19629ec7b004SRick Macklem 	if (!nd->nd_repstat) {
19639ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
19649ec7b004SRick Macklem 	} else {
19659ec7b004SRick Macklem 		vrele(dp);
19669ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
19679ec7b004SRick Macklem 	}
19689ec7b004SRick Macklem 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
19699ec7b004SRick Macklem 		vrele(dirp);
19709ec7b004SRick Macklem 		dirp = NULL;
19719ec7b004SRick Macklem 	}
19729ec7b004SRick Macklem 	if (nd->nd_repstat) {
19739ec7b004SRick Macklem 		if (dirp != NULL) {
197490d2dfabSRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
197590d2dfabSRick Macklem 			    NULL);
19769ec7b004SRick Macklem 			vrele(dirp);
19779ec7b004SRick Macklem 		}
19789ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
19799ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
19809ec7b004SRick Macklem 			    &diraft);
1981a9285ae5SZack Kirsch 		goto out;
19829ec7b004SRick Macklem 	}
19839ec7b004SRick Macklem 	if (dirp != NULL)
198490d2dfabSRick Macklem 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
19859ec7b004SRick Macklem 
19869ec7b004SRick Macklem 	/*
19879ec7b004SRick Macklem 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
19889ec7b004SRick Macklem 	 */
19899ec7b004SRick Macklem 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
19909ec7b004SRick Macklem 	    &diraft_ret, NULL, NULL, p, exp);
19919ec7b004SRick Macklem 
19929ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
19939ec7b004SRick Macklem 		if (!nd->nd_repstat) {
19949ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
19959ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
19969ec7b004SRick Macklem 		}
19979ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
19989ec7b004SRick Macklem 	} else if (!nd->nd_repstat) {
19999ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
20009ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
20019ec7b004SRick Macklem 	}
2002a9285ae5SZack Kirsch 
2003a9285ae5SZack Kirsch out:
2004a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
20059ec7b004SRick Macklem 	return (0);
20069ec7b004SRick Macklem nfsmout:
20079ec7b004SRick Macklem 	vrele(dp);
20089ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
2009a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
20109ec7b004SRick Macklem 	return (error);
20119ec7b004SRick Macklem }
20129ec7b004SRick Macklem 
20139ec7b004SRick Macklem /*
20149ec7b004SRick Macklem  * Code common to mkdir for V2,3 and 4.
20159ec7b004SRick Macklem  */
20169ec7b004SRick Macklem static void
20179ec7b004SRick Macklem nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
20189ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
20199ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
20209ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
20219ec7b004SRick Macklem     NFSPROC_T *p, struct nfsexstuff *exp)
20229ec7b004SRick Macklem {
20239ec7b004SRick Macklem 	vnode_t vp;
20249ec7b004SRick Macklem 	u_int32_t *tl;
20259ec7b004SRick Macklem 
20269ec7b004SRick Macklem 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
20279ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
20289ec7b004SRick Macklem 	    nd->nd_cred, p, exp);
20299ec7b004SRick Macklem 	if (!nd->nd_repstat) {
20309ec7b004SRick Macklem 		vp = ndp->ni_vp;
20319ec7b004SRick Macklem 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
20329ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
20339ec7b004SRick Macklem 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
203490d2dfabSRick Macklem 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
203590d2dfabSRick Macklem 			    NULL);
20369ec7b004SRick Macklem 		if (vpp && !nd->nd_repstat) {
2037c383087cSZack Kirsch 			NFSVOPUNLOCK(vp, 0);
20389ec7b004SRick Macklem 			*vpp = vp;
20399ec7b004SRick Macklem 		} else {
20409ec7b004SRick Macklem 			vput(vp);
20419ec7b004SRick Macklem 		}
20429ec7b004SRick Macklem 	}
20439ec7b004SRick Macklem 	if (dirp) {
204490d2dfabSRick Macklem 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
20459ec7b004SRick Macklem 		vrele(dirp);
20469ec7b004SRick Macklem 	}
20479ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
20489ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
20499ec7b004SRick Macklem 		*tl++ = newnfs_false;
20509ec7b004SRick Macklem 		txdr_hyper(dirforp->na_filerev, tl);
20519ec7b004SRick Macklem 		tl += 2;
20529ec7b004SRick Macklem 		txdr_hyper(diraftp->na_filerev, tl);
20539ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, attrbitp);
20549ec7b004SRick Macklem 	}
2055a9285ae5SZack Kirsch 
2056a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
20579ec7b004SRick Macklem }
20589ec7b004SRick Macklem 
20599ec7b004SRick Macklem /*
20609ec7b004SRick Macklem  * nfs commit service
20619ec7b004SRick Macklem  */
20629ec7b004SRick Macklem APPLESTATIC int
20639ec7b004SRick Macklem nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2064af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
20659ec7b004SRick Macklem {
20669ec7b004SRick Macklem 	struct nfsvattr bfor, aft;
20679ec7b004SRick Macklem 	u_int32_t *tl;
20689ec7b004SRick Macklem 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
20699ec7b004SRick Macklem 	u_int64_t off;
2070af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
20719ec7b004SRick Macklem 
20729ec7b004SRick Macklem        if (nd->nd_repstat) {
20739ec7b004SRick Macklem 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2074a9285ae5SZack Kirsch 		goto out;
20759ec7b004SRick Macklem 	}
2076d8a5961fSMarcelo Araujo 
2077d8a5961fSMarcelo Araujo 	/* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2078d8a5961fSMarcelo Araujo 	if (vp->v_type != VREG) {
2079d8a5961fSMarcelo Araujo 		if (nd->nd_flag & ND_NFSV3)
2080d8a5961fSMarcelo Araujo 			error = NFSERR_NOTSUPP;
2081d8a5961fSMarcelo Araujo 		else
2082d8a5961fSMarcelo Araujo 			error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2083d8a5961fSMarcelo Araujo 		goto nfsmout;
2084d8a5961fSMarcelo Araujo 	}
20859ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2086d8a5961fSMarcelo Araujo 
20879ec7b004SRick Macklem 	/*
20889ec7b004SRick Macklem 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
20899ec7b004SRick Macklem 	 * count parameters, so these arguments are useless (someday maybe).
20909ec7b004SRick Macklem 	 */
20919ec7b004SRick Macklem 	off = fxdr_hyper(tl);
20929ec7b004SRick Macklem 	tl += 2;
20939ec7b004SRick Macklem 	cnt = fxdr_unsigned(int, *tl);
20949ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
209590d2dfabSRick Macklem 		for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
20969ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
20979ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
209890d2dfabSRick Macklem 		aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
20999ec7b004SRick Macklem 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
21009ec7b004SRick Macklem 	}
21019ec7b004SRick Macklem 	vput(vp);
21029ec7b004SRick Macklem 	if (!nd->nd_repstat) {
21039ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
21049ec7b004SRick Macklem 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
21059ec7b004SRick Macklem 		*tl = txdr_unsigned(nfsboottime.tv_usec);
21069ec7b004SRick Macklem 	}
2107a9285ae5SZack Kirsch 
2108a9285ae5SZack Kirsch out:
2109a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
21109ec7b004SRick Macklem 	return (0);
21119ec7b004SRick Macklem nfsmout:
21129ec7b004SRick Macklem 	vput(vp);
2113a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
21149ec7b004SRick Macklem 	return (error);
21159ec7b004SRick Macklem }
21169ec7b004SRick Macklem 
21179ec7b004SRick Macklem /*
21189ec7b004SRick Macklem  * nfs statfs service
21199ec7b004SRick Macklem  */
21209ec7b004SRick Macklem APPLESTATIC int
21219ec7b004SRick Macklem nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2122af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
21239ec7b004SRick Macklem {
21249ec7b004SRick Macklem 	struct statfs *sf;
21259ec7b004SRick Macklem 	u_int32_t *tl;
21269ec7b004SRick Macklem 	int getret = 1;
21279ec7b004SRick Macklem 	struct nfsvattr at;
21289ec7b004SRick Macklem 	u_quad_t tval;
2129af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
21309ec7b004SRick Macklem 
21312f304845SKonstantin Belousov 	sf = NULL;
21329ec7b004SRick Macklem 	if (nd->nd_repstat) {
21339ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
2134a9285ae5SZack Kirsch 		goto out;
21359ec7b004SRick Macklem 	}
21362f304845SKonstantin Belousov 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2137dfd233edSAttilio Rao 	nd->nd_repstat = nfsvno_statfs(vp, sf);
213890d2dfabSRick Macklem 	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
21399ec7b004SRick Macklem 	vput(vp);
21409ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
21419ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
21429ec7b004SRick Macklem 	if (nd->nd_repstat)
2143a9285ae5SZack Kirsch 		goto out;
21449ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
21459ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
21469ec7b004SRick Macklem 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
21479ec7b004SRick Macklem 		*tl++ = txdr_unsigned(sf->f_bsize);
21489ec7b004SRick Macklem 		*tl++ = txdr_unsigned(sf->f_blocks);
21499ec7b004SRick Macklem 		*tl++ = txdr_unsigned(sf->f_bfree);
21509ec7b004SRick Macklem 		*tl = txdr_unsigned(sf->f_bavail);
21519ec7b004SRick Macklem 	} else {
21529ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
21539ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_blocks;
21549ec7b004SRick Macklem 		tval *= (u_quad_t)sf->f_bsize;
21559ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
21569ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_bfree;
21579ec7b004SRick Macklem 		tval *= (u_quad_t)sf->f_bsize;
21589ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
21599ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_bavail;
21609ec7b004SRick Macklem 		tval *= (u_quad_t)sf->f_bsize;
21619ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
21629ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_files;
21639ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
21649ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_ffree;
21659ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
21669ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_ffree;
21679ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
21689ec7b004SRick Macklem 		*tl = 0;
21699ec7b004SRick Macklem 	}
2170a9285ae5SZack Kirsch 
2171a9285ae5SZack Kirsch out:
21722f304845SKonstantin Belousov 	free(sf, M_STATFS);
2173a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
21749ec7b004SRick Macklem 	return (0);
21759ec7b004SRick Macklem }
21769ec7b004SRick Macklem 
21779ec7b004SRick Macklem /*
21789ec7b004SRick Macklem  * nfs fsinfo service
21799ec7b004SRick Macklem  */
21809ec7b004SRick Macklem APPLESTATIC int
21819ec7b004SRick Macklem nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2182af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
21839ec7b004SRick Macklem {
21849ec7b004SRick Macklem 	u_int32_t *tl;
21859ec7b004SRick Macklem 	struct nfsfsinfo fs;
21869ec7b004SRick Macklem 	int getret = 1;
21879ec7b004SRick Macklem 	struct nfsvattr at;
2188af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
21899ec7b004SRick Macklem 
21909ec7b004SRick Macklem 	if (nd->nd_repstat) {
21919ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
2192a9285ae5SZack Kirsch 		goto out;
21939ec7b004SRick Macklem 	}
219490d2dfabSRick Macklem 	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
21959ec7b004SRick Macklem 	nfsvno_getfs(&fs, isdgram);
21969ec7b004SRick Macklem 	vput(vp);
21979ec7b004SRick Macklem 	nfsrv_postopattr(nd, getret, &at);
21989ec7b004SRick Macklem 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
21999ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_rtmax);
22009ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_rtpref);
22019ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_rtmult);
22029ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_wtmax);
22039ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_wtpref);
22049ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_wtmult);
22059ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_dtpref);
22069ec7b004SRick Macklem 	txdr_hyper(fs.fs_maxfilesize, tl);
22079ec7b004SRick Macklem 	tl += 2;
22089ec7b004SRick Macklem 	txdr_nfsv3time(&fs.fs_timedelta, tl);
22099ec7b004SRick Macklem 	tl += 2;
22109ec7b004SRick Macklem 	*tl = txdr_unsigned(fs.fs_properties);
2211a9285ae5SZack Kirsch 
2212a9285ae5SZack Kirsch out:
2213a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
22149ec7b004SRick Macklem 	return (0);
22159ec7b004SRick Macklem }
22169ec7b004SRick Macklem 
22179ec7b004SRick Macklem /*
22189ec7b004SRick Macklem  * nfs pathconf service
22199ec7b004SRick Macklem  */
22209ec7b004SRick Macklem APPLESTATIC int
22219ec7b004SRick Macklem nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2222af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
22239ec7b004SRick Macklem {
22249ec7b004SRick Macklem 	struct nfsv3_pathconf *pc;
22259ec7b004SRick Macklem 	int getret = 1;
2226b1288166SJohn Baldwin 	long linkmax, namemax, chownres, notrunc;
22279ec7b004SRick Macklem 	struct nfsvattr at;
2228af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
22299ec7b004SRick Macklem 
22309ec7b004SRick Macklem 	if (nd->nd_repstat) {
22319ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
2232a9285ae5SZack Kirsch 		goto out;
22339ec7b004SRick Macklem 	}
22349ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
22359ec7b004SRick Macklem 	    nd->nd_cred, p);
22369ec7b004SRick Macklem 	if (!nd->nd_repstat)
22379ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
22389ec7b004SRick Macklem 		    nd->nd_cred, p);
22399ec7b004SRick Macklem 	if (!nd->nd_repstat)
22409ec7b004SRick Macklem 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
22419ec7b004SRick Macklem 		    &chownres, nd->nd_cred, p);
22429ec7b004SRick Macklem 	if (!nd->nd_repstat)
22439ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
22449ec7b004SRick Macklem 		    nd->nd_cred, p);
224590d2dfabSRick Macklem 	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
22469ec7b004SRick Macklem 	vput(vp);
22479ec7b004SRick Macklem 	nfsrv_postopattr(nd, getret, &at);
22489ec7b004SRick Macklem 	if (!nd->nd_repstat) {
22499ec7b004SRick Macklem 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
22509ec7b004SRick Macklem 		pc->pc_linkmax = txdr_unsigned(linkmax);
22519ec7b004SRick Macklem 		pc->pc_namemax = txdr_unsigned(namemax);
22529ec7b004SRick Macklem 		pc->pc_notrunc = txdr_unsigned(notrunc);
22539ec7b004SRick Macklem 		pc->pc_chownrestricted = txdr_unsigned(chownres);
22549ec7b004SRick Macklem 
22559ec7b004SRick Macklem 		/*
22569ec7b004SRick Macklem 		 * These should probably be supported by VOP_PATHCONF(), but
22579ec7b004SRick Macklem 		 * until msdosfs is exportable (why would you want to?), the
22589ec7b004SRick Macklem 		 * Unix defaults should be ok.
22599ec7b004SRick Macklem 		 */
22609ec7b004SRick Macklem 		pc->pc_caseinsensitive = newnfs_false;
22619ec7b004SRick Macklem 		pc->pc_casepreserving = newnfs_true;
22629ec7b004SRick Macklem 	}
2263a9285ae5SZack Kirsch 
2264a9285ae5SZack Kirsch out:
2265a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
22669ec7b004SRick Macklem 	return (0);
22679ec7b004SRick Macklem }
22689ec7b004SRick Macklem 
22699ec7b004SRick Macklem /*
22709ec7b004SRick Macklem  * nfsv4 lock service
22719ec7b004SRick Macklem  */
22729ec7b004SRick Macklem APPLESTATIC int
22739ec7b004SRick Macklem nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2274af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
22759ec7b004SRick Macklem {
22769ec7b004SRick Macklem 	u_int32_t *tl;
22779ec7b004SRick Macklem 	int i;
22789ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
22799ec7b004SRick Macklem 	struct nfslock *lop;
22809ec7b004SRick Macklem 	struct nfslockconflict cf;
22819ec7b004SRick Macklem 	int error = 0;
22829ec7b004SRick Macklem 	u_short flags = NFSLCK_LOCK, lflags;
22839ec7b004SRick Macklem 	u_int64_t offset, len;
22849ec7b004SRick Macklem 	nfsv4stateid_t stateid;
22859ec7b004SRick Macklem 	nfsquad_t clientid;
2286af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
22879ec7b004SRick Macklem 
22889ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
22899ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
22909ec7b004SRick Macklem 	switch (i) {
22919ec7b004SRick Macklem 	case NFSV4LOCKT_READW:
22929ec7b004SRick Macklem 		flags |= NFSLCK_BLOCKING;
22939ec7b004SRick Macklem 	case NFSV4LOCKT_READ:
22949ec7b004SRick Macklem 		lflags = NFSLCK_READ;
22959ec7b004SRick Macklem 		break;
22969ec7b004SRick Macklem 	case NFSV4LOCKT_WRITEW:
22979ec7b004SRick Macklem 		flags |= NFSLCK_BLOCKING;
22989ec7b004SRick Macklem 	case NFSV4LOCKT_WRITE:
22999ec7b004SRick Macklem 		lflags = NFSLCK_WRITE;
23009ec7b004SRick Macklem 		break;
23019ec7b004SRick Macklem 	default:
23029ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
23039ec7b004SRick Macklem 		goto nfsmout;
230474b8d63dSPedro F. Giffuni 	}
23059ec7b004SRick Macklem 	if (*tl++ == newnfs_true)
23069ec7b004SRick Macklem 		flags |= NFSLCK_RECLAIM;
23079ec7b004SRick Macklem 	offset = fxdr_hyper(tl);
23089ec7b004SRick Macklem 	tl += 2;
23099ec7b004SRick Macklem 	len = fxdr_hyper(tl);
23109ec7b004SRick Macklem 	tl += 2;
23119ec7b004SRick Macklem 	if (*tl == newnfs_true)
23129ec7b004SRick Macklem 		flags |= NFSLCK_OPENTOLOCK;
23139ec7b004SRick Macklem 	if (flags & NFSLCK_OPENTOLOCK) {
23149ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
23159ec7b004SRick Macklem 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
23162a45247cSRick Macklem 		if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
23172a45247cSRick Macklem 			nd->nd_repstat = NFSERR_BADXDR;
23182a45247cSRick Macklem 			goto nfsmout;
23192a45247cSRick Macklem 		}
2320222daa42SConrad Meyer 		stp = malloc(sizeof (struct nfsstate) + i,
23219ec7b004SRick Macklem 			M_NFSDSTATE, M_WAITOK);
23229ec7b004SRick Macklem 		stp->ls_ownerlen = i;
23239ec7b004SRick Macklem 		stp->ls_op = nd->nd_rp;
23249ec7b004SRick Macklem 		stp->ls_seq = fxdr_unsigned(int, *tl++);
23259ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
23269ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
23279ec7b004SRick Macklem 			NFSX_STATEIDOTHER);
23289ec7b004SRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
232990d2dfabSRick Macklem 
233090d2dfabSRick Macklem 		/*
233190d2dfabSRick Macklem 		 * For the special stateid of other all 0s and seqid == 1, set
233290d2dfabSRick Macklem 		 * the stateid to the current stateid, if it is set.
233390d2dfabSRick Macklem 		 */
233490d2dfabSRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
233590d2dfabSRick Macklem 		    stp->ls_stateid.seqid == 1 &&
233690d2dfabSRick Macklem 		    stp->ls_stateid.other[0] == 0 &&
233790d2dfabSRick Macklem 		    stp->ls_stateid.other[1] == 0 &&
233890d2dfabSRick Macklem 		    stp->ls_stateid.other[2] == 0) {
233990d2dfabSRick Macklem 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
234090d2dfabSRick Macklem 				stp->ls_stateid = nd->nd_curstateid;
234190d2dfabSRick Macklem 				stp->ls_stateid.seqid = 0;
234290d2dfabSRick Macklem 			} else {
234390d2dfabSRick Macklem 				nd->nd_repstat = NFSERR_BADSTATEID;
234490d2dfabSRick Macklem 				goto nfsmout;
234590d2dfabSRick Macklem 			}
234690d2dfabSRick Macklem 		}
234790d2dfabSRick Macklem 
23489ec7b004SRick Macklem 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
23499ec7b004SRick Macklem 		clientid.lval[0] = *tl++;
23509ec7b004SRick Macklem 		clientid.lval[1] = *tl++;
2351c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2352c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
2353c59e4cc3SRick Macklem 				clientid.qval = nd->nd_clientid.qval;
2354c59e4cc3SRick Macklem 			else if (nd->nd_clientid.qval != clientid.qval)
2355c59e4cc3SRick Macklem 				printf("EEK3 multiple clids\n");
23569ec7b004SRick Macklem 		} else {
2357c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
2358c59e4cc3SRick Macklem 				printf("EEK! no clientid from session\n");
23599ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
23609ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
23619ec7b004SRick Macklem 		}
23629ec7b004SRick Macklem 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
23639ec7b004SRick Macklem 		if (error)
23649ec7b004SRick Macklem 			goto nfsmout;
23659ec7b004SRick Macklem 	} else {
23669ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2367222daa42SConrad Meyer 		stp = malloc(sizeof (struct nfsstate),
23689ec7b004SRick Macklem 			M_NFSDSTATE, M_WAITOK);
23699ec7b004SRick Macklem 		stp->ls_ownerlen = 0;
23709ec7b004SRick Macklem 		stp->ls_op = nd->nd_rp;
23719ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
23729ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
23739ec7b004SRick Macklem 			NFSX_STATEIDOTHER);
23749ec7b004SRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
237590d2dfabSRick Macklem 
237690d2dfabSRick Macklem 		/*
237790d2dfabSRick Macklem 		 * For the special stateid of other all 0s and seqid == 1, set
237890d2dfabSRick Macklem 		 * the stateid to the current stateid, if it is set.
237990d2dfabSRick Macklem 		 */
238090d2dfabSRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
238190d2dfabSRick Macklem 		    stp->ls_stateid.seqid == 1 &&
238290d2dfabSRick Macklem 		    stp->ls_stateid.other[0] == 0 &&
238390d2dfabSRick Macklem 		    stp->ls_stateid.other[1] == 0 &&
238490d2dfabSRick Macklem 		    stp->ls_stateid.other[2] == 0) {
238590d2dfabSRick Macklem 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
238690d2dfabSRick Macklem 				stp->ls_stateid = nd->nd_curstateid;
238790d2dfabSRick Macklem 				stp->ls_stateid.seqid = 0;
238890d2dfabSRick Macklem 			} else {
238990d2dfabSRick Macklem 				nd->nd_repstat = NFSERR_BADSTATEID;
239090d2dfabSRick Macklem 				goto nfsmout;
239190d2dfabSRick Macklem 			}
239290d2dfabSRick Macklem 		}
239390d2dfabSRick Macklem 
23949ec7b004SRick Macklem 		stp->ls_seq = fxdr_unsigned(int, *tl);
23959ec7b004SRick Macklem 		clientid.lval[0] = stp->ls_stateid.other[0];
23969ec7b004SRick Macklem 		clientid.lval[1] = stp->ls_stateid.other[1];
2397c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2398c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
2399c59e4cc3SRick Macklem 				clientid.qval = nd->nd_clientid.qval;
2400c59e4cc3SRick Macklem 			else if (nd->nd_clientid.qval != clientid.qval)
2401c59e4cc3SRick Macklem 				printf("EEK4 multiple clids\n");
24029ec7b004SRick Macklem 		} else {
2403c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
2404c59e4cc3SRick Macklem 				printf("EEK! no clientid from session\n");
24059ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
24069ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
24079ec7b004SRick Macklem 		}
24089ec7b004SRick Macklem 	}
2409222daa42SConrad Meyer 	lop = malloc(sizeof (struct nfslock),
24109ec7b004SRick Macklem 		M_NFSDLOCK, M_WAITOK);
24119ec7b004SRick Macklem 	lop->lo_first = offset;
24129ec7b004SRick Macklem 	if (len == NFS64BITSSET) {
24139ec7b004SRick Macklem 		lop->lo_end = NFS64BITSSET;
24149ec7b004SRick Macklem 	} else {
24159ec7b004SRick Macklem 		lop->lo_end = offset + len;
24169ec7b004SRick Macklem 		if (lop->lo_end <= lop->lo_first)
24179ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
24189ec7b004SRick Macklem 	}
24199ec7b004SRick Macklem 	lop->lo_flags = lflags;
24209ec7b004SRick Macklem 	stp->ls_flags = flags;
24219ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
24229ec7b004SRick Macklem 
24239ec7b004SRick Macklem 	/*
24249ec7b004SRick Macklem 	 * Do basic access checking.
24259ec7b004SRick Macklem 	 */
24269ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
24279ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
24289ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
24299ec7b004SRick Macklem 	    else
24309ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
24319ec7b004SRick Macklem 	}
24329ec7b004SRick Macklem 	if (!nd->nd_repstat) {
24339ec7b004SRick Macklem 	    if (lflags & NFSLCK_WRITE) {
24348da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
24359ec7b004SRick Macklem 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
24368da45f2cSRick Macklem 		    NFSACCCHK_VPISLOCKED, NULL);
24379ec7b004SRick Macklem 	    } else {
24388da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
24399ec7b004SRick Macklem 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
24408da45f2cSRick Macklem 		    NFSACCCHK_VPISLOCKED, NULL);
24419ec7b004SRick Macklem 		if (nd->nd_repstat)
24428da45f2cSRick Macklem 		    nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
24439ec7b004SRick Macklem 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
24448da45f2cSRick Macklem 			NFSACCCHK_VPISLOCKED, NULL);
24459ec7b004SRick Macklem 	    }
24469ec7b004SRick Macklem 	}
24479ec7b004SRick Macklem 
24489ec7b004SRick Macklem 	/*
24499ec7b004SRick Macklem 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
24509ec7b004SRick Macklem 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
24519ec7b004SRick Macklem 	 * of nd_repstat, if it gets that far.
24529ec7b004SRick Macklem 	 */
24539ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
24549ec7b004SRick Macklem 		&stateid, exp, nd, p);
24559ec7b004SRick Macklem 	if (lop)
2456222daa42SConrad Meyer 		free(lop, M_NFSDLOCK);
24579ec7b004SRick Macklem 	if (stp)
2458222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
24599ec7b004SRick Macklem 	if (!nd->nd_repstat) {
246090d2dfabSRick Macklem 		/* For NFSv4.1, set the Current StateID. */
246190d2dfabSRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0) {
246290d2dfabSRick Macklem 			nd->nd_curstateid = stateid;
246390d2dfabSRick Macklem 			nd->nd_flag |= ND_CURSTATEID;
246490d2dfabSRick Macklem 		}
24659ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
24669ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
24679ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
24689ec7b004SRick Macklem 	} else if (nd->nd_repstat == NFSERR_DENIED) {
24699ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
24709ec7b004SRick Macklem 		txdr_hyper(cf.cl_first, tl);
24719ec7b004SRick Macklem 		tl += 2;
24729ec7b004SRick Macklem 		if (cf.cl_end == NFS64BITSSET)
24739ec7b004SRick Macklem 			len = NFS64BITSSET;
24749ec7b004SRick Macklem 		else
24759ec7b004SRick Macklem 			len = cf.cl_end - cf.cl_first;
24769ec7b004SRick Macklem 		txdr_hyper(len, tl);
24779ec7b004SRick Macklem 		tl += 2;
24789ec7b004SRick Macklem 		if (cf.cl_flags == NFSLCK_WRITE)
24799ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
24809ec7b004SRick Macklem 		else
24819ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
24829ec7b004SRick Macklem 		*tl++ = stateid.other[0];
24839ec7b004SRick Macklem 		*tl = stateid.other[1];
24849ec7b004SRick Macklem 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
24859ec7b004SRick Macklem 	}
24869ec7b004SRick Macklem 	vput(vp);
2487a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
24889ec7b004SRick Macklem 	return (0);
24899ec7b004SRick Macklem nfsmout:
24909ec7b004SRick Macklem 	vput(vp);
24919ec7b004SRick Macklem 	if (stp)
2492222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
2493a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
24949ec7b004SRick Macklem 	return (error);
24959ec7b004SRick Macklem }
24969ec7b004SRick Macklem 
24979ec7b004SRick Macklem /*
24989ec7b004SRick Macklem  * nfsv4 lock test service
24999ec7b004SRick Macklem  */
25009ec7b004SRick Macklem APPLESTATIC int
25019ec7b004SRick Macklem nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2502af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
25039ec7b004SRick Macklem {
25049ec7b004SRick Macklem 	u_int32_t *tl;
25059ec7b004SRick Macklem 	int i;
25069ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
25079ec7b004SRick Macklem 	struct nfslock lo, *lop = &lo;
25089ec7b004SRick Macklem 	struct nfslockconflict cf;
25099ec7b004SRick Macklem 	int error = 0;
25109ec7b004SRick Macklem 	nfsv4stateid_t stateid;
25119ec7b004SRick Macklem 	nfsquad_t clientid;
25129ec7b004SRick Macklem 	u_int64_t len;
2513af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
25149ec7b004SRick Macklem 
25159ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
25169ec7b004SRick Macklem 	i = fxdr_unsigned(int, *(tl + 7));
25172a45247cSRick Macklem 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
25182a45247cSRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
25192a45247cSRick Macklem 		goto nfsmout;
25202a45247cSRick Macklem 	}
2521222daa42SConrad Meyer 	stp = malloc(sizeof (struct nfsstate) + i,
25229ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
25239ec7b004SRick Macklem 	stp->ls_ownerlen = i;
25249ec7b004SRick Macklem 	stp->ls_op = NULL;
25259ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_TEST;
25269ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
25279ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
25289ec7b004SRick Macklem 	switch (i) {
25299ec7b004SRick Macklem 	case NFSV4LOCKT_READW:
25309ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
25319ec7b004SRick Macklem 	case NFSV4LOCKT_READ:
25329ec7b004SRick Macklem 		lo.lo_flags = NFSLCK_READ;
25339ec7b004SRick Macklem 		break;
25349ec7b004SRick Macklem 	case NFSV4LOCKT_WRITEW:
25359ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
25369ec7b004SRick Macklem 	case NFSV4LOCKT_WRITE:
25379ec7b004SRick Macklem 		lo.lo_flags = NFSLCK_WRITE;
25389ec7b004SRick Macklem 		break;
25399ec7b004SRick Macklem 	default:
25409ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
25419ec7b004SRick Macklem 		goto nfsmout;
254274b8d63dSPedro F. Giffuni 	}
25439ec7b004SRick Macklem 	lo.lo_first = fxdr_hyper(tl);
25449ec7b004SRick Macklem 	tl += 2;
25459ec7b004SRick Macklem 	len = fxdr_hyper(tl);
25469ec7b004SRick Macklem 	if (len == NFS64BITSSET) {
25479ec7b004SRick Macklem 		lo.lo_end = NFS64BITSSET;
25489ec7b004SRick Macklem 	} else {
25499ec7b004SRick Macklem 		lo.lo_end = lo.lo_first + len;
25509ec7b004SRick Macklem 		if (lo.lo_end <= lo.lo_first)
25519ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
25529ec7b004SRick Macklem 	}
25539ec7b004SRick Macklem 	tl += 2;
25549ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
25559ec7b004SRick Macklem 	clientid.lval[1] = *tl;
2556c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2557c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2558c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
2559c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
2560c59e4cc3SRick Macklem 			printf("EEK5 multiple clids\n");
25619ec7b004SRick Macklem 	} else {
2562c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2563c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
25649ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
25659ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
25669ec7b004SRick Macklem 	}
25679ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
25689ec7b004SRick Macklem 	if (error)
25699ec7b004SRick Macklem 		goto nfsmout;
25709ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
25719ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
25729ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
25739ec7b004SRick Macklem 	    else
25749ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
25759ec7b004SRick Macklem 	}
25769ec7b004SRick Macklem 	if (!nd->nd_repstat)
25779ec7b004SRick Macklem 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
25789ec7b004SRick Macklem 	    &stateid, exp, nd, p);
25799ec7b004SRick Macklem 	if (nd->nd_repstat) {
25809ec7b004SRick Macklem 	    if (nd->nd_repstat == NFSERR_DENIED) {
25819ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
25829ec7b004SRick Macklem 		txdr_hyper(cf.cl_first, tl);
25839ec7b004SRick Macklem 		tl += 2;
25849ec7b004SRick Macklem 		if (cf.cl_end == NFS64BITSSET)
25859ec7b004SRick Macklem 			len = NFS64BITSSET;
25869ec7b004SRick Macklem 		else
25879ec7b004SRick Macklem 			len = cf.cl_end - cf.cl_first;
25889ec7b004SRick Macklem 		txdr_hyper(len, tl);
25899ec7b004SRick Macklem 		tl += 2;
25909ec7b004SRick Macklem 		if (cf.cl_flags == NFSLCK_WRITE)
25919ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
25929ec7b004SRick Macklem 		else
25939ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
25949ec7b004SRick Macklem 		*tl++ = stp->ls_stateid.other[0];
25959ec7b004SRick Macklem 		*tl = stp->ls_stateid.other[1];
25969ec7b004SRick Macklem 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
25979ec7b004SRick Macklem 	    }
25989ec7b004SRick Macklem 	}
25999ec7b004SRick Macklem 	vput(vp);
26005ecc225fSConrad Meyer 	if (stp)
2601222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
2602a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
26039ec7b004SRick Macklem 	return (0);
26049ec7b004SRick Macklem nfsmout:
26059ec7b004SRick Macklem 	vput(vp);
26069ec7b004SRick Macklem 	if (stp)
2607222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
2608a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
26099ec7b004SRick Macklem 	return (error);
26109ec7b004SRick Macklem }
26119ec7b004SRick Macklem 
26129ec7b004SRick Macklem /*
26139ec7b004SRick Macklem  * nfsv4 unlock service
26149ec7b004SRick Macklem  */
26159ec7b004SRick Macklem APPLESTATIC int
26169ec7b004SRick Macklem nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2617af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
26189ec7b004SRick Macklem {
26199ec7b004SRick Macklem 	u_int32_t *tl;
26209ec7b004SRick Macklem 	int i;
26219ec7b004SRick Macklem 	struct nfsstate *stp;
26229ec7b004SRick Macklem 	struct nfslock *lop;
26239ec7b004SRick Macklem 	int error = 0;
26249ec7b004SRick Macklem 	nfsv4stateid_t stateid;
26259ec7b004SRick Macklem 	nfsquad_t clientid;
26269ec7b004SRick Macklem 	u_int64_t len;
2627af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
26289ec7b004SRick Macklem 
26299ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2630222daa42SConrad Meyer 	stp = malloc(sizeof (struct nfsstate),
26319ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
2632222daa42SConrad Meyer 	lop = malloc(sizeof (struct nfslock),
26339ec7b004SRick Macklem 	    M_NFSDLOCK, M_WAITOK);
26349ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_UNLOCK;
26359ec7b004SRick Macklem 	lop->lo_flags = NFSLCK_UNLOCK;
26369ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
26379ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
26389ec7b004SRick Macklem 	switch (i) {
26399ec7b004SRick Macklem 	case NFSV4LOCKT_READW:
26409ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
26419ec7b004SRick Macklem 	case NFSV4LOCKT_READ:
26429ec7b004SRick Macklem 		break;
26439ec7b004SRick Macklem 	case NFSV4LOCKT_WRITEW:
26449ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
26459ec7b004SRick Macklem 	case NFSV4LOCKT_WRITE:
26469ec7b004SRick Macklem 		break;
26479ec7b004SRick Macklem 	default:
26489ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
26492a45247cSRick Macklem 		free(stp, M_NFSDSTATE);
26502a45247cSRick Macklem 		free(lop, M_NFSDLOCK);
26519ec7b004SRick Macklem 		goto nfsmout;
265274b8d63dSPedro F. Giffuni 	}
26539ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
26549ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
26559ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(int, *tl++);
26569ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
26579ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
26589ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
26599ec7b004SRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
266090d2dfabSRick Macklem 
266190d2dfabSRick Macklem 	/*
266290d2dfabSRick Macklem 	 * For the special stateid of other all 0s and seqid == 1, set the
266390d2dfabSRick Macklem 	 * stateid to the current stateid, if it is set.
266490d2dfabSRick Macklem 	 */
266590d2dfabSRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
266690d2dfabSRick Macklem 	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
266790d2dfabSRick Macklem 	    stp->ls_stateid.other[2] == 0) {
266890d2dfabSRick Macklem 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
266990d2dfabSRick Macklem 			stp->ls_stateid = nd->nd_curstateid;
267090d2dfabSRick Macklem 			stp->ls_stateid.seqid = 0;
267190d2dfabSRick Macklem 		} else {
267290d2dfabSRick Macklem 			nd->nd_repstat = NFSERR_BADSTATEID;
267390d2dfabSRick Macklem 			goto nfsmout;
267490d2dfabSRick Macklem 		}
267590d2dfabSRick Macklem 	}
267690d2dfabSRick Macklem 
26779ec7b004SRick Macklem 	lop->lo_first = fxdr_hyper(tl);
26789ec7b004SRick Macklem 	tl += 2;
26799ec7b004SRick Macklem 	len = fxdr_hyper(tl);
26809ec7b004SRick Macklem 	if (len == NFS64BITSSET) {
26819ec7b004SRick Macklem 		lop->lo_end = NFS64BITSSET;
26829ec7b004SRick Macklem 	} else {
26839ec7b004SRick Macklem 		lop->lo_end = lop->lo_first + len;
26849ec7b004SRick Macklem 		if (lop->lo_end <= lop->lo_first)
26859ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
26869ec7b004SRick Macklem 	}
26879ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
26889ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
2689c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2690c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2691c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
2692c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
2693c59e4cc3SRick Macklem 			printf("EEK6 multiple clids\n");
26949ec7b004SRick Macklem 	} else {
2695c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2696c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
26979ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
26989ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
26999ec7b004SRick Macklem 	}
27009ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
27019ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
27029ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
27039ec7b004SRick Macklem 	    else
27049ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
27059ec7b004SRick Macklem 	}
27069ec7b004SRick Macklem 	/*
27079ec7b004SRick Macklem 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
27089ec7b004SRick Macklem 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
27099ec7b004SRick Macklem 	 * value of nd_repstat, if it gets that far.
27109ec7b004SRick Macklem 	 */
27119ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
27129ec7b004SRick Macklem 	    &stateid, exp, nd, p);
27139ec7b004SRick Macklem 	if (stp)
2714222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
27159ec7b004SRick Macklem 	if (lop)
2716222daa42SConrad Meyer 		free(lop, M_NFSDLOCK);
27179ec7b004SRick Macklem 	if (!nd->nd_repstat) {
27189ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
27199ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
27209ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
27219ec7b004SRick Macklem 	}
27229ec7b004SRick Macklem nfsmout:
27239ec7b004SRick Macklem 	vput(vp);
2724a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
27259ec7b004SRick Macklem 	return (error);
27269ec7b004SRick Macklem }
27279ec7b004SRick Macklem 
27289ec7b004SRick Macklem /*
27299ec7b004SRick Macklem  * nfsv4 open service
27309ec7b004SRick Macklem  */
27319ec7b004SRick Macklem APPLESTATIC int
27329ec7b004SRick Macklem nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2733af444b18SEdward Tomasz Napierala     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
27349ec7b004SRick Macklem {
27359ec7b004SRick Macklem 	u_int32_t *tl;
2736c59e4cc3SRick Macklem 	int i, retext;
27379ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
27389ec7b004SRick Macklem 	int error = 0, create, claim, exclusive_flag = 0;
27399ec7b004SRick Macklem 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
27409ec7b004SRick Macklem 	int how = NFSCREATE_UNCHECKED;
2741086f6e0cSRick Macklem 	int32_t cverf[2], tverf[2] = { 0, 0 };
27429ec7b004SRick Macklem 	vnode_t vp = NULL, dirp = NULL;
27439ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
27449ec7b004SRick Macklem 	struct nameidata named;
27459ec7b004SRick Macklem 	nfsv4stateid_t stateid, delegstateid;
27469ec7b004SRick Macklem 	nfsattrbit_t attrbits;
27479ec7b004SRick Macklem 	nfsquad_t clientid;
27489ec7b004SRick Macklem 	char *bufp = NULL;
27499ec7b004SRick Macklem 	u_long *hashp;
27509ec7b004SRick Macklem 	NFSACL_T *aclp = NULL;
2751af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
27529ec7b004SRick Macklem 
27539ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
2754c3e22f83SRick Macklem 	aclp = acl_alloc(M_WAITOK);
27559ec7b004SRick Macklem 	aclp->acl_cnt = 0;
27569ec7b004SRick Macklem #endif
27579ec7b004SRick Macklem 	NFSZERO_ATTRBIT(&attrbits);
27589ec7b004SRick Macklem 	named.ni_startdir = NULL;
27599ec7b004SRick Macklem 	named.ni_cnd.cn_nameiop = 0;
27609ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
27619ec7b004SRick Macklem 	i = fxdr_unsigned(int, *(tl + 5));
27622a45247cSRick Macklem 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
27632a45247cSRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
2764a9285ae5SZack Kirsch 		goto nfsmout;
27652a45247cSRick Macklem 	}
2766222daa42SConrad Meyer 	stp = malloc(sizeof (struct nfsstate) + i,
27679ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
27689ec7b004SRick Macklem 	stp->ls_ownerlen = i;
27699ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
27709ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_OPEN;
27719ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
27729ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
27739ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
2774c59e4cc3SRick Macklem 	retext = 0;
2775c59e4cc3SRick Macklem 	if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2776c59e4cc3SRick Macklem 	    NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2777c59e4cc3SRick Macklem 		retext = 1;
2778c59e4cc3SRick Macklem 		/* For now, ignore these. */
2779c59e4cc3SRick Macklem 		i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2780c59e4cc3SRick Macklem 		switch (i & NFSV4OPEN_WANTDELEGMASK) {
2781c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTANYDELEG:
2782c59e4cc3SRick Macklem 			stp->ls_flags |= (NFSLCK_WANTRDELEG |
2783c59e4cc3SRick Macklem 			    NFSLCK_WANTWDELEG);
2784c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2785c59e4cc3SRick Macklem 			break;
2786c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTREADDELEG:
2787c59e4cc3SRick Macklem 			stp->ls_flags |= NFSLCK_WANTRDELEG;
2788c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2789c59e4cc3SRick Macklem 			break;
2790c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTWRITEDELEG:
2791c59e4cc3SRick Macklem 			stp->ls_flags |= NFSLCK_WANTWDELEG;
2792c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2793c59e4cc3SRick Macklem 			break;
2794c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTNODELEG:
2795c59e4cc3SRick Macklem 			stp->ls_flags |= NFSLCK_WANTNODELEG;
2796c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2797c59e4cc3SRick Macklem 			break;
2798c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTCANCEL:
2799c59e4cc3SRick Macklem 			printf("NFSv4: ignore Open WantCancel\n");
2800c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2801c59e4cc3SRick Macklem 			break;
2802c59e4cc3SRick Macklem 		default:
2803c59e4cc3SRick Macklem 			/* nd_repstat will be set to NFSERR_INVAL below. */
2804c59e4cc3SRick Macklem 			break;
280574b8d63dSPedro F. Giffuni 		}
2806c59e4cc3SRick Macklem 	}
28079ec7b004SRick Macklem 	switch (i) {
28089ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSREAD:
28099ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_READACCESS;
28109ec7b004SRick Macklem 		break;
28119ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSWRITE:
28129ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_WRITEACCESS;
28139ec7b004SRick Macklem 		break;
28149ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSBOTH:
28159ec7b004SRick Macklem 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
28169ec7b004SRick Macklem 		break;
28179ec7b004SRick Macklem 	default:
28189ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
281974b8d63dSPedro F. Giffuni 	}
28209ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
28219ec7b004SRick Macklem 	switch (i) {
28229ec7b004SRick Macklem 	case NFSV4OPEN_DENYNONE:
28239ec7b004SRick Macklem 		break;
28249ec7b004SRick Macklem 	case NFSV4OPEN_DENYREAD:
28259ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_READDENY;
28269ec7b004SRick Macklem 		break;
28279ec7b004SRick Macklem 	case NFSV4OPEN_DENYWRITE:
28289ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_WRITEDENY;
28299ec7b004SRick Macklem 		break;
28309ec7b004SRick Macklem 	case NFSV4OPEN_DENYBOTH:
28319ec7b004SRick Macklem 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
28329ec7b004SRick Macklem 		break;
28339ec7b004SRick Macklem 	default:
28349ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
283574b8d63dSPedro F. Giffuni 	}
28369ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
28379ec7b004SRick Macklem 	clientid.lval[1] = *tl;
2838c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2839c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2840c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
2841c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
2842c59e4cc3SRick Macklem 			printf("EEK7 multiple clids\n");
28439ec7b004SRick Macklem 	} else {
2844c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2845c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
28469ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
28479ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
28489ec7b004SRick Macklem 	}
28499ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2850a9285ae5SZack Kirsch 	if (error)
2851a9285ae5SZack Kirsch 		goto nfsmout;
28529ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
28539ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
28549ec7b004SRick Macklem 	create = fxdr_unsigned(int, *tl);
28559ec7b004SRick Macklem 	if (!nd->nd_repstat)
285690d2dfabSRick Macklem 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
28579ec7b004SRick Macklem 	if (create == NFSV4OPEN_CREATE) {
28589ec7b004SRick Macklem 		nva.na_type = VREG;
28599ec7b004SRick Macklem 		nva.na_mode = 0;
28609ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
28619ec7b004SRick Macklem 		how = fxdr_unsigned(int, *tl);
28629ec7b004SRick Macklem 		switch (how) {
28639ec7b004SRick Macklem 		case NFSCREATE_UNCHECKED:
28649ec7b004SRick Macklem 		case NFSCREATE_GUARDED:
2865d8a5961fSMarcelo Araujo 			error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2866a9285ae5SZack Kirsch 			if (error)
2867a9285ae5SZack Kirsch 				goto nfsmout;
28689ec7b004SRick Macklem 			/*
28699ec7b004SRick Macklem 			 * If the na_gid being set is the same as that of
28709ec7b004SRick Macklem 			 * the directory it is going in, clear it, since
28719ec7b004SRick Macklem 			 * that is what will be set by default. This allows
28729ec7b004SRick Macklem 			 * a user that isn't in that group to do the create.
28739ec7b004SRick Macklem 			 */
28749ec7b004SRick Macklem 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
28759ec7b004SRick Macklem 			    nva.na_gid == dirfor.na_gid)
28769ec7b004SRick Macklem 				NFSVNO_UNSET(&nva, gid);
28779ec7b004SRick Macklem 			if (!nd->nd_repstat)
28789ec7b004SRick Macklem 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
28799ec7b004SRick Macklem 			break;
28809ec7b004SRick Macklem 		case NFSCREATE_EXCLUSIVE:
28819ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2882086f6e0cSRick Macklem 			cverf[0] = *tl++;
2883086f6e0cSRick Macklem 			cverf[1] = *tl;
28849ec7b004SRick Macklem 			break;
2885c59e4cc3SRick Macklem 		case NFSCREATE_EXCLUSIVE41:
2886c59e4cc3SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2887c59e4cc3SRick Macklem 			cverf[0] = *tl++;
2888c59e4cc3SRick Macklem 			cverf[1] = *tl;
2889*b4645807SRick Macklem 			error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2890c59e4cc3SRick Macklem 			if (error != 0)
2891c59e4cc3SRick Macklem 				goto nfsmout;
2892c59e4cc3SRick Macklem 			if (NFSISSET_ATTRBIT(&attrbits,
2893c59e4cc3SRick Macklem 			    NFSATTRBIT_TIMEACCESSSET))
2894c59e4cc3SRick Macklem 				nd->nd_repstat = NFSERR_INVAL;
2895c59e4cc3SRick Macklem 			/*
2896c59e4cc3SRick Macklem 			 * If the na_gid being set is the same as that of
2897c59e4cc3SRick Macklem 			 * the directory it is going in, clear it, since
2898c59e4cc3SRick Macklem 			 * that is what will be set by default. This allows
2899c59e4cc3SRick Macklem 			 * a user that isn't in that group to do the create.
2900c59e4cc3SRick Macklem 			 */
2901c59e4cc3SRick Macklem 			if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2902c59e4cc3SRick Macklem 			    nva.na_gid == dirfor.na_gid)
2903c59e4cc3SRick Macklem 				NFSVNO_UNSET(&nva, gid);
2904c59e4cc3SRick Macklem 			if (nd->nd_repstat == 0)
2905c59e4cc3SRick Macklem 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2906c59e4cc3SRick Macklem 			break;
29079ec7b004SRick Macklem 		default:
29089ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_BADXDR;
2909a9285ae5SZack Kirsch 			goto nfsmout;
291074b8d63dSPedro F. Giffuni 		}
29119ec7b004SRick Macklem 	} else if (create != NFSV4OPEN_NOCREATE) {
29129ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
2913a9285ae5SZack Kirsch 		goto nfsmout;
29149ec7b004SRick Macklem 	}
29159ec7b004SRick Macklem 
29169ec7b004SRick Macklem 	/*
29179ec7b004SRick Macklem 	 * Now, handle the claim, which usually includes looking up a
29189ec7b004SRick Macklem 	 * name in the directory referenced by dp. The exception is
29199ec7b004SRick Macklem 	 * NFSV4OPEN_CLAIMPREVIOUS.
29209ec7b004SRick Macklem 	 */
29219ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
29229ec7b004SRick Macklem 	claim = fxdr_unsigned(int, *tl);
29239ec7b004SRick Macklem 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
29249ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
29259ec7b004SRick Macklem 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
29269ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
29279ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_DELEGCUR;
29289ec7b004SRick Macklem 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
29299ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_DELEGPREV;
29309ec7b004SRick Macklem 	}
29319ec7b004SRick Macklem 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
29329ec7b004SRick Macklem 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
29339ec7b004SRick Macklem 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
29349ec7b004SRick Macklem 		    claim != NFSV4OPEN_CLAIMNULL)
29359ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
29369ec7b004SRick Macklem 		if (nd->nd_repstat) {
29379ec7b004SRick Macklem 			nd->nd_repstat = nfsrv_opencheck(clientid,
29389ec7b004SRick Macklem 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
2939a9285ae5SZack Kirsch 			goto nfsmout;
29409ec7b004SRick Macklem 		}
29419ec7b004SRick Macklem 		if (create == NFSV4OPEN_CREATE)
29429ec7b004SRick Macklem 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
29436c21f6edSKonstantin Belousov 			LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
29449ec7b004SRick Macklem 		else
29459ec7b004SRick Macklem 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
29469ec7b004SRick Macklem 			LOCKLEAF | SAVESTART);
29479ec7b004SRick Macklem 		nfsvno_setpathbuf(&named, &bufp, &hashp);
29489ec7b004SRick Macklem 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
29499ec7b004SRick Macklem 		if (error) {
29509ec7b004SRick Macklem 			vrele(dp);
29519ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
29529ec7b004SRick Macklem 			acl_free(aclp);
29539ec7b004SRick Macklem #endif
2954222daa42SConrad Meyer 			free(stp, M_NFSDSTATE);
29559ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
2956a9285ae5SZack Kirsch 			NFSEXITCODE2(error, nd);
29579ec7b004SRick Macklem 			return (error);
29589ec7b004SRick Macklem 		}
29599ec7b004SRick Macklem 		if (!nd->nd_repstat) {
29609ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
29619ec7b004SRick Macklem 			    p, &dirp);
29629ec7b004SRick Macklem 		} else {
29639ec7b004SRick Macklem 			vrele(dp);
29649ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
29659ec7b004SRick Macklem 		}
29669ec7b004SRick Macklem 		if (create == NFSV4OPEN_CREATE) {
29679ec7b004SRick Macklem 		    switch (how) {
29689ec7b004SRick Macklem 		    case NFSCREATE_UNCHECKED:
29699ec7b004SRick Macklem 			if (named.ni_vp) {
29709ec7b004SRick Macklem 				/*
29719ec7b004SRick Macklem 				 * Clear the setable attribute bits, except
29729ec7b004SRick Macklem 				 * for Size, if it is being truncated.
29739ec7b004SRick Macklem 				 */
29749ec7b004SRick Macklem 				NFSZERO_ATTRBIT(&attrbits);
29759ec7b004SRick Macklem 				if (NFSVNO_ISSETSIZE(&nva))
29769ec7b004SRick Macklem 					NFSSETBIT_ATTRBIT(&attrbits,
29779ec7b004SRick Macklem 					    NFSATTRBIT_SIZE);
29789ec7b004SRick Macklem 			}
29799ec7b004SRick Macklem 			break;
29809ec7b004SRick Macklem 		    case NFSCREATE_GUARDED:
29819ec7b004SRick Macklem 			if (named.ni_vp && !nd->nd_repstat)
29829ec7b004SRick Macklem 				nd->nd_repstat = EEXIST;
29839ec7b004SRick Macklem 			break;
29849ec7b004SRick Macklem 		    case NFSCREATE_EXCLUSIVE:
29859ec7b004SRick Macklem 			exclusive_flag = 1;
29869ec7b004SRick Macklem 			if (!named.ni_vp)
29879ec7b004SRick Macklem 				nva.na_mode = 0;
2988c59e4cc3SRick Macklem 			break;
2989c59e4cc3SRick Macklem 		    case NFSCREATE_EXCLUSIVE41:
2990c59e4cc3SRick Macklem 			exclusive_flag = 1;
2991c59e4cc3SRick Macklem 			break;
299274b8d63dSPedro F. Giffuni 		    }
29939ec7b004SRick Macklem 		}
29949ec7b004SRick Macklem 		nfsvno_open(nd, &named, clientid, &stateid, stp,
29959ec7b004SRick Macklem 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
299601c27978SEdward Tomasz Napierala 		    nd->nd_cred, exp, &vp);
2997c59e4cc3SRick Macklem 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
2998c59e4cc3SRick Macklem 	    NFSV4OPEN_CLAIMFH) {
2999c59e4cc3SRick Macklem 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
30009ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
30019ec7b004SRick Macklem 			i = fxdr_unsigned(int, *tl);
30029ec7b004SRick Macklem 			switch (i) {
30039ec7b004SRick Macklem 			case NFSV4OPEN_DELEGATEREAD:
30049ec7b004SRick Macklem 				stp->ls_flags |= NFSLCK_DELEGREAD;
30059ec7b004SRick Macklem 				break;
30069ec7b004SRick Macklem 			case NFSV4OPEN_DELEGATEWRITE:
30079ec7b004SRick Macklem 				stp->ls_flags |= NFSLCK_DELEGWRITE;
30089ec7b004SRick Macklem 			case NFSV4OPEN_DELEGATENONE:
30099ec7b004SRick Macklem 				break;
30109ec7b004SRick Macklem 			default:
30119ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_BADXDR;
3012a9285ae5SZack Kirsch 				goto nfsmout;
301374b8d63dSPedro F. Giffuni 			}
30149ec7b004SRick Macklem 			stp->ls_flags |= NFSLCK_RECLAIM;
3015c59e4cc3SRick Macklem 		} else {
3016c59e4cc3SRick Macklem 			/* CLAIM_NULL_FH */
3017c59e4cc3SRick Macklem 			if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3018c59e4cc3SRick Macklem 				nd->nd_repstat = NFSERR_INVAL;
3019c59e4cc3SRick Macklem 		}
30209ec7b004SRick Macklem 		vp = dp;
302198f234f3SZack Kirsch 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3022629fa50eSRick Macklem 		if ((vp->v_iflag & VI_DOOMED) == 0)
3023629fa50eSRick Macklem 			nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3024629fa50eSRick Macklem 			    stp, vp, nd, p, nd->nd_repstat);
3025629fa50eSRick Macklem 		else
3026629fa50eSRick Macklem 			nd->nd_repstat = NFSERR_PERM;
30279ec7b004SRick Macklem 	} else {
30289ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
3029a9285ae5SZack Kirsch 		goto nfsmout;
30309ec7b004SRick Macklem 	}
30319ec7b004SRick Macklem 
30329ec7b004SRick Macklem 	/*
30339ec7b004SRick Macklem 	 * Do basic access checking.
30349ec7b004SRick Macklem 	 */
30359ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
3036de67b496SRick Macklem 		/*
3037de67b496SRick Macklem 		 * The IETF working group decided that this is the correct
3038de67b496SRick Macklem 		 * error return for all non-regular files.
3039de67b496SRick Macklem 		 */
3040d8a5961fSMarcelo Araujo 		nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
30419ec7b004SRick Macklem 	}
30429ec7b004SRick Macklem 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
30438da45f2cSRick Macklem 	    nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
30448da45f2cSRick Macklem 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
30459ec7b004SRick Macklem 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
30468da45f2cSRick Macklem 	    nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
30478da45f2cSRick Macklem 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
30489ec7b004SRick Macklem 	    if (nd->nd_repstat)
30498da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
30509ec7b004SRick Macklem 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
30518da45f2cSRick Macklem 		    NFSACCCHK_VPISLOCKED, NULL);
30529ec7b004SRick Macklem 	}
30539ec7b004SRick Macklem 
3054086f6e0cSRick Macklem 	if (!nd->nd_repstat) {
305590d2dfabSRick Macklem 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3056086f6e0cSRick Macklem 		if (!nd->nd_repstat) {
3057086f6e0cSRick Macklem 			tverf[0] = nva.na_atime.tv_sec;
3058086f6e0cSRick Macklem 			tverf[1] = nva.na_atime.tv_nsec;
3059086f6e0cSRick Macklem 		}
3060086f6e0cSRick Macklem 	}
3061086f6e0cSRick Macklem 	if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3062086f6e0cSRick Macklem 	    cverf[1] != tverf[1]))
30639ec7b004SRick Macklem 		nd->nd_repstat = EEXIST;
30649ec7b004SRick Macklem 	/*
30659ec7b004SRick Macklem 	 * Do the open locking/delegation stuff.
30669ec7b004SRick Macklem 	 */
30679ec7b004SRick Macklem 	if (!nd->nd_repstat)
30689ec7b004SRick Macklem 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
30699ec7b004SRick Macklem 		&delegstateid, &rflags, exp, p, nva.na_filerev);
30709ec7b004SRick Macklem 
30719ec7b004SRick Macklem 	/*
30729ec7b004SRick Macklem 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
30739ec7b004SRick Macklem 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
30749ec7b004SRick Macklem 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
30759ec7b004SRick Macklem 	 */
30769ec7b004SRick Macklem 	if (vp)
3077c383087cSZack Kirsch 		NFSVOPUNLOCK(vp, 0);
30789ec7b004SRick Macklem 	if (stp)
3079222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
30809ec7b004SRick Macklem 	if (!nd->nd_repstat && dirp)
308190d2dfabSRick Macklem 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
30829ec7b004SRick Macklem 	if (!nd->nd_repstat) {
308390d2dfabSRick Macklem 		/* For NFSv4.1, set the Current StateID. */
308490d2dfabSRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0) {
308590d2dfabSRick Macklem 			nd->nd_curstateid = stateid;
308690d2dfabSRick Macklem 			nd->nd_flag |= ND_CURSTATEID;
308790d2dfabSRick Macklem 		}
30889ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
30899ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
30909ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
30919ec7b004SRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
30929ec7b004SRick Macklem 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
30939ec7b004SRick Macklem 			*tl++ = newnfs_true;
30949ec7b004SRick Macklem 			*tl++ = 0;
30959ec7b004SRick Macklem 			*tl++ = 0;
30969ec7b004SRick Macklem 			*tl++ = 0;
30979ec7b004SRick Macklem 			*tl++ = 0;
30989ec7b004SRick Macklem 		} else {
30999ec7b004SRick Macklem 			*tl++ = newnfs_false;	/* Since dirp is not locked */
31009ec7b004SRick Macklem 			txdr_hyper(dirfor.na_filerev, tl);
31019ec7b004SRick Macklem 			tl += 2;
31029ec7b004SRick Macklem 			txdr_hyper(diraft.na_filerev, tl);
31039ec7b004SRick Macklem 			tl += 2;
31049ec7b004SRick Macklem 		}
31059ec7b004SRick Macklem 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
31069ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, &attrbits);
31079ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
31089ec7b004SRick Macklem 		if (rflags & NFSV4OPEN_READDELEGATE)
31099ec7b004SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
31109ec7b004SRick Macklem 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
31119ec7b004SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3112c59e4cc3SRick Macklem 		else if (retext != 0) {
3113c59e4cc3SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
31145d54f186SRick Macklem 			if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
31155d54f186SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
31165d54f186SRick Macklem 				*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
31175d54f186SRick Macklem 			} else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
31185d54f186SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
31195d54f186SRick Macklem 				*tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
31205d54f186SRick Macklem 			} else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3121c59e4cc3SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3122c59e4cc3SRick Macklem 				*tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3123c59e4cc3SRick Macklem 				*tl = newnfs_false;
3124c59e4cc3SRick Macklem 			} else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3125c59e4cc3SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3126c59e4cc3SRick Macklem 				*tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3127c59e4cc3SRick Macklem 				*tl = newnfs_false;
3128c59e4cc3SRick Macklem 			} else {
3129c59e4cc3SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3130c59e4cc3SRick Macklem 				*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3131c59e4cc3SRick Macklem 			}
3132c59e4cc3SRick Macklem 		} else
31339ec7b004SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
31349ec7b004SRick Macklem 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
31359ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
31369ec7b004SRick Macklem 			*tl++ = txdr_unsigned(delegstateid.seqid);
31379ec7b004SRick Macklem 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
31389ec7b004SRick Macklem 			    NFSX_STATEIDOTHER);
31399ec7b004SRick Macklem 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
31409ec7b004SRick Macklem 			if (rflags & NFSV4OPEN_RECALL)
31419ec7b004SRick Macklem 				*tl = newnfs_true;
31429ec7b004SRick Macklem 			else
31439ec7b004SRick Macklem 				*tl = newnfs_false;
31449ec7b004SRick Macklem 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
31459ec7b004SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
31469ec7b004SRick Macklem 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
31479ec7b004SRick Macklem 				txdr_hyper(nva.na_size, tl);
31489ec7b004SRick Macklem 			}
31499ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
31509ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
31519ec7b004SRick Macklem 			*tl++ = txdr_unsigned(0x0);
31529ec7b004SRick Macklem 			acemask = NFSV4ACE_ALLFILESMASK;
31539ec7b004SRick Macklem 			if (nva.na_mode & S_IRUSR)
31549ec7b004SRick Macklem 			    acemask |= NFSV4ACE_READMASK;
31559ec7b004SRick Macklem 			if (nva.na_mode & S_IWUSR)
31569ec7b004SRick Macklem 			    acemask |= NFSV4ACE_WRITEMASK;
31579ec7b004SRick Macklem 			if (nva.na_mode & S_IXUSR)
31589ec7b004SRick Macklem 			    acemask |= NFSV4ACE_EXECUTEMASK;
31599ec7b004SRick Macklem 			*tl = txdr_unsigned(acemask);
31609ec7b004SRick Macklem 			(void) nfsm_strtom(nd, "OWNER@", 6);
31619ec7b004SRick Macklem 		}
31629ec7b004SRick Macklem 		*vpp = vp;
31639ec7b004SRick Macklem 	} else if (vp) {
31649ec7b004SRick Macklem 		vrele(vp);
31659ec7b004SRick Macklem 	}
31669ec7b004SRick Macklem 	if (dirp)
31679ec7b004SRick Macklem 		vrele(dirp);
31689ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
31699ec7b004SRick Macklem 	acl_free(aclp);
31709ec7b004SRick Macklem #endif
3171a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
31729ec7b004SRick Macklem 	return (0);
31739ec7b004SRick Macklem nfsmout:
31749ec7b004SRick Macklem 	vrele(dp);
31759ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
31769ec7b004SRick Macklem 	acl_free(aclp);
31779ec7b004SRick Macklem #endif
31789ec7b004SRick Macklem 	if (stp)
3179222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
3180a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
31819ec7b004SRick Macklem 	return (error);
31829ec7b004SRick Macklem }
31839ec7b004SRick Macklem 
31849ec7b004SRick Macklem /*
31859ec7b004SRick Macklem  * nfsv4 close service
31869ec7b004SRick Macklem  */
31879ec7b004SRick Macklem APPLESTATIC int
31889ec7b004SRick Macklem nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3189af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
31909ec7b004SRick Macklem {
31919ec7b004SRick Macklem 	u_int32_t *tl;
31929ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
319390d2dfabSRick Macklem 	int error = 0, writeacc;
31949ec7b004SRick Macklem 	nfsv4stateid_t stateid;
31959ec7b004SRick Macklem 	nfsquad_t clientid;
319690d2dfabSRick Macklem 	struct nfsvattr na;
3197af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
31989ec7b004SRick Macklem 
31999ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
32009ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
32019ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
32029ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
32039ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
32049ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
32059ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
32069ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
320790d2dfabSRick Macklem 
320890d2dfabSRick Macklem 	/*
320990d2dfabSRick Macklem 	 * For the special stateid of other all 0s and seqid == 1, set the
321090d2dfabSRick Macklem 	 * stateid to the current stateid, if it is set.
321190d2dfabSRick Macklem 	 */
321290d2dfabSRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
321390d2dfabSRick Macklem 	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
321490d2dfabSRick Macklem 	    stp->ls_stateid.other[2] == 0) {
321590d2dfabSRick Macklem 		if ((nd->nd_flag & ND_CURSTATEID) != 0)
321690d2dfabSRick Macklem 			stp->ls_stateid = nd->nd_curstateid;
321790d2dfabSRick Macklem 		else {
321890d2dfabSRick Macklem 			nd->nd_repstat = NFSERR_BADSTATEID;
321990d2dfabSRick Macklem 			goto nfsmout;
322090d2dfabSRick Macklem 		}
322190d2dfabSRick Macklem 	}
322290d2dfabSRick Macklem 
32239ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_CLOSE;
32249ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
32259ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
3226c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3227c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3228c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3229c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3230c59e4cc3SRick Macklem 			printf("EEK8 multiple clids\n");
32319ec7b004SRick Macklem 	} else {
3232c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3233c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
32349ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
32359ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
32369ec7b004SRick Macklem 	}
323790d2dfabSRick Macklem 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
323890d2dfabSRick Macklem 	    &writeacc);
323990d2dfabSRick Macklem 	/* For pNFS, update the attributes. */
324090d2dfabSRick Macklem 	if (writeacc != 0 || nfsrv_pnfsatime != 0)
324190d2dfabSRick Macklem 		nfsrv_updatemdsattr(vp, &na, p);
32429ec7b004SRick Macklem 	vput(vp);
32439ec7b004SRick Macklem 	if (!nd->nd_repstat) {
324490d2dfabSRick Macklem 		/*
324590d2dfabSRick Macklem 		 * If the stateid that has been closed is the current stateid,
324690d2dfabSRick Macklem 		 * unset it.
324790d2dfabSRick Macklem 		 */
324890d2dfabSRick Macklem 		if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
324990d2dfabSRick Macklem 		    stateid.other[0] == nd->nd_curstateid.other[0] &&
325090d2dfabSRick Macklem 		    stateid.other[1] == nd->nd_curstateid.other[1] &&
325190d2dfabSRick Macklem 		    stateid.other[2] == nd->nd_curstateid.other[2])
325290d2dfabSRick Macklem 			nd->nd_flag &= ~ND_CURSTATEID;
32539ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
32549ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
32559ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
32569ec7b004SRick Macklem 	}
3257a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
32589ec7b004SRick Macklem 	return (0);
32599ec7b004SRick Macklem nfsmout:
32609ec7b004SRick Macklem 	vput(vp);
3261a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
32629ec7b004SRick Macklem 	return (error);
32639ec7b004SRick Macklem }
32649ec7b004SRick Macklem 
32659ec7b004SRick Macklem /*
32669ec7b004SRick Macklem  * nfsv4 delegpurge service
32679ec7b004SRick Macklem  */
32689ec7b004SRick Macklem APPLESTATIC int
32699ec7b004SRick Macklem nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3270af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
32719ec7b004SRick Macklem {
32729ec7b004SRick Macklem 	u_int32_t *tl;
32739ec7b004SRick Macklem 	int error = 0;
32749ec7b004SRick Macklem 	nfsquad_t clientid;
3275af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
32769ec7b004SRick Macklem 
3277c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3278b1cfc0d9SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3279a9285ae5SZack Kirsch 		goto nfsmout;
3280b1cfc0d9SRick Macklem 	}
32819ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
32829ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
32839ec7b004SRick Macklem 	clientid.lval[1] = *tl;
3284c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3285c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3286c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3287c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3288c59e4cc3SRick Macklem 			printf("EEK9 multiple clids\n");
32899ec7b004SRick Macklem 	} else {
3290c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3291c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
32929ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
32939ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
32949ec7b004SRick Macklem 	}
3295c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
329690d2dfabSRick Macklem 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
32979ec7b004SRick Macklem nfsmout:
3298a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
32999ec7b004SRick Macklem 	return (error);
33009ec7b004SRick Macklem }
33019ec7b004SRick Macklem 
33029ec7b004SRick Macklem /*
33039ec7b004SRick Macklem  * nfsv4 delegreturn service
33049ec7b004SRick Macklem  */
33059ec7b004SRick Macklem APPLESTATIC int
33069ec7b004SRick Macklem nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3307af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
33089ec7b004SRick Macklem {
33099ec7b004SRick Macklem 	u_int32_t *tl;
331090d2dfabSRick Macklem 	int error = 0, writeacc;
33119ec7b004SRick Macklem 	nfsv4stateid_t stateid;
33129ec7b004SRick Macklem 	nfsquad_t clientid;
331390d2dfabSRick Macklem 	struct nfsvattr na;
3314af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
33159ec7b004SRick Macklem 
33169ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
33179ec7b004SRick Macklem 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
33189ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
33199ec7b004SRick Macklem 	clientid.lval[0] = stateid.other[0];
33209ec7b004SRick Macklem 	clientid.lval[1] = stateid.other[1];
3321c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3322c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3323c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3324c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3325c59e4cc3SRick Macklem 			printf("EEK10 multiple clids\n");
33269ec7b004SRick Macklem 	} else {
3327c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3328c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
33299ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
33309ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
33319ec7b004SRick Macklem 	}
3332c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
333390d2dfabSRick Macklem 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
333490d2dfabSRick Macklem 	/* For pNFS, update the attributes. */
333590d2dfabSRick Macklem 	if (writeacc != 0 || nfsrv_pnfsatime != 0)
333690d2dfabSRick Macklem 		nfsrv_updatemdsattr(vp, &na, p);
33379ec7b004SRick Macklem nfsmout:
33389ec7b004SRick Macklem 	vput(vp);
3339a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
33409ec7b004SRick Macklem 	return (error);
33419ec7b004SRick Macklem }
33429ec7b004SRick Macklem 
33439ec7b004SRick Macklem /*
33449ec7b004SRick Macklem  * nfsv4 get file handle service
33459ec7b004SRick Macklem  */
33469ec7b004SRick Macklem APPLESTATIC int
33479ec7b004SRick Macklem nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3348af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
33499ec7b004SRick Macklem {
33509ec7b004SRick Macklem 	fhandle_t fh;
3351af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
33529ec7b004SRick Macklem 
33539ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
33549ec7b004SRick Macklem 	vput(vp);
33559ec7b004SRick Macklem 	if (!nd->nd_repstat)
33569ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3357a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
33589ec7b004SRick Macklem 	return (0);
33599ec7b004SRick Macklem }
33609ec7b004SRick Macklem 
33619ec7b004SRick Macklem /*
33629ec7b004SRick Macklem  * nfsv4 open confirm service
33639ec7b004SRick Macklem  */
33649ec7b004SRick Macklem APPLESTATIC int
33659ec7b004SRick Macklem nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3366af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
33679ec7b004SRick Macklem {
33689ec7b004SRick Macklem 	u_int32_t *tl;
33699ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
33709ec7b004SRick Macklem 	int error = 0;
33719ec7b004SRick Macklem 	nfsv4stateid_t stateid;
33729ec7b004SRick Macklem 	nfsquad_t clientid;
3373af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
33749ec7b004SRick Macklem 
3375c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3376c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3377c59e4cc3SRick Macklem 		goto nfsmout;
3378c59e4cc3SRick Macklem 	}
33799ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
33809ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
33819ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
33829ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
33839ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
33849ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
33859ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
33869ec7b004SRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
33879ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
33889ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_CONFIRM;
33899ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
33909ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
3391c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3392c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3393c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3394c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3395c59e4cc3SRick Macklem 			printf("EEK11 multiple clids\n");
33969ec7b004SRick Macklem 	} else {
3397c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3398c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
33999ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
34009ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
34019ec7b004SRick Macklem 	}
340290d2dfabSRick Macklem 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
340390d2dfabSRick Macklem 	    NULL);
34049ec7b004SRick Macklem 	if (!nd->nd_repstat) {
34059ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
34069ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
34079ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
34089ec7b004SRick Macklem 	}
34099ec7b004SRick Macklem nfsmout:
34109ec7b004SRick Macklem 	vput(vp);
3411a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
34129ec7b004SRick Macklem 	return (error);
34139ec7b004SRick Macklem }
34149ec7b004SRick Macklem 
34159ec7b004SRick Macklem /*
34169ec7b004SRick Macklem  * nfsv4 open downgrade service
34179ec7b004SRick Macklem  */
34189ec7b004SRick Macklem APPLESTATIC int
34199ec7b004SRick Macklem nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3420af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
34219ec7b004SRick Macklem {
34229ec7b004SRick Macklem 	u_int32_t *tl;
34239ec7b004SRick Macklem 	int i;
34249ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
34259ec7b004SRick Macklem 	int error = 0;
34269ec7b004SRick Macklem 	nfsv4stateid_t stateid;
34279ec7b004SRick Macklem 	nfsquad_t clientid;
3428af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
34299ec7b004SRick Macklem 
3430d8a5961fSMarcelo Araujo 	/* opendowngrade can only work on a file object.*/
3431d8a5961fSMarcelo Araujo 	if (vp->v_type != VREG) {
3432d8a5961fSMarcelo Araujo 		error = NFSERR_INVAL;
3433d8a5961fSMarcelo Araujo 		goto nfsmout;
3434d8a5961fSMarcelo Araujo 	}
34359ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
34369ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
34379ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
34389ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
34399ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
34409ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
34419ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
34429ec7b004SRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
344390d2dfabSRick Macklem 
344490d2dfabSRick Macklem 	/*
344590d2dfabSRick Macklem 	 * For the special stateid of other all 0s and seqid == 1, set the
344690d2dfabSRick Macklem 	 * stateid to the current stateid, if it is set.
344790d2dfabSRick Macklem 	 */
344890d2dfabSRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
344990d2dfabSRick Macklem 	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
345090d2dfabSRick Macklem 	    stp->ls_stateid.other[2] == 0) {
345190d2dfabSRick Macklem 		if ((nd->nd_flag & ND_CURSTATEID) != 0)
345290d2dfabSRick Macklem 			stp->ls_stateid = nd->nd_curstateid;
345390d2dfabSRick Macklem 		else {
345490d2dfabSRick Macklem 			nd->nd_repstat = NFSERR_BADSTATEID;
345590d2dfabSRick Macklem 			goto nfsmout;
345690d2dfabSRick Macklem 		}
345790d2dfabSRick Macklem 	}
345890d2dfabSRick Macklem 
34599ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
34609ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
34616269d663SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0)
34626269d663SRick Macklem 		i &= ~NFSV4OPEN_WANTDELEGMASK;
34639ec7b004SRick Macklem 	switch (i) {
34649ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSREAD:
34659ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
34669ec7b004SRick Macklem 		break;
34679ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSWRITE:
34689ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
34699ec7b004SRick Macklem 		break;
34709ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSBOTH:
34719ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
34729ec7b004SRick Macklem 		    NFSLCK_DOWNGRADE);
34739ec7b004SRick Macklem 		break;
34749ec7b004SRick Macklem 	default:
34756269d663SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
347674b8d63dSPedro F. Giffuni 	}
34779ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl);
34789ec7b004SRick Macklem 	switch (i) {
34799ec7b004SRick Macklem 	case NFSV4OPEN_DENYNONE:
34809ec7b004SRick Macklem 		break;
34819ec7b004SRick Macklem 	case NFSV4OPEN_DENYREAD:
34829ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_READDENY;
34839ec7b004SRick Macklem 		break;
34849ec7b004SRick Macklem 	case NFSV4OPEN_DENYWRITE:
34859ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_WRITEDENY;
34869ec7b004SRick Macklem 		break;
34879ec7b004SRick Macklem 	case NFSV4OPEN_DENYBOTH:
34889ec7b004SRick Macklem 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
34899ec7b004SRick Macklem 		break;
34909ec7b004SRick Macklem 	default:
34916269d663SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
349274b8d63dSPedro F. Giffuni 	}
34939ec7b004SRick Macklem 
34949ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
34959ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
3496c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3497c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3498c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3499c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3500c59e4cc3SRick Macklem 			printf("EEK12 multiple clids\n");
35019ec7b004SRick Macklem 	} else {
3502c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3503c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
35049ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
35059ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
35069ec7b004SRick Macklem 	}
35079ec7b004SRick Macklem 	if (!nd->nd_repstat)
35089ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
350990d2dfabSRick Macklem 		    nd, p, NULL);
35109ec7b004SRick Macklem 	if (!nd->nd_repstat) {
351190d2dfabSRick Macklem 		/* For NFSv4.1, set the Current StateID. */
351290d2dfabSRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0) {
351390d2dfabSRick Macklem 			nd->nd_curstateid = stateid;
351490d2dfabSRick Macklem 			nd->nd_flag |= ND_CURSTATEID;
351590d2dfabSRick Macklem 		}
35169ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
35179ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
35189ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
35199ec7b004SRick Macklem 	}
35209ec7b004SRick Macklem nfsmout:
35219ec7b004SRick Macklem 	vput(vp);
3522a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
35239ec7b004SRick Macklem 	return (error);
35249ec7b004SRick Macklem }
35259ec7b004SRick Macklem 
35269ec7b004SRick Macklem /*
35279ec7b004SRick Macklem  * nfsv4 renew lease service
35289ec7b004SRick Macklem  */
35299ec7b004SRick Macklem APPLESTATIC int
35309ec7b004SRick Macklem nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3531af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
35329ec7b004SRick Macklem {
35339ec7b004SRick Macklem 	u_int32_t *tl;
35349ec7b004SRick Macklem 	int error = 0;
35359ec7b004SRick Macklem 	nfsquad_t clientid;
3536af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
35379ec7b004SRick Macklem 
3538c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3539c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3540c59e4cc3SRick Macklem 		goto nfsmout;
3541c59e4cc3SRick Macklem 	}
3542c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3543b1cfc0d9SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3544a9285ae5SZack Kirsch 		goto nfsmout;
3545b1cfc0d9SRick Macklem 	}
35469ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
35479ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
35489ec7b004SRick Macklem 	clientid.lval[1] = *tl;
3549c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3550c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3551c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3552c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3553c59e4cc3SRick Macklem 			printf("EEK13 multiple clids\n");
35549ec7b004SRick Macklem 	} else {
3555c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3556c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
35579ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
35589ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
35599ec7b004SRick Macklem 	}
35609ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3561c59e4cc3SRick Macklem 	    NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
35629ec7b004SRick Macklem nfsmout:
3563a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
35649ec7b004SRick Macklem 	return (error);
35659ec7b004SRick Macklem }
35669ec7b004SRick Macklem 
35679ec7b004SRick Macklem /*
35689ec7b004SRick Macklem  * nfsv4 security info service
35699ec7b004SRick Macklem  */
35709ec7b004SRick Macklem APPLESTATIC int
35719ec7b004SRick Macklem nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3572af444b18SEdward Tomasz Napierala     vnode_t dp, struct nfsexstuff *exp)
35739ec7b004SRick Macklem {
35749ec7b004SRick Macklem 	u_int32_t *tl;
35759ec7b004SRick Macklem 	int len;
35769ec7b004SRick Macklem 	struct nameidata named;
35779ec7b004SRick Macklem 	vnode_t dirp = NULL, vp;
35789ec7b004SRick Macklem 	struct nfsrvfh fh;
35799ec7b004SRick Macklem 	struct nfsexstuff retnes;
35809ec7b004SRick Macklem 	u_int32_t *sizp;
3581a9285ae5SZack Kirsch 	int error = 0, savflag, i;
35829ec7b004SRick Macklem 	char *bufp;
35839ec7b004SRick Macklem 	u_long *hashp;
3584af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
35859ec7b004SRick Macklem 
35869ec7b004SRick Macklem 	/*
35879ec7b004SRick Macklem 	 * All this just to get the export flags for the name.
35889ec7b004SRick Macklem 	 */
35899ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
35909ec7b004SRick Macklem 	    LOCKLEAF | SAVESTART);
35919ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
35929ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
35939ec7b004SRick Macklem 	if (error) {
35949ec7b004SRick Macklem 		vput(dp);
35959ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
3596a9285ae5SZack Kirsch 		goto out;
35979ec7b004SRick Macklem 	}
35989ec7b004SRick Macklem 	if (!nd->nd_repstat) {
35999ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
36009ec7b004SRick Macklem 	} else {
36019ec7b004SRick Macklem 		vput(dp);
36029ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
36039ec7b004SRick Macklem 	}
36049ec7b004SRick Macklem 	if (dirp)
36059ec7b004SRick Macklem 		vrele(dirp);
36069ec7b004SRick Macklem 	if (nd->nd_repstat)
3607a9285ae5SZack Kirsch 		goto out;
36089ec7b004SRick Macklem 	vrele(named.ni_startdir);
36099ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
36109ec7b004SRick Macklem 	fh.nfsrvfh_len = NFSX_MYFH;
36119ec7b004SRick Macklem 	vp = named.ni_vp;
36129ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
36139ec7b004SRick Macklem 	vput(vp);
36149ec7b004SRick Macklem 	savflag = nd->nd_flag;
36159ec7b004SRick Macklem 	if (!nd->nd_repstat) {
36165edc9102SEdward Tomasz Napierala 		nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0);
36179ec7b004SRick Macklem 		if (vp)
36189ec7b004SRick Macklem 			vput(vp);
36199ec7b004SRick Macklem 	}
36209ec7b004SRick Macklem 	nd->nd_flag = savflag;
36219ec7b004SRick Macklem 	if (nd->nd_repstat)
3622a9285ae5SZack Kirsch 		goto out;
36239ec7b004SRick Macklem 
36249ec7b004SRick Macklem 	/*
36259ec7b004SRick Macklem 	 * Finally have the export flags for name, so we can create
36269ec7b004SRick Macklem 	 * the security info.
36279ec7b004SRick Macklem 	 */
36289ec7b004SRick Macklem 	len = 0;
36299ec7b004SRick Macklem 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
363098ad4453SRick Macklem 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
363198ad4453SRick Macklem 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
36329ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
36339ec7b004SRick Macklem 			*tl = txdr_unsigned(RPCAUTH_UNIX);
36349ec7b004SRick Macklem 			len++;
363598ad4453SRick Macklem 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
36369ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
36379ec7b004SRick Macklem 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
36389ec7b004SRick Macklem 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
36399ec7b004SRick Macklem 			    nfsgss_mechlist[KERBV_MECH].len);
36409ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
36419ec7b004SRick Macklem 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
364298ad4453SRick Macklem 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
36439ec7b004SRick Macklem 			len++;
364498ad4453SRick Macklem 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
364598ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
364698ad4453SRick Macklem 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
364798ad4453SRick Macklem 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
364898ad4453SRick Macklem 			    nfsgss_mechlist[KERBV_MECH].len);
364998ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
365098ad4453SRick Macklem 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
365198ad4453SRick Macklem 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
365298ad4453SRick Macklem 			len++;
365398ad4453SRick Macklem 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
365498ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
365598ad4453SRick Macklem 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
365698ad4453SRick Macklem 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
365798ad4453SRick Macklem 			    nfsgss_mechlist[KERBV_MECH].len);
365898ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
365998ad4453SRick Macklem 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
366098ad4453SRick Macklem 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
366198ad4453SRick Macklem 			len++;
366298ad4453SRick Macklem 		}
36639ec7b004SRick Macklem 	}
36649ec7b004SRick Macklem 	*sizp = txdr_unsigned(len);
3665a9285ae5SZack Kirsch 
3666a9285ae5SZack Kirsch out:
3667a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
3668a9285ae5SZack Kirsch 	return (error);
36699ec7b004SRick Macklem }
36709ec7b004SRick Macklem 
36719ec7b004SRick Macklem /*
36729ec7b004SRick Macklem  * nfsv4 set client id service
36739ec7b004SRick Macklem  */
36749ec7b004SRick Macklem APPLESTATIC int
36759ec7b004SRick Macklem nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3676af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
36779ec7b004SRick Macklem {
36789ec7b004SRick Macklem 	u_int32_t *tl;
36799ec7b004SRick Macklem 	int i;
36809ec7b004SRick Macklem 	int error = 0, idlen;
36819ec7b004SRick Macklem 	struct nfsclient *clp = NULL;
3682ed2f1001SRick Macklem #ifdef INET
3683ed2f1001SRick Macklem 	struct sockaddr_in *rin;
3684ed2f1001SRick Macklem #endif
3685ed2f1001SRick Macklem #ifdef INET6
3686ed2f1001SRick Macklem 	struct sockaddr_in6 *rin6;
3687ed2f1001SRick Macklem #endif
3688ed2f1001SRick Macklem #if defined(INET) || defined(INET6)
3689ed2f1001SRick Macklem 	u_char *ucp, *ucp2;
3690ed2f1001SRick Macklem #endif
3691ed2f1001SRick Macklem 	u_char *verf, *addrbuf;
36929ec7b004SRick Macklem 	nfsquad_t clientid, confirm;
3693af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
36949ec7b004SRick Macklem 
3695c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3696c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3697c59e4cc3SRick Macklem 		goto nfsmout;
3698c59e4cc3SRick Macklem 	}
3699c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
37009ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3701a9285ae5SZack Kirsch 		goto out;
37029ec7b004SRick Macklem 	}
37039ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
37049ec7b004SRick Macklem 	verf = (u_char *)tl;
37059ec7b004SRick Macklem 	tl += (NFSX_VERF / NFSX_UNSIGNED);
37069ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl);
37079ec7b004SRick Macklem 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
37089ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
3709a9285ae5SZack Kirsch 		goto nfsmout;
37109ec7b004SRick Macklem 	}
37119ec7b004SRick Macklem 	idlen = i;
37129ec7b004SRick Macklem 	if (nd->nd_flag & ND_GSS)
37139ec7b004SRick Macklem 		i += nd->nd_princlen;
37141f54e596SRick Macklem 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
37151f54e596SRick Macklem 	    M_ZERO);
37161f54e596SRick Macklem 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
37171f54e596SRick Macklem 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
37189ec7b004SRick Macklem 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3719ed2f1001SRick Macklem 	/* Allocated large enough for an AF_INET or AF_INET6 socket. */
3720ed2f1001SRick Macklem 	clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3721b97b91b5SConrad Meyer 	    M_WAITOK | M_ZERO);
37229ec7b004SRick Macklem 	clp->lc_req.nr_cred = NULL;
37239ec7b004SRick Macklem 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
37249ec7b004SRick Macklem 	clp->lc_idlen = idlen;
37259ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
37269ec7b004SRick Macklem 	if (error)
37279ec7b004SRick Macklem 		goto nfsmout;
37289ec7b004SRick Macklem 	if (nd->nd_flag & ND_GSS) {
37299ec7b004SRick Macklem 		clp->lc_flags = LCL_GSS;
37309ec7b004SRick Macklem 		if (nd->nd_flag & ND_GSSINTEGRITY)
37319ec7b004SRick Macklem 			clp->lc_flags |= LCL_GSSINTEGRITY;
37329ec7b004SRick Macklem 		else if (nd->nd_flag & ND_GSSPRIVACY)
37339ec7b004SRick Macklem 			clp->lc_flags |= LCL_GSSPRIVACY;
37349ec7b004SRick Macklem 	} else {
37359ec7b004SRick Macklem 		clp->lc_flags = 0;
37369ec7b004SRick Macklem 	}
37379ec7b004SRick Macklem 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
37389ec7b004SRick Macklem 		clp->lc_flags |= LCL_NAME;
37399ec7b004SRick Macklem 		clp->lc_namelen = nd->nd_princlen;
37409ec7b004SRick Macklem 		clp->lc_name = &clp->lc_id[idlen];
37419ec7b004SRick Macklem 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
37429ec7b004SRick Macklem 	} else {
37439ec7b004SRick Macklem 		clp->lc_uid = nd->nd_cred->cr_uid;
37449ec7b004SRick Macklem 		clp->lc_gid = nd->nd_cred->cr_gid;
37459ec7b004SRick Macklem 	}
37469ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
37479ec7b004SRick Macklem 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
37489ec7b004SRick Macklem 	error = nfsrv_getclientipaddr(nd, clp);
37499ec7b004SRick Macklem 	if (error)
37509ec7b004SRick Macklem 		goto nfsmout;
37519ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
37529ec7b004SRick Macklem 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
37539ec7b004SRick Macklem 
37549ec7b004SRick Macklem 	/*
37559ec7b004SRick Macklem 	 * nfsrv_setclient() does the actual work of adding it to the
37569ec7b004SRick Macklem 	 * client list. If there is no error, the structure has been
37579ec7b004SRick Macklem 	 * linked into the client list and clp should no longer be used
37589ec7b004SRick Macklem 	 * here. When an error is returned, it has not been linked in,
37599ec7b004SRick Macklem 	 * so it should be free'd.
37609ec7b004SRick Macklem 	 */
37619ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
37629ec7b004SRick Macklem 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3763ed2f1001SRick Macklem 		/*
3764ed2f1001SRick Macklem 		 * 8 is the maximum length of the port# string.
3765ed2f1001SRick Macklem 		 */
3766ed2f1001SRick Macklem 		addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
3767ed2f1001SRick Macklem 		switch (clp->lc_req.nr_nam->sa_family) {
3768ed2f1001SRick Macklem #ifdef INET
3769ed2f1001SRick Macklem 		case AF_INET:
37709ec7b004SRick Macklem 			if (clp->lc_flags & LCL_TCPCALLBACK)
37719ec7b004SRick Macklem 				(void) nfsm_strtom(nd, "tcp", 3);
37729ec7b004SRick Macklem 			else
37739ec7b004SRick Macklem 				(void) nfsm_strtom(nd, "udp", 3);
3774ed2f1001SRick Macklem 			rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
3775ed2f1001SRick Macklem 			ucp = (u_char *)&rin->sin_addr.s_addr;
3776ed2f1001SRick Macklem 			ucp2 = (u_char *)&rin->sin_port;
37779ec7b004SRick Macklem 			sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
37789ec7b004SRick Macklem 			    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
37799ec7b004SRick Macklem 			    ucp2[0] & 0xff, ucp2[1] & 0xff);
3780ed2f1001SRick Macklem 			break;
3781ed2f1001SRick Macklem #endif
3782ed2f1001SRick Macklem #ifdef INET6
3783ed2f1001SRick Macklem 		case AF_INET6:
3784ed2f1001SRick Macklem 			if (clp->lc_flags & LCL_TCPCALLBACK)
3785ed2f1001SRick Macklem 				(void) nfsm_strtom(nd, "tcp6", 4);
3786ed2f1001SRick Macklem 			else
3787ed2f1001SRick Macklem 				(void) nfsm_strtom(nd, "udp6", 4);
3788ed2f1001SRick Macklem 			rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
3789ed2f1001SRick Macklem 			ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
3790ed2f1001SRick Macklem 			    INET6_ADDRSTRLEN);
3791ed2f1001SRick Macklem 			if (ucp != NULL)
3792ed2f1001SRick Macklem 				i = strlen(ucp);
3793ed2f1001SRick Macklem 			else
3794ed2f1001SRick Macklem 				i = 0;
3795ed2f1001SRick Macklem 			ucp2 = (u_char *)&rin6->sin6_port;
3796ed2f1001SRick Macklem 			sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
3797ed2f1001SRick Macklem 			    ucp2[1] & 0xff);
3798ed2f1001SRick Macklem 			break;
3799ed2f1001SRick Macklem #endif
3800ed2f1001SRick Macklem 		}
38019ec7b004SRick Macklem 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3802ed2f1001SRick Macklem 		free(addrbuf, M_TEMP);
38039ec7b004SRick Macklem 	}
38049ec7b004SRick Macklem 	if (clp) {
3805b97b91b5SConrad Meyer 		free(clp->lc_req.nr_nam, M_SONAME);
38069ec7b004SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
38071f54e596SRick Macklem 		free(clp->lc_stateid, M_NFSDCLIENT);
38081f54e596SRick Macklem 		free(clp, M_NFSDCLIENT);
38099ec7b004SRick Macklem 	}
38109ec7b004SRick Macklem 	if (!nd->nd_repstat) {
38119ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
38129ec7b004SRick Macklem 		*tl++ = clientid.lval[0];
38139ec7b004SRick Macklem 		*tl++ = clientid.lval[1];
38149ec7b004SRick Macklem 		*tl++ = confirm.lval[0];
38159ec7b004SRick Macklem 		*tl = confirm.lval[1];
38169ec7b004SRick Macklem 	}
3817a9285ae5SZack Kirsch 
3818a9285ae5SZack Kirsch out:
3819a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
38209ec7b004SRick Macklem 	return (0);
38219ec7b004SRick Macklem nfsmout:
38229ec7b004SRick Macklem 	if (clp) {
3823b97b91b5SConrad Meyer 		free(clp->lc_req.nr_nam, M_SONAME);
38249ec7b004SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
38251f54e596SRick Macklem 		free(clp->lc_stateid, M_NFSDCLIENT);
38261f54e596SRick Macklem 		free(clp, M_NFSDCLIENT);
38279ec7b004SRick Macklem 	}
3828a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
38299ec7b004SRick Macklem 	return (error);
38309ec7b004SRick Macklem }
38319ec7b004SRick Macklem 
38329ec7b004SRick Macklem /*
38339ec7b004SRick Macklem  * nfsv4 set client id confirm service
38349ec7b004SRick Macklem  */
38359ec7b004SRick Macklem APPLESTATIC int
38369ec7b004SRick Macklem nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3837af444b18SEdward Tomasz Napierala     __unused int isdgram, __unused vnode_t vp,
38389ec7b004SRick Macklem     __unused struct nfsexstuff *exp)
38399ec7b004SRick Macklem {
38409ec7b004SRick Macklem 	u_int32_t *tl;
38419ec7b004SRick Macklem 	int error = 0;
38429ec7b004SRick Macklem 	nfsquad_t clientid, confirm;
3843af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
38449ec7b004SRick Macklem 
3845c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3846c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3847c59e4cc3SRick Macklem 		goto nfsmout;
3848c59e4cc3SRick Macklem 	}
3849c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
38509ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3851a9285ae5SZack Kirsch 		goto nfsmout;
38529ec7b004SRick Macklem 	}
38539ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
38549ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
38559ec7b004SRick Macklem 	clientid.lval[1] = *tl++;
38569ec7b004SRick Macklem 	confirm.lval[0] = *tl++;
38579ec7b004SRick Macklem 	confirm.lval[1] = *tl;
38589ec7b004SRick Macklem 
38599ec7b004SRick Macklem 	/*
38609ec7b004SRick Macklem 	 * nfsrv_getclient() searches the client list for a match and
38619ec7b004SRick Macklem 	 * returns the appropriate NFSERR status.
38629ec7b004SRick Macklem 	 */
38639ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3864c59e4cc3SRick Macklem 	    NULL, NULL, confirm, 0, nd, p);
38659ec7b004SRick Macklem nfsmout:
3866a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
38679ec7b004SRick Macklem 	return (error);
38689ec7b004SRick Macklem }
38699ec7b004SRick Macklem 
38709ec7b004SRick Macklem /*
38719ec7b004SRick Macklem  * nfsv4 verify service
38729ec7b004SRick Macklem  */
38739ec7b004SRick Macklem APPLESTATIC int
38749ec7b004SRick Macklem nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3875af444b18SEdward Tomasz Napierala     vnode_t vp, __unused struct nfsexstuff *exp)
38769ec7b004SRick Macklem {
38779ec7b004SRick Macklem 	int error = 0, ret, fhsize = NFSX_MYFH;
38789ec7b004SRick Macklem 	struct nfsvattr nva;
38792f304845SKonstantin Belousov 	struct statfs *sf;
38809ec7b004SRick Macklem 	struct nfsfsinfo fs;
38819ec7b004SRick Macklem 	fhandle_t fh;
3882af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
38839ec7b004SRick Macklem 
38842f304845SKonstantin Belousov 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
388590d2dfabSRick Macklem 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
38869ec7b004SRick Macklem 	if (!nd->nd_repstat)
38872f304845SKonstantin Belousov 		nd->nd_repstat = nfsvno_statfs(vp, sf);
38889ec7b004SRick Macklem 	if (!nd->nd_repstat)
38899ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
38909ec7b004SRick Macklem 	if (!nd->nd_repstat) {
38919ec7b004SRick Macklem 		nfsvno_getfs(&fs, isdgram);
38929ec7b004SRick Macklem 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
38932f304845SKonstantin Belousov 		    sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
38949ec7b004SRick Macklem 		if (!error) {
38959ec7b004SRick Macklem 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
38969ec7b004SRick Macklem 				if (ret == 0)
38979ec7b004SRick Macklem 					nd->nd_repstat = NFSERR_SAME;
38989ec7b004SRick Macklem 				else if (ret != NFSERR_NOTSAME)
38999ec7b004SRick Macklem 					nd->nd_repstat = ret;
39009ec7b004SRick Macklem 			} else if (ret)
39019ec7b004SRick Macklem 				nd->nd_repstat = ret;
39029ec7b004SRick Macklem 		}
39039ec7b004SRick Macklem 	}
39049ec7b004SRick Macklem 	vput(vp);
39052f304845SKonstantin Belousov 	free(sf, M_STATFS);
3906a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
39079ec7b004SRick Macklem 	return (error);
39089ec7b004SRick Macklem }
39099ec7b004SRick Macklem 
39109ec7b004SRick Macklem /*
39119ec7b004SRick Macklem  * nfs openattr rpc
39129ec7b004SRick Macklem  */
39139ec7b004SRick Macklem APPLESTATIC int
39149ec7b004SRick Macklem nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
39159ec7b004SRick Macklem     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3916af444b18SEdward Tomasz Napierala     __unused struct nfsexstuff *exp)
39179ec7b004SRick Macklem {
39189ec7b004SRick Macklem 	u_int32_t *tl;
39198014c971SRick Macklem 	int error = 0, createdir __unused;
39209ec7b004SRick Macklem 
39219ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
39229ec7b004SRick Macklem 	createdir = fxdr_unsigned(int, *tl);
39239ec7b004SRick Macklem 	nd->nd_repstat = NFSERR_NOTSUPP;
39249ec7b004SRick Macklem nfsmout:
39259ec7b004SRick Macklem 	vrele(dp);
3926a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
39279ec7b004SRick Macklem 	return (error);
39289ec7b004SRick Macklem }
39299ec7b004SRick Macklem 
39309ec7b004SRick Macklem /*
39319ec7b004SRick Macklem  * nfsv4 release lock owner service
39329ec7b004SRick Macklem  */
39339ec7b004SRick Macklem APPLESTATIC int
39349ec7b004SRick Macklem nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3935af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
39369ec7b004SRick Macklem {
39379ec7b004SRick Macklem 	u_int32_t *tl;
39389ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
39399ec7b004SRick Macklem 	int error = 0, len;
39409ec7b004SRick Macklem 	nfsquad_t clientid;
3941af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
39429ec7b004SRick Macklem 
3943c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3944c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3945c59e4cc3SRick Macklem 		goto nfsmout;
3946c59e4cc3SRick Macklem 	}
3947c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3948b1cfc0d9SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3949a9285ae5SZack Kirsch 		goto nfsmout;
3950b1cfc0d9SRick Macklem 	}
39519ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
39529ec7b004SRick Macklem 	len = fxdr_unsigned(int, *(tl + 2));
39532a45247cSRick Macklem 	if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
39542a45247cSRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
3955a9285ae5SZack Kirsch 		goto nfsmout;
39562a45247cSRick Macklem 	}
3957222daa42SConrad Meyer 	stp = malloc(sizeof (struct nfsstate) + len,
39589ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
39599ec7b004SRick Macklem 	stp->ls_ownerlen = len;
39609ec7b004SRick Macklem 	stp->ls_op = NULL;
39619ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_RELEASE;
39629ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
39639ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
39649ec7b004SRick Macklem 	clientid.lval[1] = *tl;
3965c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3966c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3967c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3968c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3969c59e4cc3SRick Macklem 			printf("EEK14 multiple clids\n");
39709ec7b004SRick Macklem 	} else {
3971c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3972c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
39739ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
39749ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
39759ec7b004SRick Macklem 	}
39769ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
39779ec7b004SRick Macklem 	if (error)
39789ec7b004SRick Macklem 		goto nfsmout;
39799ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3980222daa42SConrad Meyer 	free(stp, M_NFSDSTATE);
3981a9285ae5SZack Kirsch 
3982a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
39839ec7b004SRick Macklem 	return (0);
39849ec7b004SRick Macklem nfsmout:
39859ec7b004SRick Macklem 	if (stp)
3986222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
3987a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
39889ec7b004SRick Macklem 	return (error);
39899ec7b004SRick Macklem }
3990c59e4cc3SRick Macklem 
3991c59e4cc3SRick Macklem /*
3992c59e4cc3SRick Macklem  * nfsv4 exchange_id service
3993c59e4cc3SRick Macklem  */
3994c59e4cc3SRick Macklem APPLESTATIC int
3995c59e4cc3SRick Macklem nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
3996af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3997c59e4cc3SRick Macklem {
3998c59e4cc3SRick Macklem 	uint32_t *tl;
3999c59e4cc3SRick Macklem 	int error = 0, i, idlen;
4000c59e4cc3SRick Macklem 	struct nfsclient *clp = NULL;
4001c59e4cc3SRick Macklem 	nfsquad_t clientid, confirm;
4002c59e4cc3SRick Macklem 	uint8_t *verf;
4003c59e4cc3SRick Macklem 	uint32_t sp4type, v41flags;
4004c59e4cc3SRick Macklem 	uint64_t owner_minor;
4005c59e4cc3SRick Macklem 	struct timespec verstime;
4006ed2f1001SRick Macklem #ifdef INET
4007ed2f1001SRick Macklem 	struct sockaddr_in *sin, *rin;
4008ed2f1001SRick Macklem #endif
4009ed2f1001SRick Macklem #ifdef INET6
4010ed2f1001SRick Macklem 	struct sockaddr_in6 *sin6, *rin6;
4011ed2f1001SRick Macklem #endif
4012af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
4013c59e4cc3SRick Macklem 
4014c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4015c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4016c59e4cc3SRick Macklem 		goto nfsmout;
4017c59e4cc3SRick Macklem 	}
4018c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4019c59e4cc3SRick Macklem 	verf = (uint8_t *)tl;
4020c59e4cc3SRick Macklem 	tl += (NFSX_VERF / NFSX_UNSIGNED);
4021c59e4cc3SRick Macklem 	i = fxdr_unsigned(int, *tl);
4022c59e4cc3SRick Macklem 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4023c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
4024c59e4cc3SRick Macklem 		goto nfsmout;
4025c59e4cc3SRick Macklem 	}
4026c59e4cc3SRick Macklem 	idlen = i;
4027c59e4cc3SRick Macklem 	if (nd->nd_flag & ND_GSS)
4028c59e4cc3SRick Macklem 		i += nd->nd_princlen;
40291f54e596SRick Macklem 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
40301f54e596SRick Macklem 	    M_ZERO);
40311f54e596SRick Macklem 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
40321f54e596SRick Macklem 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4033c59e4cc3SRick Macklem 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4034ed2f1001SRick Macklem 	/* Allocated large enough for an AF_INET or AF_INET6 socket. */
4035ed2f1001SRick Macklem 	clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4036b97b91b5SConrad Meyer 	    M_WAITOK | M_ZERO);
4037ed2f1001SRick Macklem 	switch (nd->nd_nam->sa_family) {
4038ed2f1001SRick Macklem #ifdef INET
4039ed2f1001SRick Macklem 	case AF_INET:
4040ed2f1001SRick Macklem 		rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4041ed2f1001SRick Macklem 		sin = (struct sockaddr_in *)nd->nd_nam;
4042ed2f1001SRick Macklem 		rin->sin_family = AF_INET;
4043ed2f1001SRick Macklem 		rin->sin_len = sizeof(struct sockaddr_in);
4044ed2f1001SRick Macklem 		rin->sin_port = 0;
4045ed2f1001SRick Macklem 		rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4046ed2f1001SRick Macklem 		break;
4047ed2f1001SRick Macklem #endif
4048ed2f1001SRick Macklem #ifdef INET6
4049ed2f1001SRick Macklem 	case AF_INET6:
4050ed2f1001SRick Macklem 		rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4051ed2f1001SRick Macklem 		sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4052ed2f1001SRick Macklem 		rin6->sin6_family = AF_INET6;
4053ed2f1001SRick Macklem 		rin6->sin6_len = sizeof(struct sockaddr_in6);
4054ed2f1001SRick Macklem 		rin6->sin6_port = 0;
4055ed2f1001SRick Macklem 		rin6->sin6_addr = sin6->sin6_addr;
4056ed2f1001SRick Macklem 		break;
4057ed2f1001SRick Macklem #endif
4058ed2f1001SRick Macklem 	}
4059c59e4cc3SRick Macklem 	clp->lc_req.nr_cred = NULL;
4060c59e4cc3SRick Macklem 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4061c59e4cc3SRick Macklem 	clp->lc_idlen = idlen;
4062c59e4cc3SRick Macklem 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4063c59e4cc3SRick Macklem 	if (error != 0)
4064c59e4cc3SRick Macklem 		goto nfsmout;
4065c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_GSS) != 0) {
4066c59e4cc3SRick Macklem 		clp->lc_flags = LCL_GSS | LCL_NFSV41;
4067c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4068c59e4cc3SRick Macklem 			clp->lc_flags |= LCL_GSSINTEGRITY;
4069c59e4cc3SRick Macklem 		else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4070c59e4cc3SRick Macklem 			clp->lc_flags |= LCL_GSSPRIVACY;
4071c59e4cc3SRick Macklem 	} else
4072c59e4cc3SRick Macklem 		clp->lc_flags = LCL_NFSV41;
4073c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4074c59e4cc3SRick Macklem 		clp->lc_flags |= LCL_NAME;
4075c59e4cc3SRick Macklem 		clp->lc_namelen = nd->nd_princlen;
4076c59e4cc3SRick Macklem 		clp->lc_name = &clp->lc_id[idlen];
4077c59e4cc3SRick Macklem 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4078c59e4cc3SRick Macklem 	} else {
4079c59e4cc3SRick Macklem 		clp->lc_uid = nd->nd_cred->cr_uid;
4080c59e4cc3SRick Macklem 		clp->lc_gid = nd->nd_cred->cr_gid;
4081c59e4cc3SRick Macklem 	}
4082c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4083c59e4cc3SRick Macklem 	v41flags = fxdr_unsigned(uint32_t, *tl++);
4084c59e4cc3SRick Macklem 	if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4085c59e4cc3SRick Macklem 	    NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4086c59e4cc3SRick Macklem 	    NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4087c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
4088c59e4cc3SRick Macklem 		goto nfsmout;
4089c59e4cc3SRick Macklem 	}
4090c59e4cc3SRick Macklem 	if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4091c59e4cc3SRick Macklem 		confirm.lval[1] = 1;
4092c59e4cc3SRick Macklem 	else
4093c59e4cc3SRick Macklem 		confirm.lval[1] = 0;
409490d2dfabSRick Macklem 	if (nfsrv_devidcnt == 0)
409590d2dfabSRick Macklem 		v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
409690d2dfabSRick Macklem  	else
409790d2dfabSRick Macklem  		v41flags = NFSV4EXCH_USEPNFSMDS;
4098c59e4cc3SRick Macklem 	sp4type = fxdr_unsigned(uint32_t, *tl);
4099c59e4cc3SRick Macklem 	if (sp4type != NFSV4EXCH_SP4NONE) {
4100c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
4101c59e4cc3SRick Macklem 		goto nfsmout;
4102c59e4cc3SRick Macklem 	}
4103c59e4cc3SRick Macklem 
4104c59e4cc3SRick Macklem 	/*
4105c59e4cc3SRick Macklem 	 * nfsrv_setclient() does the actual work of adding it to the
4106c59e4cc3SRick Macklem 	 * client list. If there is no error, the structure has been
4107c59e4cc3SRick Macklem 	 * linked into the client list and clp should no longer be used
4108c59e4cc3SRick Macklem 	 * here. When an error is returned, it has not been linked in,
4109c59e4cc3SRick Macklem 	 * so it should be free'd.
4110c59e4cc3SRick Macklem 	 */
4111c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4112c59e4cc3SRick Macklem 	if (clp != NULL) {
4113b97b91b5SConrad Meyer 		free(clp->lc_req.nr_nam, M_SONAME);
4114c59e4cc3SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
41151f54e596SRick Macklem 		free(clp->lc_stateid, M_NFSDCLIENT);
4116c59e4cc3SRick Macklem 		free(clp, M_NFSDCLIENT);
4117c59e4cc3SRick Macklem 	}
4118c59e4cc3SRick Macklem 	if (nd->nd_repstat == 0) {
4119c59e4cc3SRick Macklem 		if (confirm.lval[1] != 0)
4120c59e4cc3SRick Macklem 			v41flags |= NFSV4EXCH_CONFIRMEDR;
4121c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
4122c59e4cc3SRick Macklem 		*tl++ = clientid.lval[0];			/* ClientID */
4123c59e4cc3SRick Macklem 		*tl++ = clientid.lval[1];
4124c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(confirm.lval[0]);		/* SequenceID */
4125c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(v41flags);		/* Exch flags */
4126c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);	/* No SSV */
4127c59e4cc3SRick Macklem 		owner_minor = 0;				/* Owner */
4128c59e4cc3SRick Macklem 		txdr_hyper(owner_minor, tl);			/* Minor */
4129c59e4cc3SRick Macklem 		(void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4130c59e4cc3SRick Macklem 		    strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
41318932a483SRick Macklem 		(void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
41328932a483SRick Macklem 		    strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */
41338932a483SRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4134c59e4cc3SRick Macklem 		*tl = txdr_unsigned(1);
4135c59e4cc3SRick Macklem 		(void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4136c59e4cc3SRick Macklem 		(void)nfsm_strtom(nd, version, strlen(version));
4137c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4138c59e4cc3SRick Macklem 		verstime.tv_sec = 1293840000;		/* Jan 1, 2011 */
4139c59e4cc3SRick Macklem 		verstime.tv_nsec = 0;
4140c59e4cc3SRick Macklem 		txdr_nfsv4time(&verstime, tl);
4141c59e4cc3SRick Macklem 	}
4142c59e4cc3SRick Macklem 	NFSEXITCODE2(0, nd);
4143c59e4cc3SRick Macklem 	return (0);
4144c59e4cc3SRick Macklem nfsmout:
4145c59e4cc3SRick Macklem 	if (clp != NULL) {
4146b97b91b5SConrad Meyer 		free(clp->lc_req.nr_nam, M_SONAME);
4147c59e4cc3SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
41481f54e596SRick Macklem 		free(clp->lc_stateid, M_NFSDCLIENT);
4149c59e4cc3SRick Macklem 		free(clp, M_NFSDCLIENT);
4150c59e4cc3SRick Macklem 	}
4151c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4152c59e4cc3SRick Macklem 	return (error);
4153c59e4cc3SRick Macklem }
4154c59e4cc3SRick Macklem 
4155c59e4cc3SRick Macklem /*
4156c59e4cc3SRick Macklem  * nfsv4 create session service
4157c59e4cc3SRick Macklem  */
4158c59e4cc3SRick Macklem APPLESTATIC int
4159c59e4cc3SRick Macklem nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4160af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4161c59e4cc3SRick Macklem {
4162c59e4cc3SRick Macklem 	uint32_t *tl;
4163c59e4cc3SRick Macklem 	int error = 0;
4164c59e4cc3SRick Macklem 	nfsquad_t clientid, confirm;
4165c59e4cc3SRick Macklem 	struct nfsdsession *sep = NULL;
4166c59e4cc3SRick Macklem 	uint32_t rdmacnt;
4167af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
4168c59e4cc3SRick Macklem 
4169c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4170c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4171c59e4cc3SRick Macklem 		goto nfsmout;
4172c59e4cc3SRick Macklem 	}
4173c59e4cc3SRick Macklem 	sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4174c59e4cc3SRick Macklem 	    M_NFSDSESSION, M_WAITOK | M_ZERO);
4175c59e4cc3SRick Macklem 	sep->sess_refcnt = 1;
4176c59e4cc3SRick Macklem 	mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4177c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4178c59e4cc3SRick Macklem 	clientid.lval[0] = *tl++;
4179c59e4cc3SRick Macklem 	clientid.lval[1] = *tl++;
4180c59e4cc3SRick Macklem 	confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4181c59e4cc3SRick Macklem 	sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4182c59e4cc3SRick Macklem 	/* Persistent sessions and RDMA are not supported. */
4183c59e4cc3SRick Macklem 	sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4184c59e4cc3SRick Macklem 
4185c59e4cc3SRick Macklem 	/* Fore channel attributes. */
4186c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4187c59e4cc3SRick Macklem 	tl++;					/* Header pad always 0. */
4188c59e4cc3SRick Macklem 	sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
418990d2dfabSRick Macklem 	if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
419090d2dfabSRick Macklem 		sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
419190d2dfabSRick Macklem 		printf("Consider increasing kern.ipc.maxsockbuf\n");
419290d2dfabSRick Macklem 	}
4193c59e4cc3SRick Macklem 	sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
419490d2dfabSRick Macklem 	if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
419590d2dfabSRick Macklem 		sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
419690d2dfabSRick Macklem 		printf("Consider increasing kern.ipc.maxsockbuf\n");
419790d2dfabSRick Macklem 	}
4198c59e4cc3SRick Macklem 	sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4199c59e4cc3SRick Macklem 	sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4200c59e4cc3SRick Macklem 	sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4201c59e4cc3SRick Macklem 	if (sep->sess_maxslots > NFSV4_SLOTS)
4202c59e4cc3SRick Macklem 		sep->sess_maxslots = NFSV4_SLOTS;
4203c59e4cc3SRick Macklem 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
4204c59e4cc3SRick Macklem 	if (rdmacnt > 1) {
4205c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
4206c59e4cc3SRick Macklem 		goto nfsmout;
4207c59e4cc3SRick Macklem 	} else if (rdmacnt == 1)
4208c59e4cc3SRick Macklem 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4209c59e4cc3SRick Macklem 
4210c59e4cc3SRick Macklem 	/* Back channel attributes. */
4211c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4212c59e4cc3SRick Macklem 	tl++;					/* Header pad always 0. */
4213c59e4cc3SRick Macklem 	sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4214c59e4cc3SRick Macklem 	sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4215c59e4cc3SRick Macklem 	sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4216c59e4cc3SRick Macklem 	sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4217c59e4cc3SRick Macklem 	sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4218c59e4cc3SRick Macklem 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
4219c59e4cc3SRick Macklem 	if (rdmacnt > 1) {
4220c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
4221c59e4cc3SRick Macklem 		goto nfsmout;
4222c59e4cc3SRick Macklem 	} else if (rdmacnt == 1)
4223c59e4cc3SRick Macklem 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4224c59e4cc3SRick Macklem 
4225c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4226c59e4cc3SRick Macklem 	sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4227c59e4cc3SRick Macklem 
4228c59e4cc3SRick Macklem 	/*
4229c59e4cc3SRick Macklem 	 * nfsrv_getclient() searches the client list for a match and
4230c59e4cc3SRick Macklem 	 * returns the appropriate NFSERR status.
4231c59e4cc3SRick Macklem 	 */
4232c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4233c59e4cc3SRick Macklem 	    NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4234c59e4cc3SRick Macklem 	if (nd->nd_repstat == 0) {
4235c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4236c59e4cc3SRick Macklem 		NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4237c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4238c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(confirm.lval[0]);	/* sequenceid */
4239c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_crflags);
4240c59e4cc3SRick Macklem 
4241c59e4cc3SRick Macklem 		/* Fore channel attributes. */
4242c59e4cc3SRick Macklem 		*tl++ = 0;
4243c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxreq);
4244c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxresp);
4245c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxrespcached);
4246c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxops);
4247c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxslots);
4248c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(1);
4249c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(0);			/* No RDMA. */
4250c59e4cc3SRick Macklem 
4251c59e4cc3SRick Macklem 		/* Back channel attributes. */
4252c59e4cc3SRick Macklem 		*tl++ = 0;
4253c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4254c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4255c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4256c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbmaxops);
4257c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4258c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(1);
4259c59e4cc3SRick Macklem 		*tl = txdr_unsigned(0);			/* No RDMA. */
4260c59e4cc3SRick Macklem 	}
4261c59e4cc3SRick Macklem nfsmout:
4262c59e4cc3SRick Macklem 	if (nd->nd_repstat != 0 && sep != NULL)
4263c59e4cc3SRick Macklem 		free(sep, M_NFSDSESSION);
4264c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4265c59e4cc3SRick Macklem 	return (error);
4266c59e4cc3SRick Macklem }
4267c59e4cc3SRick Macklem 
4268c59e4cc3SRick Macklem /*
4269c59e4cc3SRick Macklem  * nfsv4 sequence service
4270c59e4cc3SRick Macklem  */
4271c59e4cc3SRick Macklem APPLESTATIC int
4272c59e4cc3SRick Macklem nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4273af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4274c59e4cc3SRick Macklem {
4275c59e4cc3SRick Macklem 	uint32_t *tl;
4276c59e4cc3SRick Macklem 	uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4277c59e4cc3SRick Macklem 	int cache_this, error = 0;
4278af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
4279c59e4cc3SRick Macklem 
4280c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4281c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4282c59e4cc3SRick Macklem 		goto nfsmout;
4283c59e4cc3SRick Macklem 	}
4284c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4285c59e4cc3SRick Macklem 	NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4286c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4287c59e4cc3SRick Macklem 	sequenceid = fxdr_unsigned(uint32_t, *tl++);
4288c59e4cc3SRick Macklem 	nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4289c59e4cc3SRick Macklem 	highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4290c59e4cc3SRick Macklem 	if (*tl == newnfs_true)
4291c59e4cc3SRick Macklem 		cache_this = 1;
4292c59e4cc3SRick Macklem 	else
4293c59e4cc3SRick Macklem 		cache_this = 0;
4294c59e4cc3SRick Macklem 	nd->nd_flag |= ND_HASSEQUENCE;
4295c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4296c59e4cc3SRick Macklem 	    &target_highest_slotid, cache_this, &sflags, p);
4297c59e4cc3SRick Macklem 	if (nd->nd_repstat == 0) {
4298c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4299c59e4cc3SRick Macklem 		NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4300c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4301c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sequenceid);
4302c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(nd->nd_slotid);
4303c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(highest_slotid);
4304c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(target_highest_slotid);
4305c59e4cc3SRick Macklem 		*tl = txdr_unsigned(sflags);
4306c59e4cc3SRick Macklem 	}
4307c59e4cc3SRick Macklem nfsmout:
4308c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4309c59e4cc3SRick Macklem 	return (error);
4310c59e4cc3SRick Macklem }
4311c59e4cc3SRick Macklem 
4312c59e4cc3SRick Macklem /*
4313c59e4cc3SRick Macklem  * nfsv4 reclaim complete service
4314c59e4cc3SRick Macklem  */
4315c59e4cc3SRick Macklem APPLESTATIC int
4316c59e4cc3SRick Macklem nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4317af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4318c59e4cc3SRick Macklem {
4319c59e4cc3SRick Macklem 	uint32_t *tl;
4320a3e709cdSRick Macklem 	int error = 0, onefs;
4321c59e4cc3SRick Macklem 
4322c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4323c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4324c59e4cc3SRick Macklem 		goto nfsmout;
4325c59e4cc3SRick Macklem 	}
4326c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4327a3e709cdSRick Macklem 	/*
4328a3e709cdSRick Macklem 	 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4329a3e709cdSRick Macklem 	 * to be used after a file system has been transferred to a different
4330a3e709cdSRick Macklem 	 * file server.  However, RFC5661 is somewhat vague w.r.t. this and
4331a3e709cdSRick Macklem 	 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4332a3e709cdSRick Macklem 	 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4333a3e709cdSRick Macklem 	 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4334a3e709cdSRick Macklem 	 * NFS_OK without doing anything.
4335a3e709cdSRick Macklem 	 */
4336a3e709cdSRick Macklem 	onefs = 0;
4337c59e4cc3SRick Macklem 	if (*tl == newnfs_true)
4338a3e709cdSRick Macklem 		onefs = 1;
4339a3e709cdSRick Macklem 	nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4340c59e4cc3SRick Macklem nfsmout:
4341c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4342c59e4cc3SRick Macklem 	return (error);
4343c59e4cc3SRick Macklem }
4344c59e4cc3SRick Macklem 
4345c59e4cc3SRick Macklem /*
4346c59e4cc3SRick Macklem  * nfsv4 destroy clientid service
4347c59e4cc3SRick Macklem  */
4348c59e4cc3SRick Macklem APPLESTATIC int
4349c59e4cc3SRick Macklem nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4350af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4351c59e4cc3SRick Macklem {
4352c59e4cc3SRick Macklem 	uint32_t *tl;
4353c59e4cc3SRick Macklem 	nfsquad_t clientid;
4354c59e4cc3SRick Macklem 	int error = 0;
4355af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
4356c59e4cc3SRick Macklem 
4357c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4358c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4359c59e4cc3SRick Macklem 		goto nfsmout;
4360c59e4cc3SRick Macklem 	}
4361c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4362c59e4cc3SRick Macklem 	clientid.lval[0] = *tl++;
4363c59e4cc3SRick Macklem 	clientid.lval[1] = *tl;
4364c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4365c59e4cc3SRick Macklem nfsmout:
4366c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4367c59e4cc3SRick Macklem 	return (error);
4368c59e4cc3SRick Macklem }
4369c59e4cc3SRick Macklem 
4370c59e4cc3SRick Macklem /*
43719442a64eSRick Macklem  * nfsv4 bind connection to session service
43729442a64eSRick Macklem  */
43739442a64eSRick Macklem APPLESTATIC int
43749442a64eSRick Macklem nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4375af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
43769442a64eSRick Macklem {
43779442a64eSRick Macklem 	uint32_t *tl;
43789442a64eSRick Macklem 	uint8_t sessid[NFSX_V4SESSIONID];
43799442a64eSRick Macklem 	int error = 0, foreaft;
43809442a64eSRick Macklem 
43819442a64eSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
43829442a64eSRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
43839442a64eSRick Macklem 		goto nfsmout;
43849442a64eSRick Macklem 	}
43859442a64eSRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
43869442a64eSRick Macklem 	NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
43879442a64eSRick Macklem 	tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
43889442a64eSRick Macklem 	foreaft = fxdr_unsigned(int, *tl++);
43899442a64eSRick Macklem 	if (*tl == newnfs_true) {
43909442a64eSRick Macklem 		/* RDMA is not supported. */
43919442a64eSRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
43929442a64eSRick Macklem 		goto nfsmout;
43939442a64eSRick Macklem 	}
43949442a64eSRick Macklem 
43959442a64eSRick Macklem 	nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
43969442a64eSRick Macklem 	if (nd->nd_repstat == 0) {
43979442a64eSRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
43989442a64eSRick Macklem 		    NFSX_UNSIGNED);
43999442a64eSRick Macklem 		NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
44009442a64eSRick Macklem 		tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
44019442a64eSRick Macklem 		*tl++ = txdr_unsigned(foreaft);
44029442a64eSRick Macklem 		*tl = newnfs_false;
44039442a64eSRick Macklem 	}
44049442a64eSRick Macklem nfsmout:
44059442a64eSRick Macklem 	NFSEXITCODE2(error, nd);
44069442a64eSRick Macklem 	return (error);
44079442a64eSRick Macklem }
44089442a64eSRick Macklem 
44099442a64eSRick Macklem /*
4410c59e4cc3SRick Macklem  * nfsv4 destroy session service
4411c59e4cc3SRick Macklem  */
4412c59e4cc3SRick Macklem APPLESTATIC int
4413c59e4cc3SRick Macklem nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4414af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4415c59e4cc3SRick Macklem {
4416c59e4cc3SRick Macklem 	uint8_t *cp, sessid[NFSX_V4SESSIONID];
4417c59e4cc3SRick Macklem 	int error = 0;
4418c59e4cc3SRick Macklem 
4419c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4420c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4421c59e4cc3SRick Macklem 		goto nfsmout;
4422c59e4cc3SRick Macklem 	}
4423c59e4cc3SRick Macklem 	NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4424c59e4cc3SRick Macklem 	NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4425c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4426c59e4cc3SRick Macklem nfsmout:
4427c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4428c59e4cc3SRick Macklem 	return (error);
4429c59e4cc3SRick Macklem }
4430c59e4cc3SRick Macklem 
4431c59e4cc3SRick Macklem /*
4432c59e4cc3SRick Macklem  * nfsv4 free stateid service
4433c59e4cc3SRick Macklem  */
4434c59e4cc3SRick Macklem APPLESTATIC int
4435c59e4cc3SRick Macklem nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4436af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4437c59e4cc3SRick Macklem {
4438c59e4cc3SRick Macklem 	uint32_t *tl;
4439c59e4cc3SRick Macklem 	nfsv4stateid_t stateid;
4440c59e4cc3SRick Macklem 	int error = 0;
4441af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
4442c59e4cc3SRick Macklem 
4443c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4444c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4445c59e4cc3SRick Macklem 		goto nfsmout;
4446c59e4cc3SRick Macklem 	}
4447c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4448c59e4cc3SRick Macklem 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4449c59e4cc3SRick Macklem 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
445090d2dfabSRick Macklem 
445190d2dfabSRick Macklem 	/*
445290d2dfabSRick Macklem 	 * For the special stateid of other all 0s and seqid == 1, set the
445390d2dfabSRick Macklem 	 * stateid to the current stateid, if it is set.
445490d2dfabSRick Macklem 	 */
445590d2dfabSRick Macklem 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
445690d2dfabSRick Macklem 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
445790d2dfabSRick Macklem 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
445890d2dfabSRick Macklem 			stateid = nd->nd_curstateid;
445990d2dfabSRick Macklem 			stateid.seqid = 0;
446090d2dfabSRick Macklem 		} else {
446190d2dfabSRick Macklem 			nd->nd_repstat = NFSERR_BADSTATEID;
446290d2dfabSRick Macklem 			goto nfsmout;
446390d2dfabSRick Macklem 		}
446490d2dfabSRick Macklem 	}
446590d2dfabSRick Macklem 
4466c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
446790d2dfabSRick Macklem 
446890d2dfabSRick Macklem 	/* If the current stateid has been free'd, unset it. */
446990d2dfabSRick Macklem 	if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
447090d2dfabSRick Macklem 	    stateid.other[0] == nd->nd_curstateid.other[0] &&
447190d2dfabSRick Macklem 	    stateid.other[1] == nd->nd_curstateid.other[1] &&
447290d2dfabSRick Macklem 	    stateid.other[2] == nd->nd_curstateid.other[2])
447390d2dfabSRick Macklem 		nd->nd_flag &= ~ND_CURSTATEID;
447490d2dfabSRick Macklem nfsmout:
447590d2dfabSRick Macklem 	NFSEXITCODE2(error, nd);
447690d2dfabSRick Macklem 	return (error);
447790d2dfabSRick Macklem }
447890d2dfabSRick Macklem 
447990d2dfabSRick Macklem /*
448090d2dfabSRick Macklem  * nfsv4 layoutget service
448190d2dfabSRick Macklem  */
448290d2dfabSRick Macklem APPLESTATIC int
448390d2dfabSRick Macklem nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4484af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
448590d2dfabSRick Macklem {
448690d2dfabSRick Macklem 	uint32_t *tl;
448790d2dfabSRick Macklem 	nfsv4stateid_t stateid;
448890d2dfabSRick Macklem 	int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
448990d2dfabSRick Macklem 	uint64_t offset, len, minlen;
449090d2dfabSRick Macklem 	char *layp;
4491af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
449290d2dfabSRick Macklem 
449390d2dfabSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
449490d2dfabSRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
449590d2dfabSRick Macklem 		goto nfsmout;
449690d2dfabSRick Macklem 	}
449790d2dfabSRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
449890d2dfabSRick Macklem 	    NFSX_STATEID);
449990d2dfabSRick Macklem 	tl++;		/* Signal layout available. Ignore for now. */
450090d2dfabSRick Macklem 	layouttype = fxdr_unsigned(int, *tl++);
450190d2dfabSRick Macklem 	iomode = fxdr_unsigned(int, *tl++);
450290d2dfabSRick Macklem 	offset = fxdr_hyper(tl); tl += 2;
450390d2dfabSRick Macklem 	len = fxdr_hyper(tl); tl += 2;
450490d2dfabSRick Macklem 	minlen = fxdr_hyper(tl); tl += 2;
450590d2dfabSRick Macklem 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
450690d2dfabSRick Macklem 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
450790d2dfabSRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
450890d2dfabSRick Macklem 	maxcnt = fxdr_unsigned(int, *tl);
450990d2dfabSRick Macklem 	NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
451090d2dfabSRick Macklem 	    layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
451190d2dfabSRick Macklem 	    (uintmax_t)minlen);
451290d2dfabSRick Macklem 	if (len < minlen ||
451390d2dfabSRick Macklem 	    (minlen != UINT64_MAX && offset + minlen < offset) ||
451490d2dfabSRick Macklem 	    (len != UINT64_MAX && offset + len < offset)) {
451590d2dfabSRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
451690d2dfabSRick Macklem 		goto nfsmout;
451790d2dfabSRick Macklem 	}
451890d2dfabSRick Macklem 
451990d2dfabSRick Macklem 	/*
452090d2dfabSRick Macklem 	 * For the special stateid of other all 0s and seqid == 1, set the
452190d2dfabSRick Macklem 	 * stateid to the current stateid, if it is set.
452290d2dfabSRick Macklem 	 */
452390d2dfabSRick Macklem 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
452490d2dfabSRick Macklem 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
452590d2dfabSRick Macklem 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
452690d2dfabSRick Macklem 			stateid = nd->nd_curstateid;
452790d2dfabSRick Macklem 			stateid.seqid = 0;
452890d2dfabSRick Macklem 		} else {
452990d2dfabSRick Macklem 			nd->nd_repstat = NFSERR_BADSTATEID;
453090d2dfabSRick Macklem 			goto nfsmout;
453190d2dfabSRick Macklem 		}
453290d2dfabSRick Macklem 	}
453390d2dfabSRick Macklem 
453490d2dfabSRick Macklem 	layp = NULL;
453590d2dfabSRick Macklem 	if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
453690d2dfabSRick Macklem 		layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
453790d2dfabSRick Macklem 	else if (layouttype == NFSLAYOUT_FLEXFILE)
453890d2dfabSRick Macklem 		layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
453990d2dfabSRick Macklem 		    M_WAITOK);
454090d2dfabSRick Macklem 	else
454190d2dfabSRick Macklem 		nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
454290d2dfabSRick Macklem 	if (layp != NULL)
454390d2dfabSRick Macklem 		nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
454490d2dfabSRick Macklem 		    &iomode, &offset, &len, minlen, &stateid, maxcnt,
454590d2dfabSRick Macklem 		    &retonclose, &layoutlen, layp, nd->nd_cred, p);
454690d2dfabSRick Macklem 	NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
454790d2dfabSRick Macklem 	    layoutlen);
454890d2dfabSRick Macklem 	if (nd->nd_repstat == 0) {
454990d2dfabSRick Macklem 		/* For NFSv4.1, set the Current StateID. */
455090d2dfabSRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0) {
455190d2dfabSRick Macklem 			nd->nd_curstateid = stateid;
455290d2dfabSRick Macklem 			nd->nd_flag |= ND_CURSTATEID;
455390d2dfabSRick Macklem 		}
455490d2dfabSRick Macklem 		NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
455590d2dfabSRick Macklem 		    2 * NFSX_HYPER);
455690d2dfabSRick Macklem 		*tl++ = txdr_unsigned(retonclose);
455790d2dfabSRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
455890d2dfabSRick Macklem 		NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
455990d2dfabSRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
456090d2dfabSRick Macklem 		*tl++ = txdr_unsigned(1);	/* Only returns one layout. */
456190d2dfabSRick Macklem 		txdr_hyper(offset, tl); tl += 2;
456290d2dfabSRick Macklem 		txdr_hyper(len, tl); tl += 2;
456390d2dfabSRick Macklem 		*tl++ = txdr_unsigned(iomode);
456490d2dfabSRick Macklem 		*tl = txdr_unsigned(layouttype);
456590d2dfabSRick Macklem 		nfsm_strtom(nd, layp, layoutlen);
456690d2dfabSRick Macklem 	} else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
456790d2dfabSRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
456890d2dfabSRick Macklem 		*tl = newnfs_false;
456990d2dfabSRick Macklem 	}
457090d2dfabSRick Macklem 	free(layp, M_TEMP);
457190d2dfabSRick Macklem nfsmout:
457290d2dfabSRick Macklem 	vput(vp);
457390d2dfabSRick Macklem 	NFSEXITCODE2(error, nd);
457490d2dfabSRick Macklem 	return (error);
457590d2dfabSRick Macklem }
457690d2dfabSRick Macklem 
457790d2dfabSRick Macklem /*
457890d2dfabSRick Macklem  * nfsv4 layoutcommit service
457990d2dfabSRick Macklem  */
458090d2dfabSRick Macklem APPLESTATIC int
458190d2dfabSRick Macklem nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4582af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
458390d2dfabSRick Macklem {
458490d2dfabSRick Macklem 	uint32_t *tl;
458590d2dfabSRick Macklem 	nfsv4stateid_t stateid;
458690d2dfabSRick Macklem 	int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
458790d2dfabSRick Macklem 	int hasnewsize;
458890d2dfabSRick Macklem 	uint64_t offset, len, newoff, newsize;
458990d2dfabSRick Macklem 	struct timespec newmtime;
459090d2dfabSRick Macklem 	char *layp;
4591af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
459290d2dfabSRick Macklem 
459390d2dfabSRick Macklem 	layp = NULL;
459490d2dfabSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
459590d2dfabSRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
459690d2dfabSRick Macklem 		goto nfsmout;
459790d2dfabSRick Macklem 	}
459890d2dfabSRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
459990d2dfabSRick Macklem 	    NFSX_STATEID);
460090d2dfabSRick Macklem 	offset = fxdr_hyper(tl); tl += 2;
460190d2dfabSRick Macklem 	len = fxdr_hyper(tl); tl += 2;
460290d2dfabSRick Macklem 	reclaim = fxdr_unsigned(int, *tl++);
460390d2dfabSRick Macklem 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
460490d2dfabSRick Macklem 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
460590d2dfabSRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
460690d2dfabSRick Macklem 	/*
460790d2dfabSRick Macklem 	 * For the special stateid of other all 0s and seqid == 1, set the
460890d2dfabSRick Macklem 	 * stateid to the current stateid, if it is set.
460990d2dfabSRick Macklem 	 */
461090d2dfabSRick Macklem 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
461190d2dfabSRick Macklem 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
461290d2dfabSRick Macklem 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
461390d2dfabSRick Macklem 			stateid = nd->nd_curstateid;
461490d2dfabSRick Macklem 			stateid.seqid = 0;
461590d2dfabSRick Macklem 		} else {
461690d2dfabSRick Macklem 			nd->nd_repstat = NFSERR_BADSTATEID;
461790d2dfabSRick Macklem 			goto nfsmout;
461890d2dfabSRick Macklem 		}
461990d2dfabSRick Macklem 	}
462090d2dfabSRick Macklem 
462190d2dfabSRick Macklem 	hasnewoff = fxdr_unsigned(int, *tl);
462290d2dfabSRick Macklem 	if (hasnewoff != 0) {
462390d2dfabSRick Macklem 		NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
462490d2dfabSRick Macklem 		newoff = fxdr_hyper(tl); tl += 2;
462590d2dfabSRick Macklem 	} else
462690d2dfabSRick Macklem 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
462790d2dfabSRick Macklem 	hasnewmtime = fxdr_unsigned(int, *tl);
462890d2dfabSRick Macklem 	if (hasnewmtime != 0) {
462990d2dfabSRick Macklem 		NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
463090d2dfabSRick Macklem 		fxdr_nfsv4time(tl, &newmtime);
463190d2dfabSRick Macklem 		tl += (NFSX_V4TIME / NFSX_UNSIGNED);
463290d2dfabSRick Macklem 	} else
463390d2dfabSRick Macklem 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
463490d2dfabSRick Macklem 	layouttype = fxdr_unsigned(int, *tl++);
463590d2dfabSRick Macklem 	maxcnt = fxdr_unsigned(int, *tl);
463690d2dfabSRick Macklem 	if (maxcnt > 0) {
463790d2dfabSRick Macklem 		layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
463890d2dfabSRick Macklem 		error = nfsrv_mtostr(nd, layp, maxcnt);
463990d2dfabSRick Macklem 		if (error != 0)
464090d2dfabSRick Macklem 			goto nfsmout;
464190d2dfabSRick Macklem 	}
464290d2dfabSRick Macklem 	nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
464390d2dfabSRick Macklem 	    newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
464490d2dfabSRick Macklem 	    maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
464590d2dfabSRick Macklem 	NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
464690d2dfabSRick Macklem 	if (nd->nd_repstat == 0) {
464790d2dfabSRick Macklem 		if (hasnewsize != 0) {
464890d2dfabSRick Macklem 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
464990d2dfabSRick Macklem 			*tl++ = newnfs_true;
465090d2dfabSRick Macklem 			txdr_hyper(newsize, tl);
465190d2dfabSRick Macklem 		} else {
465290d2dfabSRick Macklem 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
465390d2dfabSRick Macklem 			*tl = newnfs_false;
465490d2dfabSRick Macklem 		}
465590d2dfabSRick Macklem 	}
465690d2dfabSRick Macklem nfsmout:
465790d2dfabSRick Macklem 	free(layp, M_TEMP);
465890d2dfabSRick Macklem 	vput(vp);
465990d2dfabSRick Macklem 	NFSEXITCODE2(error, nd);
466090d2dfabSRick Macklem 	return (error);
466190d2dfabSRick Macklem }
466290d2dfabSRick Macklem 
466390d2dfabSRick Macklem /*
466490d2dfabSRick Macklem  * nfsv4 layoutreturn service
466590d2dfabSRick Macklem  */
466690d2dfabSRick Macklem APPLESTATIC int
466790d2dfabSRick Macklem nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4668af444b18SEdward Tomasz Napierala     vnode_t vp, struct nfsexstuff *exp)
466990d2dfabSRick Macklem {
467090d2dfabSRick Macklem 	uint32_t *tl, *layp;
467190d2dfabSRick Macklem 	nfsv4stateid_t stateid;
467290d2dfabSRick Macklem 	int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
467390d2dfabSRick Macklem 	uint64_t offset, len;
4674af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
467590d2dfabSRick Macklem 
467690d2dfabSRick Macklem 	layp = NULL;
467790d2dfabSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
467890d2dfabSRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
467990d2dfabSRick Macklem 		goto nfsmout;
468090d2dfabSRick Macklem 	}
468190d2dfabSRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
468290d2dfabSRick Macklem 	reclaim = *tl++;
468390d2dfabSRick Macklem 	layouttype = fxdr_unsigned(int, *tl++);
468490d2dfabSRick Macklem 	iomode = fxdr_unsigned(int, *tl++);
468590d2dfabSRick Macklem 	kind = fxdr_unsigned(int, *tl);
468690d2dfabSRick Macklem 	NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
468790d2dfabSRick Macklem 	    layouttype, iomode, kind);
468890d2dfabSRick Macklem 	if (kind == NFSV4LAYOUTRET_FILE) {
468990d2dfabSRick Macklem 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
469090d2dfabSRick Macklem 		    NFSX_UNSIGNED);
469190d2dfabSRick Macklem 		offset = fxdr_hyper(tl); tl += 2;
469290d2dfabSRick Macklem 		len = fxdr_hyper(tl); tl += 2;
469390d2dfabSRick Macklem 		stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
469490d2dfabSRick Macklem 		NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
469590d2dfabSRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
469690d2dfabSRick Macklem 
469790d2dfabSRick Macklem 		/*
469890d2dfabSRick Macklem 		 * For the special stateid of other all 0s and seqid == 1, set
469990d2dfabSRick Macklem 		 * the stateid to the current stateid, if it is set.
470090d2dfabSRick Macklem 		 */
470190d2dfabSRick Macklem 		if (stateid.seqid == 1 && stateid.other[0] == 0 &&
470290d2dfabSRick Macklem 		    stateid.other[1] == 0 && stateid.other[2] == 0) {
470390d2dfabSRick Macklem 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
470490d2dfabSRick Macklem 				stateid = nd->nd_curstateid;
470590d2dfabSRick Macklem 				stateid.seqid = 0;
470690d2dfabSRick Macklem 			} else {
470790d2dfabSRick Macklem 				nd->nd_repstat = NFSERR_BADSTATEID;
470890d2dfabSRick Macklem 				goto nfsmout;
470990d2dfabSRick Macklem 			}
471090d2dfabSRick Macklem 		}
471190d2dfabSRick Macklem 
471290d2dfabSRick Macklem 		maxcnt = fxdr_unsigned(int, *tl);
471390d2dfabSRick Macklem 		if (maxcnt > 0) {
471490d2dfabSRick Macklem 			layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
471590d2dfabSRick Macklem 			error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
471690d2dfabSRick Macklem 			if (error != 0)
471790d2dfabSRick Macklem 				goto nfsmout;
471890d2dfabSRick Macklem 		}
471990d2dfabSRick Macklem 	} else {
472090d2dfabSRick Macklem 		if (reclaim == newnfs_true) {
472190d2dfabSRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
472290d2dfabSRick Macklem 			goto nfsmout;
472390d2dfabSRick Macklem 		}
472490d2dfabSRick Macklem 		offset = len = 0;
472590d2dfabSRick Macklem 		maxcnt = 0;
472690d2dfabSRick Macklem 	}
472790d2dfabSRick Macklem 	nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
472890d2dfabSRick Macklem 	    offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
472990d2dfabSRick Macklem 	    nd->nd_cred, p);
473090d2dfabSRick Macklem 	NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
473190d2dfabSRick Macklem 	    fnd);
473290d2dfabSRick Macklem 	if (nd->nd_repstat == 0) {
473390d2dfabSRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
473490d2dfabSRick Macklem 		if (fnd != 0) {
473590d2dfabSRick Macklem 			*tl = newnfs_true;
473690d2dfabSRick Macklem 			NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
473790d2dfabSRick Macklem 			*tl++ = txdr_unsigned(stateid.seqid);
473890d2dfabSRick Macklem 			NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
473990d2dfabSRick Macklem 		} else
474090d2dfabSRick Macklem 			*tl = newnfs_false;
474190d2dfabSRick Macklem 	}
474290d2dfabSRick Macklem nfsmout:
474390d2dfabSRick Macklem 	free(layp, M_TEMP);
474490d2dfabSRick Macklem 	vput(vp);
474590d2dfabSRick Macklem 	NFSEXITCODE2(error, nd);
474690d2dfabSRick Macklem 	return (error);
474790d2dfabSRick Macklem }
474890d2dfabSRick Macklem 
474990d2dfabSRick Macklem /*
475090d2dfabSRick Macklem  * nfsv4 getdeviceinfo service
475190d2dfabSRick Macklem  */
475290d2dfabSRick Macklem APPLESTATIC int
475390d2dfabSRick Macklem nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
4754af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
475590d2dfabSRick Macklem {
475690d2dfabSRick Macklem 	uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
475790d2dfabSRick Macklem 	int cnt, devaddrlen, error = 0, i, layouttype;
475890d2dfabSRick Macklem 	char devid[NFSX_V4DEVICEID], *devaddr;
475990d2dfabSRick Macklem 	time_t dev_time;
476090d2dfabSRick Macklem 
476190d2dfabSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
476290d2dfabSRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
476390d2dfabSRick Macklem 		goto nfsmout;
476490d2dfabSRick Macklem 	}
476590d2dfabSRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
476690d2dfabSRick Macklem 	NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
476790d2dfabSRick Macklem 	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
476890d2dfabSRick Macklem 	layouttype = fxdr_unsigned(int, *tl++);
476990d2dfabSRick Macklem 	maxcnt = fxdr_unsigned(uint32_t, *tl++);
477090d2dfabSRick Macklem 	cnt = fxdr_unsigned(int, *tl);
477190d2dfabSRick Macklem 	NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
477290d2dfabSRick Macklem 	    maxcnt, cnt);
477390d2dfabSRick Macklem 	if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
477490d2dfabSRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
477590d2dfabSRick Macklem 		goto nfsmout;
477690d2dfabSRick Macklem 	}
477790d2dfabSRick Macklem 	if (cnt > 0) {
477890d2dfabSRick Macklem 		NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
477990d2dfabSRick Macklem 		for (i = 0; i < cnt; i++)
478090d2dfabSRick Macklem 			notify[i] = fxdr_unsigned(uint32_t, *tl++);
478190d2dfabSRick Macklem 	}
478290d2dfabSRick Macklem 	for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
478390d2dfabSRick Macklem 		notify[i] = 0;
478490d2dfabSRick Macklem 
478590d2dfabSRick Macklem 	/*
478690d2dfabSRick Macklem 	 * Check that the device id is not stale.  Device ids are recreated
478790d2dfabSRick Macklem 	 * each time the nfsd threads are restarted.
478890d2dfabSRick Macklem 	 */
478990d2dfabSRick Macklem 	NFSBCOPY(devid, &dev_time, sizeof(dev_time));
479090d2dfabSRick Macklem 	if (dev_time != nfsdev_time) {
479190d2dfabSRick Macklem 		nd->nd_repstat = NFSERR_NOENT;
479290d2dfabSRick Macklem 		goto nfsmout;
479390d2dfabSRick Macklem 	}
479490d2dfabSRick Macklem 
479590d2dfabSRick Macklem 	/* Look for the device id. */
479690d2dfabSRick Macklem 	nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
479790d2dfabSRick Macklem 	    notify, &devaddrlen, &devaddr);
479890d2dfabSRick Macklem 	NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
479990d2dfabSRick Macklem 	if (nd->nd_repstat == 0) {
480090d2dfabSRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
480190d2dfabSRick Macklem 		*tl = txdr_unsigned(layouttype);
480290d2dfabSRick Macklem 		nfsm_strtom(nd, devaddr, devaddrlen);
480390d2dfabSRick Macklem 		cnt = 0;
480490d2dfabSRick Macklem 		for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
480590d2dfabSRick Macklem 			if (notify[i] != 0)
480690d2dfabSRick Macklem 				cnt = i + 1;
480790d2dfabSRick Macklem 		}
480890d2dfabSRick Macklem 		NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
480990d2dfabSRick Macklem 		*tl++ = txdr_unsigned(cnt);
481090d2dfabSRick Macklem 		for (i = 0; i < cnt; i++)
481190d2dfabSRick Macklem 			*tl++ = txdr_unsigned(notify[i]);
481290d2dfabSRick Macklem 	} else if (nd->nd_repstat == NFSERR_TOOSMALL) {
481390d2dfabSRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
481490d2dfabSRick Macklem 		*tl = txdr_unsigned(maxcnt);
481590d2dfabSRick Macklem 	}
4816c59e4cc3SRick Macklem nfsmout:
4817c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4818c59e4cc3SRick Macklem 	return (error);
4819c59e4cc3SRick Macklem }
4820c59e4cc3SRick Macklem 
4821c59e4cc3SRick Macklem /*
48225d4835e4SRick Macklem  * nfsv4 test stateid service
48235d4835e4SRick Macklem  */
48245d4835e4SRick Macklem APPLESTATIC int
48255d4835e4SRick Macklem nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
4826af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
48275d4835e4SRick Macklem {
48285d4835e4SRick Macklem 	uint32_t *tl;
48295d4835e4SRick Macklem 	nfsv4stateid_t *stateidp = NULL, *tstateidp;
48305d4835e4SRick Macklem 	int cnt, error = 0, i, ret;
4831af444b18SEdward Tomasz Napierala 	struct thread *p = curthread;
48325d4835e4SRick Macklem 
48335d4835e4SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
48345d4835e4SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
48355d4835e4SRick Macklem 		goto nfsmout;
48365d4835e4SRick Macklem 	}
48375d4835e4SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
48385d4835e4SRick Macklem 	cnt = fxdr_unsigned(int, *tl);
48395d4835e4SRick Macklem 	if (cnt <= 0 || cnt > 1024) {
48405d4835e4SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
48415d4835e4SRick Macklem 		goto nfsmout;
48425d4835e4SRick Macklem 	}
48435d4835e4SRick Macklem 	stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
48445d4835e4SRick Macklem 	tstateidp = stateidp;
48455d4835e4SRick Macklem 	for (i = 0; i < cnt; i++) {
48465d4835e4SRick Macklem 		NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
48475d4835e4SRick Macklem 		tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
48485d4835e4SRick Macklem 		NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
48495d4835e4SRick Macklem 		tstateidp++;
48505d4835e4SRick Macklem 	}
48515d4835e4SRick Macklem 	NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
48525d4835e4SRick Macklem 	*tl = txdr_unsigned(cnt);
48535d4835e4SRick Macklem 	tstateidp = stateidp;
48545d4835e4SRick Macklem 	for (i = 0; i < cnt; i++) {
48555d4835e4SRick Macklem 		ret = nfsrv_teststateid(nd, tstateidp, p);
48565d4835e4SRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
48575d4835e4SRick Macklem 		*tl = txdr_unsigned(ret);
48585d4835e4SRick Macklem 		tstateidp++;
48595d4835e4SRick Macklem 	}
48605d4835e4SRick Macklem nfsmout:
48615d4835e4SRick Macklem 	free(stateidp, M_TEMP);
48625d4835e4SRick Macklem 	NFSEXITCODE2(error, nd);
48635d4835e4SRick Macklem 	return (error);
48645d4835e4SRick Macklem }
48655d4835e4SRick Macklem 
48665d4835e4SRick Macklem /*
4867c59e4cc3SRick Macklem  * nfsv4 service not supported
4868c59e4cc3SRick Macklem  */
4869c59e4cc3SRick Macklem APPLESTATIC int
4870c59e4cc3SRick Macklem nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4871af444b18SEdward Tomasz Napierala     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4872c59e4cc3SRick Macklem {
4873c59e4cc3SRick Macklem 
4874c59e4cc3SRick Macklem 	nd->nd_repstat = NFSERR_NOTSUPP;
4875c59e4cc3SRick Macklem 	NFSEXITCODE2(0, nd);
4876c59e4cc3SRick Macklem 	return (0);
4877c59e4cc3SRick Macklem }
4878c59e4cc3SRick Macklem 
4879