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