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