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