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