2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * These functions support the macros and help fiddle mbuf chains for
39 * the nfs op functions. They do things like create the rpc header and
40 * copy data between mbuf chains and uio lists.
43 #include "opt_inet6.h"
45 #include <fs/nfs/nfsport.h>
48 * Data items converted to xdr at startup, since they are constant
49 * This is kinda hokey, but may save a little time doing byte swaps
51 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
53 /* And other global data */
54 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
56 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
57 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
58 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
61 struct nfssockreq nfsrv_nfsuserdsock;
62 int nfsrv_nfsuserd = 0;
63 struct nfsreqhead nfsd_reqq;
64 uid_t nfsrv_defaultuid;
65 gid_t nfsrv_defaultgid;
66 int nfsrv_lease = NFSRV_LEASE;
67 int ncl_mbuf_mlen = MLEN;
72 * This array of structures indicates, for V4:
73 * retfh - which of 3 types of calling args are used
74 * 0 - doesn't change cfh or use a sfh
75 * 1 - replaces cfh with a new one (unless it returns an error status)
76 * 2 - uses cfh and sfh
77 * needscfh - if the op wants a cfh and premtime
78 * 0 - doesn't use a cfh
79 * 1 - uses a cfh, but doesn't want pre-op attributes
80 * 2 - uses a cfh and wants pre-op attributes
81 * savereply - indicates a non-idempotent Op
82 * 0 - not non-idempotent
84 * Ops that are ordered via seqid# are handled separately from these
86 * Define it here, since it is used by both the client and server.
88 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
89 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
90 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
91 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
92 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Access */
93 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Close */
94 { 0, 2, 0, 1, LK_EXCLUSIVE, 1 }, /* Commit */
95 { 1, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Create */
96 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegpurge */
97 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegreturn */
98 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Getattr */
99 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* GetFH */
100 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Link */
101 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lock */
102 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockT */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockU */
104 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */
105 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookupp */
106 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* NVerify */
107 { 1, 1, 0, 1, LK_EXCLUSIVE, 1 }, /* Open */
108 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenAttr */
109 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenConfirm */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenDowngrade */
111 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutFH */
112 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutPubFH */
113 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutRootFH */
114 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Read */
115 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Readdir */
116 { 0, 1, 0, 0, LK_SHARED, 1 }, /* ReadLink */
117 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Remove */
118 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Rename */
119 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Renew */
120 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* RestoreFH */
121 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SaveFH */
122 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SecInfo */
123 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Setattr */
124 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientID */
125 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientIDConfirm */
126 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Verify */
127 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Write */
128 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* ReleaseLockOwner */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Backchannel Ctrl */
130 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Bind Conn to Sess */
131 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Exchange ID */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Create Session */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy Session */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Free StateID */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Dir Deleg */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device Info */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device List */
138 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Commit */
139 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Get */
140 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Return */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Secinfo No name */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Sequence */
143 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Set SSV */
144 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Test StateID */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Want Delegation */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy ClientID */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Reclaim Complete */
149 #endif /* !APPLEKEXT */
151 static int ncl_mbuf_mhlen = MHLEN;
152 static int nfsrv_usercnt = 0;
153 static int nfsrv_dnsnamelen;
154 static u_char *nfsrv_dnsname = NULL;
155 static int nfsrv_usermax = 999999999;
156 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
157 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
158 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
159 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
160 static struct nfsuserlruhead nfsuserlruhead;
163 * This static array indicates whether or not the RPC generates a large
164 * reply. This is used by nfs_reply() to decide whether or not an mbuf
165 * cluster should be allocated. (If a cluster is required by an RPC
166 * marked 0 in this array, the code will still work, just not quite as
169 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
170 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
173 /* local functions */
174 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
175 static void nfsv4_wanted(struct nfsv4lock *lp);
176 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
177 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
179 static void nfsrv_removeuser(struct nfsusrgrp *usrp);
180 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
182 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
187 * copies mbuf chain to the uio scatter/gather list
190 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
192 char *mbufcp, *uiocp;
199 mbufcp = nd->nd_dpos;
200 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
201 rem = NFSM_RNDUP(siz) - siz;
203 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
207 left = uiop->uio_iov->iov_len;
208 uiocp = uiop->uio_iov->iov_base;
219 mbufcp = NFSMTOD(mp, caddr_t);
221 KASSERT(len > 0, ("len %d", len));
223 xfer = (left > len) ? len : left;
226 if (uiop->uio_iov->iov_op != NULL)
227 (*(uiop->uio_iov->iov_op))
228 (mbufcp, uiocp, xfer);
231 if (uiop->uio_segflg == UIO_SYSSPACE)
232 NFSBCOPY(mbufcp, uiocp, xfer);
234 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
239 uiop->uio_offset += xfer;
240 uiop->uio_resid -= xfer;
242 if (uiop->uio_iov->iov_len <= siz) {
246 uiop->uio_iov->iov_base = (void *)
247 ((char *)uiop->uio_iov->iov_base + uiosiz);
248 uiop->uio_iov->iov_len -= uiosiz;
252 nd->nd_dpos = mbufcp;
256 error = nfsm_advance(nd, rem, len);
262 NFSEXITCODE2(error, nd);
268 * Help break down an mbuf chain by setting the first siz bytes contiguous
269 * pointed to by returned val.
270 * This is used by the macro NFSM_DISSECT for tough
274 nfsm_dissct(struct nfsrv_descript *nd, int siz)
283 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
285 nd->nd_md = mbuf_next(nd->nd_md);
286 if (nd->nd_md == NULL)
288 left = mbuf_len(nd->nd_md);
289 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
294 } else if (mbuf_next(nd->nd_md) == NULL) {
296 } else if (siz > ncl_mbuf_mhlen) {
297 panic("nfs S too big");
300 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
301 mbuf_setnext(nd->nd_md, mp2);
302 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
304 retp = p = NFSMTOD(mp2, caddr_t);
305 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
308 mp2 = mbuf_next(mp2);
309 /* Loop around copying up the siz2 bytes */
313 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
315 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
316 NFSM_DATAP(mp2, xfer);
317 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
322 mp2 = mbuf_next(mp2);
324 mbuf_setlen(nd->nd_md, siz);
326 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
332 * Advance the position in the mbuf chain.
333 * If offs == 0, this is a no-op, but it is simpler to just return from
334 * here than check for offs > 0 for all calls to nfsm_advance.
335 * If left == -1, it should be calculated here.
338 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
345 * A negative offs should be considered a serious problem.
348 panic("nfsrv_advance");
351 * If left == -1, calculate it here.
354 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
358 * Loop around, advancing over the mbuf data.
360 while (offs > left) {
362 nd->nd_md = mbuf_next(nd->nd_md);
363 if (nd->nd_md == NULL) {
367 left = mbuf_len(nd->nd_md);
368 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
378 * Copy a string into mbuf(s).
379 * Return the number of bytes output, including XDR overheads.
382 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
391 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
392 *tl = txdr_unsigned(siz);
393 rem = NFSM_RNDUP(siz) - siz;
394 bytesize = NFSX_UNSIGNED + siz + rem;
397 left = M_TRAILINGSPACE(m2);
400 * Loop around copying the string to mbuf(s).
404 if (siz > ncl_mbuf_mlen)
405 NFSMCLGET(m1, M_WAITOK);
409 mbuf_setnext(m2, m1);
411 cp2 = NFSMTOD(m2, caddr_t);
412 left = M_TRAILINGSPACE(m2);
418 NFSBCOPY(cp, cp2, xfer);
420 mbuf_setlen(m2, mbuf_len(m2) + xfer);
423 if (siz == 0 && rem) {
425 panic("nfsm_strtom");
426 NFSBZERO(cp2 + xfer, rem);
427 mbuf_setlen(m2, mbuf_len(m2) + rem);
431 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
436 * Called once to initialize data structures...
441 static int nfs_inited = 0;
447 newnfs_true = txdr_unsigned(TRUE);
448 newnfs_false = txdr_unsigned(FALSE);
449 newnfs_xdrneg1 = txdr_unsigned(-1);
450 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
453 NFSSETBOOTTIME(nfsboottime);
456 * Initialize reply list and start timer
458 TAILQ_INIT(&nfsd_reqq);
463 * Put a file handle in an mbuf list.
464 * If the size argument == 0, just use the default size.
465 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
466 * Return the number of bytes output, including XDR overhead.
469 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
473 int fullsiz, rem, bytesize = 0;
477 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
479 if (size > NFSX_V2FH)
480 panic("fh size > NFSX_V2FH for NFSv2");
481 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
482 NFSBCOPY(fhp, cp, size);
483 if (size < NFSX_V2FH)
484 NFSBZERO(cp + size, NFSX_V2FH - size);
485 bytesize = NFSX_V2FH;
489 fullsiz = NFSM_RNDUP(size);
490 rem = fullsiz - size;
492 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
493 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
496 bytesize = NFSX_UNSIGNED + fullsiz;
498 (void) nfsm_strtom(nd, fhp, size);
505 * This function compares two net addresses by family and returns TRUE
506 * if they are the same host.
507 * If there is any doubt, return FALSE.
508 * The AF_INET family is handled as a special case so that address mbufs
509 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
512 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
514 struct sockaddr_in *inetaddr;
518 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
519 if (inetaddr->sin_family == AF_INET &&
520 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
526 struct sockaddr_in6 *inetaddr6;
528 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
529 /* XXX - should test sin6_scope_id ? */
530 if (inetaddr6->sin6_family == AF_INET6 &&
531 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
542 * Similar to the above, but takes to NFSSOCKADDR_T args.
545 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
547 struct sockaddr_in *addr1, *addr2;
548 struct sockaddr *inaddr;
550 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
551 switch (inaddr->sa_family) {
553 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
554 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
555 if (addr2->sin_family == AF_INET &&
556 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
562 struct sockaddr_in6 *inet6addr1, *inet6addr2;
564 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
565 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
566 /* XXX - should test sin6_scope_id ? */
567 if (inet6addr2->sin6_family == AF_INET6 &&
568 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
569 &inet6addr2->sin6_addr))
580 * Trim the stuff already dissected off the mbuf list.
583 newnfs_trimleading(nd)
584 struct nfsrv_descript *nd;
590 * First, free up leading mbufs.
592 if (nd->nd_mrep != nd->nd_md) {
594 while (mbuf_next(m) != nd->nd_md) {
595 if (mbuf_next(m) == NULL)
596 panic("nfsm trim leading");
599 mbuf_setnext(m, NULL);
600 mbuf_freem(nd->nd_mrep);
605 * Now, adjust this mbuf, based on nd_dpos.
607 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
608 if (offs == mbuf_len(m)) {
612 panic("nfsm trim leading2");
613 mbuf_setnext(n, NULL);
615 } else if (offs > 0) {
616 mbuf_setlen(m, mbuf_len(m) - offs);
619 panic("nfsm trimleading offs");
622 nd->nd_dpos = NFSMTOD(m, caddr_t);
626 * Trim trailing data off the mbuf list being built.
629 newnfs_trimtrailing(nd, mb, bpos)
630 struct nfsrv_descript *nd;
636 mbuf_freem(mbuf_next(mb));
637 mbuf_setnext(mb, NULL);
639 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
645 * Dissect a file handle on the client.
648 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
655 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
656 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
657 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
664 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
666 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
668 FREE((caddr_t)nfhp, M_NFSFH);
674 NFSEXITCODE2(error, nd);
679 * Break down the nfsv4 acl.
680 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
683 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
684 int *aclsizep, __unused NFSPROC_T *p)
688 int acecnt, error = 0, aceerr = 0, acesize;
694 * Parse out the ace entries and expect them to conform to
695 * what can be supported by R/W/X bits.
697 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
698 aclsize = NFSX_UNSIGNED;
699 acecnt = fxdr_unsigned(int, *tl);
700 if (acecnt > ACL_MAX_ENTRIES)
701 aceerr = NFSERR_ATTRNOTSUPP;
702 if (nfsrv_useacl == 0)
703 aceerr = NFSERR_ATTRNOTSUPP;
704 for (i = 0; i < acecnt; i++) {
706 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
707 &aceerr, &acesize, p);
709 error = nfsrv_skipace(nd, &acesize);
715 aclp->acl_cnt = acecnt;
721 NFSEXITCODE2(error, nd);
726 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
729 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
734 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
735 len = fxdr_unsigned(int, *(tl + 3));
736 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
738 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
739 NFSEXITCODE2(error, nd);
744 * Get attribute bits from an mbuf list.
745 * Returns EBADRPC for a parsing error, 0 otherwise.
746 * If the clearinvalid flag is set, clear the bits not supported.
749 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
756 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
757 cnt = fxdr_unsigned(int, *tl);
759 error = NFSERR_BADXDR;
762 if (cnt > NFSATTRBIT_MAXWORDS) {
763 outcnt = NFSATTRBIT_MAXWORDS;
765 *retnotsupp = NFSERR_ATTRNOTSUPP;
769 NFSZERO_ATTRBIT(attrbitp);
771 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
772 for (i = 0; i < outcnt; i++)
773 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
776 error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1);
778 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
780 NFSEXITCODE2(error, nd);
785 * Get the attributes for V4.
786 * If the compare flag is true, test for any attribute changes,
787 * otherwise return the attribute values.
788 * These attributes cover fields in "struct vattr", "struct statfs",
789 * "struct nfsfsinfo", the file handle and the lease duration.
790 * The value of retcmpp is set to 1 if all attributes are the same,
792 * Returns EBADRPC if it can't be parsed, 0 otherwise.
795 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
796 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
797 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
798 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
799 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
802 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
803 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
804 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
805 nfsattrbit_t attrbits, retattrbits, checkattrbits;
807 struct nfsreferral *refp;
810 struct timespec temptime;
814 u_int32_t freenum = 0, tuint;
815 u_int64_t uquad = 0, thyp, thyp2;
823 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
825 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
831 *retcmpp = retnotsup;
834 * Just set default values to some of the important ones.
839 nap->na_rdev = (NFSDEV_T)0;
840 nap->na_mtime.tv_sec = 0;
841 nap->na_mtime.tv_nsec = 0;
844 nap->na_blocksize = NFS_FABLKSIZE;
847 sbp->f_bsize = NFS_FABLKSIZE;
855 fsp->fs_rtmax = 8192;
856 fsp->fs_rtpref = 8192;
857 fsp->fs_maxname = NFS_MAXNAMLEN;
858 fsp->fs_wtmax = 8192;
859 fsp->fs_wtpref = 8192;
860 fsp->fs_wtmult = NFS_FABLKSIZE;
861 fsp->fs_dtpref = 8192;
862 fsp->fs_maxfilesize = 0xffffffffffffffffull;
863 fsp->fs_timedelta.tv_sec = 0;
864 fsp->fs_timedelta.tv_nsec = 1;
865 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
866 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
869 pc->pc_linkmax = LINK_MAX;
870 pc->pc_namemax = NAME_MAX;
872 pc->pc_chownrestricted = 0;
873 pc->pc_caseinsensitive = 0;
874 pc->pc_casepreserving = 1;
879 * Loop around getting the attributes.
881 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
882 attrsize = fxdr_unsigned(int, *tl);
883 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
884 if (attrsum > attrsize) {
885 error = NFSERR_BADXDR;
888 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
890 case NFSATTRBIT_SUPPORTEDATTRS:
892 if (compare || nap == NULL)
893 error = nfsrv_getattrbits(nd, &retattrbits,
896 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
900 if (compare && !(*retcmpp)) {
901 NFSSETSUPP_ATTRBIT(&checkattrbits);
902 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
904 *retcmpp = NFSERR_NOTSAME;
908 case NFSATTRBIT_TYPE:
909 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
912 if (nap->na_type != nfsv34tov_type(*tl))
913 *retcmpp = NFSERR_NOTSAME;
915 } else if (nap != NULL) {
916 nap->na_type = nfsv34tov_type(*tl);
918 attrsum += NFSX_UNSIGNED;
920 case NFSATTRBIT_FHEXPIRETYPE:
921 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
922 if (compare && !(*retcmpp)) {
923 if (fxdr_unsigned(int, *tl) !=
924 NFSV4FHTYPE_PERSISTENT)
925 *retcmpp = NFSERR_NOTSAME;
927 attrsum += NFSX_UNSIGNED;
929 case NFSATTRBIT_CHANGE:
930 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
933 if (nap->na_filerev != fxdr_hyper(tl))
934 *retcmpp = NFSERR_NOTSAME;
936 } else if (nap != NULL) {
937 nap->na_filerev = fxdr_hyper(tl);
939 attrsum += NFSX_HYPER;
941 case NFSATTRBIT_SIZE:
942 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
945 if (nap->na_size != fxdr_hyper(tl))
946 *retcmpp = NFSERR_NOTSAME;
948 } else if (nap != NULL) {
949 nap->na_size = fxdr_hyper(tl);
951 attrsum += NFSX_HYPER;
953 case NFSATTRBIT_LINKSUPPORT:
954 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
957 if (fsp->fs_properties & NFSV3_FSFLINK) {
958 if (*tl == newnfs_false)
959 *retcmpp = NFSERR_NOTSAME;
961 if (*tl == newnfs_true)
962 *retcmpp = NFSERR_NOTSAME;
965 } else if (fsp != NULL) {
966 if (*tl == newnfs_true)
967 fsp->fs_properties |= NFSV3_FSFLINK;
969 fsp->fs_properties &= ~NFSV3_FSFLINK;
971 attrsum += NFSX_UNSIGNED;
973 case NFSATTRBIT_SYMLINKSUPPORT:
974 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
977 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
978 if (*tl == newnfs_false)
979 *retcmpp = NFSERR_NOTSAME;
981 if (*tl == newnfs_true)
982 *retcmpp = NFSERR_NOTSAME;
985 } else if (fsp != NULL) {
986 if (*tl == newnfs_true)
987 fsp->fs_properties |= NFSV3_FSFSYMLINK;
989 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
991 attrsum += NFSX_UNSIGNED;
993 case NFSATTRBIT_NAMEDATTR:
994 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
995 if (compare && !(*retcmpp)) {
996 if (*tl != newnfs_false)
997 *retcmpp = NFSERR_NOTSAME;
999 attrsum += NFSX_UNSIGNED;
1001 case NFSATTRBIT_FSID:
1002 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1003 thyp = fxdr_hyper(tl);
1005 thyp2 = fxdr_hyper(tl);
1007 if (*retcmpp == 0) {
1008 if (thyp != (u_int64_t)
1009 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1010 thyp2 != (u_int64_t)
1011 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1012 *retcmpp = NFSERR_NOTSAME;
1014 } else if (nap != NULL) {
1015 nap->na_filesid[0] = thyp;
1016 nap->na_filesid[1] = thyp2;
1018 attrsum += (4 * NFSX_UNSIGNED);
1020 case NFSATTRBIT_UNIQUEHANDLES:
1021 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1022 if (compare && !(*retcmpp)) {
1023 if (*tl != newnfs_true)
1024 *retcmpp = NFSERR_NOTSAME;
1026 attrsum += NFSX_UNSIGNED;
1028 case NFSATTRBIT_LEASETIME:
1029 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1031 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1033 *retcmpp = NFSERR_NOTSAME;
1034 } else if (leasep != NULL) {
1035 *leasep = fxdr_unsigned(u_int32_t, *tl);
1037 attrsum += NFSX_UNSIGNED;
1039 case NFSATTRBIT_RDATTRERROR:
1040 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1043 *retcmpp = NFSERR_INVAL;
1044 } else if (rderrp != NULL) {
1045 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1047 attrsum += NFSX_UNSIGNED;
1049 case NFSATTRBIT_ACL:
1055 naclp = acl_alloc(M_WAITOK);
1056 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1062 if (aceerr || aclp == NULL ||
1063 nfsrv_compareacl(aclp, naclp))
1064 *retcmpp = NFSERR_NOTSAME;
1067 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1069 *retcmpp = NFSERR_ATTRNOTSUPP;
1073 if (vp != NULL && aclp != NULL)
1074 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1077 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1084 case NFSATTRBIT_ACLSUPPORT:
1085 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1086 if (compare && !(*retcmpp)) {
1088 if (fxdr_unsigned(u_int32_t, *tl) !=
1090 *retcmpp = NFSERR_NOTSAME;
1092 *retcmpp = NFSERR_ATTRNOTSUPP;
1095 attrsum += NFSX_UNSIGNED;
1097 case NFSATTRBIT_ARCHIVE:
1098 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1099 if (compare && !(*retcmpp))
1100 *retcmpp = NFSERR_ATTRNOTSUPP;
1101 attrsum += NFSX_UNSIGNED;
1103 case NFSATTRBIT_CANSETTIME:
1104 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1107 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1108 if (*tl == newnfs_false)
1109 *retcmpp = NFSERR_NOTSAME;
1111 if (*tl == newnfs_true)
1112 *retcmpp = NFSERR_NOTSAME;
1115 } else if (fsp != NULL) {
1116 if (*tl == newnfs_true)
1117 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1119 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1121 attrsum += NFSX_UNSIGNED;
1123 case NFSATTRBIT_CASEINSENSITIVE:
1124 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1127 if (*tl != newnfs_false)
1128 *retcmpp = NFSERR_NOTSAME;
1130 } else if (pc != NULL) {
1131 pc->pc_caseinsensitive =
1132 fxdr_unsigned(u_int32_t, *tl);
1134 attrsum += NFSX_UNSIGNED;
1136 case NFSATTRBIT_CASEPRESERVING:
1137 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1140 if (*tl != newnfs_true)
1141 *retcmpp = NFSERR_NOTSAME;
1143 } else if (pc != NULL) {
1144 pc->pc_casepreserving =
1145 fxdr_unsigned(u_int32_t, *tl);
1147 attrsum += NFSX_UNSIGNED;
1149 case NFSATTRBIT_CHOWNRESTRICTED:
1150 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1153 if (*tl != newnfs_true)
1154 *retcmpp = NFSERR_NOTSAME;
1156 } else if (pc != NULL) {
1157 pc->pc_chownrestricted =
1158 fxdr_unsigned(u_int32_t, *tl);
1160 attrsum += NFSX_UNSIGNED;
1162 case NFSATTRBIT_FILEHANDLE:
1163 error = nfsm_getfh(nd, &tnfhp);
1166 tfhsize = tnfhp->nfh_len;
1169 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1171 *retcmpp = NFSERR_NOTSAME;
1172 FREE((caddr_t)tnfhp, M_NFSFH);
1173 } else if (nfhpp != NULL) {
1176 FREE((caddr_t)tnfhp, M_NFSFH);
1178 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1180 case NFSATTRBIT_FILEID:
1181 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1182 thyp = fxdr_hyper(tl);
1185 if ((u_int64_t)nap->na_fileid != thyp)
1186 *retcmpp = NFSERR_NOTSAME;
1188 } else if (nap != NULL) {
1190 printf("NFSv4 fileid > 32bits\n");
1191 nap->na_fileid = thyp;
1193 attrsum += NFSX_HYPER;
1195 case NFSATTRBIT_FILESAVAIL:
1196 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1199 sfp->sf_afiles != fxdr_hyper(tl))
1200 *retcmpp = NFSERR_NOTSAME;
1201 } else if (sfp != NULL) {
1202 sfp->sf_afiles = fxdr_hyper(tl);
1204 attrsum += NFSX_HYPER;
1206 case NFSATTRBIT_FILESFREE:
1207 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1210 sfp->sf_ffiles != fxdr_hyper(tl))
1211 *retcmpp = NFSERR_NOTSAME;
1212 } else if (sfp != NULL) {
1213 sfp->sf_ffiles = fxdr_hyper(tl);
1215 attrsum += NFSX_HYPER;
1217 case NFSATTRBIT_FILESTOTAL:
1218 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1221 sfp->sf_tfiles != fxdr_hyper(tl))
1222 *retcmpp = NFSERR_NOTSAME;
1223 } else if (sfp != NULL) {
1224 sfp->sf_tfiles = fxdr_hyper(tl);
1226 attrsum += NFSX_HYPER;
1228 case NFSATTRBIT_FSLOCATIONS:
1229 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1233 if (compare && !(*retcmpp)) {
1234 refp = nfsv4root_getreferral(vp, NULL, 0);
1236 if (cp == NULL || cp2 == NULL ||
1238 strcmp(cp2, refp->nfr_srvlist))
1239 *retcmpp = NFSERR_NOTSAME;
1240 } else if (m == 0) {
1241 *retcmpp = NFSERR_NOTSAME;
1245 free(cp, M_NFSSTRING);
1247 free(cp2, M_NFSSTRING);
1249 case NFSATTRBIT_HIDDEN:
1250 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1251 if (compare && !(*retcmpp))
1252 *retcmpp = NFSERR_ATTRNOTSUPP;
1253 attrsum += NFSX_UNSIGNED;
1255 case NFSATTRBIT_HOMOGENEOUS:
1256 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1259 if (fsp->fs_properties &
1260 NFSV3_FSFHOMOGENEOUS) {
1261 if (*tl == newnfs_false)
1262 *retcmpp = NFSERR_NOTSAME;
1264 if (*tl == newnfs_true)
1265 *retcmpp = NFSERR_NOTSAME;
1268 } else if (fsp != NULL) {
1269 if (*tl == newnfs_true)
1270 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1272 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1274 attrsum += NFSX_UNSIGNED;
1276 case NFSATTRBIT_MAXFILESIZE:
1277 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1278 tnfsquad.qval = fxdr_hyper(tl);
1281 tquad = NFSRV_MAXFILESIZE;
1282 if (tquad != tnfsquad.qval)
1283 *retcmpp = NFSERR_NOTSAME;
1285 } else if (fsp != NULL) {
1286 fsp->fs_maxfilesize = tnfsquad.qval;
1288 attrsum += NFSX_HYPER;
1290 case NFSATTRBIT_MAXLINK:
1291 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1294 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1295 *retcmpp = NFSERR_NOTSAME;
1297 } else if (pc != NULL) {
1298 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1300 attrsum += NFSX_UNSIGNED;
1302 case NFSATTRBIT_MAXNAME:
1303 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1306 if (fsp->fs_maxname !=
1307 fxdr_unsigned(u_int32_t, *tl))
1308 *retcmpp = NFSERR_NOTSAME;
1311 tuint = fxdr_unsigned(u_int32_t, *tl);
1313 * Some Linux NFSv4 servers report this
1314 * as 0 or 4billion, so I'll set it to
1315 * NFS_MAXNAMLEN. If a server actually creates
1316 * a name longer than NFS_MAXNAMLEN, it will
1317 * get an error back.
1319 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1320 tuint = NFS_MAXNAMLEN;
1322 fsp->fs_maxname = tuint;
1324 pc->pc_namemax = tuint;
1326 attrsum += NFSX_UNSIGNED;
1328 case NFSATTRBIT_MAXREAD:
1329 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1332 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1333 *(tl + 1)) || *tl != 0)
1334 *retcmpp = NFSERR_NOTSAME;
1336 } else if (fsp != NULL) {
1337 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1338 fsp->fs_rtpref = fsp->fs_rtmax;
1339 fsp->fs_dtpref = fsp->fs_rtpref;
1341 attrsum += NFSX_HYPER;
1343 case NFSATTRBIT_MAXWRITE:
1344 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1347 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1348 *(tl + 1)) || *tl != 0)
1349 *retcmpp = NFSERR_NOTSAME;
1351 } else if (fsp != NULL) {
1352 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1353 fsp->fs_wtpref = fsp->fs_wtmax;
1355 attrsum += NFSX_HYPER;
1357 case NFSATTRBIT_MIMETYPE:
1358 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1359 i = fxdr_unsigned(int, *tl);
1360 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1361 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1364 if (compare && !(*retcmpp))
1365 *retcmpp = NFSERR_ATTRNOTSUPP;
1367 case NFSATTRBIT_MODE:
1368 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1371 if (nap->na_mode != nfstov_mode(*tl))
1372 *retcmpp = NFSERR_NOTSAME;
1374 } else if (nap != NULL) {
1375 nap->na_mode = nfstov_mode(*tl);
1377 attrsum += NFSX_UNSIGNED;
1379 case NFSATTRBIT_NOTRUNC:
1380 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1383 if (*tl != newnfs_true)
1384 *retcmpp = NFSERR_NOTSAME;
1386 } else if (pc != NULL) {
1387 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1389 attrsum += NFSX_UNSIGNED;
1391 case NFSATTRBIT_NUMLINKS:
1392 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1393 tuint = fxdr_unsigned(u_int32_t, *tl);
1396 if ((u_int32_t)nap->na_nlink != tuint)
1397 *retcmpp = NFSERR_NOTSAME;
1399 } else if (nap != NULL) {
1400 nap->na_nlink = tuint;
1402 attrsum += NFSX_UNSIGNED;
1404 case NFSATTRBIT_OWNER:
1405 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1406 j = fxdr_unsigned(int, *tl);
1408 error = NFSERR_BADXDR;
1411 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1412 if (j > NFSV4_SMALLSTR)
1413 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1416 error = nfsrv_mtostr(nd, cp, j);
1418 if (j > NFSV4_SMALLSTR)
1419 free(cp, M_NFSSTRING);
1424 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1426 *retcmpp = NFSERR_NOTSAME;
1428 } else if (nap != NULL) {
1429 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1430 nap->na_uid = nfsrv_defaultuid;
1434 if (j > NFSV4_SMALLSTR)
1435 free(cp, M_NFSSTRING);
1437 case NFSATTRBIT_OWNERGROUP:
1438 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1439 j = fxdr_unsigned(int, *tl);
1441 error = NFSERR_BADXDR;
1444 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1445 if (j > NFSV4_SMALLSTR)
1446 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1449 error = nfsrv_mtostr(nd, cp, j);
1451 if (j > NFSV4_SMALLSTR)
1452 free(cp, M_NFSSTRING);
1457 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1459 *retcmpp = NFSERR_NOTSAME;
1461 } else if (nap != NULL) {
1462 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1463 nap->na_gid = nfsrv_defaultgid;
1467 if (j > NFSV4_SMALLSTR)
1468 free(cp, M_NFSSTRING);
1470 case NFSATTRBIT_QUOTAHARD:
1471 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1473 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1474 freenum = sbp->f_bfree;
1476 freenum = sbp->f_bavail;
1479 * ufs_quotactl() insists that the uid argument
1480 * equal p_ruid for non-root quota access, so
1481 * we'll just make sure that's the case.
1483 savuid = p->p_cred->p_ruid;
1484 p->p_cred->p_ruid = cred->cr_uid;
1485 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1486 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1487 freenum = min(dqb.dqb_bhardlimit, freenum);
1488 p->p_cred->p_ruid = savuid;
1490 uquad = (u_int64_t)freenum;
1491 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1493 if (compare && !(*retcmpp)) {
1494 if (uquad != fxdr_hyper(tl))
1495 *retcmpp = NFSERR_NOTSAME;
1497 attrsum += NFSX_HYPER;
1499 case NFSATTRBIT_QUOTASOFT:
1500 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1502 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1503 freenum = sbp->f_bfree;
1505 freenum = sbp->f_bavail;
1508 * ufs_quotactl() insists that the uid argument
1509 * equal p_ruid for non-root quota access, so
1510 * we'll just make sure that's the case.
1512 savuid = p->p_cred->p_ruid;
1513 p->p_cred->p_ruid = cred->cr_uid;
1514 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1515 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1516 freenum = min(dqb.dqb_bsoftlimit, freenum);
1517 p->p_cred->p_ruid = savuid;
1519 uquad = (u_int64_t)freenum;
1520 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1522 if (compare && !(*retcmpp)) {
1523 if (uquad != fxdr_hyper(tl))
1524 *retcmpp = NFSERR_NOTSAME;
1526 attrsum += NFSX_HYPER;
1528 case NFSATTRBIT_QUOTAUSED:
1529 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1534 * ufs_quotactl() insists that the uid argument
1535 * equal p_ruid for non-root quota access, so
1536 * we'll just make sure that's the case.
1538 savuid = p->p_cred->p_ruid;
1539 p->p_cred->p_ruid = cred->cr_uid;
1540 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1541 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1542 freenum = dqb.dqb_curblocks;
1543 p->p_cred->p_ruid = savuid;
1545 uquad = (u_int64_t)freenum;
1546 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1548 if (compare && !(*retcmpp)) {
1549 if (uquad != fxdr_hyper(tl))
1550 *retcmpp = NFSERR_NOTSAME;
1552 attrsum += NFSX_HYPER;
1554 case NFSATTRBIT_RAWDEV:
1555 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1556 j = fxdr_unsigned(int, *tl++);
1557 k = fxdr_unsigned(int, *tl);
1560 if (nap->na_rdev != NFSMAKEDEV(j, k))
1561 *retcmpp = NFSERR_NOTSAME;
1563 } else if (nap != NULL) {
1564 nap->na_rdev = NFSMAKEDEV(j, k);
1566 attrsum += NFSX_V4SPECDATA;
1568 case NFSATTRBIT_SPACEAVAIL:
1569 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1572 sfp->sf_abytes != fxdr_hyper(tl))
1573 *retcmpp = NFSERR_NOTSAME;
1574 } else if (sfp != NULL) {
1575 sfp->sf_abytes = fxdr_hyper(tl);
1577 attrsum += NFSX_HYPER;
1579 case NFSATTRBIT_SPACEFREE:
1580 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1583 sfp->sf_fbytes != fxdr_hyper(tl))
1584 *retcmpp = NFSERR_NOTSAME;
1585 } else if (sfp != NULL) {
1586 sfp->sf_fbytes = fxdr_hyper(tl);
1588 attrsum += NFSX_HYPER;
1590 case NFSATTRBIT_SPACETOTAL:
1591 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1594 sfp->sf_tbytes != fxdr_hyper(tl))
1595 *retcmpp = NFSERR_NOTSAME;
1596 } else if (sfp != NULL) {
1597 sfp->sf_tbytes = fxdr_hyper(tl);
1599 attrsum += NFSX_HYPER;
1601 case NFSATTRBIT_SPACEUSED:
1602 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1603 thyp = fxdr_hyper(tl);
1606 if ((u_int64_t)nap->na_bytes != thyp)
1607 *retcmpp = NFSERR_NOTSAME;
1609 } else if (nap != NULL) {
1610 nap->na_bytes = thyp;
1612 attrsum += NFSX_HYPER;
1614 case NFSATTRBIT_SYSTEM:
1615 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1616 if (compare && !(*retcmpp))
1617 *retcmpp = NFSERR_ATTRNOTSUPP;
1618 attrsum += NFSX_UNSIGNED;
1620 case NFSATTRBIT_TIMEACCESS:
1621 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1622 fxdr_nfsv4time(tl, &temptime);
1625 if (!NFS_CMPTIME(temptime, nap->na_atime))
1626 *retcmpp = NFSERR_NOTSAME;
1628 } else if (nap != NULL) {
1629 nap->na_atime = temptime;
1631 attrsum += NFSX_V4TIME;
1633 case NFSATTRBIT_TIMEACCESSSET:
1634 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1635 attrsum += NFSX_UNSIGNED;
1636 i = fxdr_unsigned(int, *tl);
1637 if (i == NFSV4SATTRTIME_TOCLIENT) {
1638 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1639 attrsum += NFSX_V4TIME;
1641 if (compare && !(*retcmpp))
1642 *retcmpp = NFSERR_INVAL;
1644 case NFSATTRBIT_TIMEBACKUP:
1645 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1646 if (compare && !(*retcmpp))
1647 *retcmpp = NFSERR_ATTRNOTSUPP;
1648 attrsum += NFSX_V4TIME;
1650 case NFSATTRBIT_TIMECREATE:
1651 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1652 if (compare && !(*retcmpp))
1653 *retcmpp = NFSERR_ATTRNOTSUPP;
1654 attrsum += NFSX_V4TIME;
1656 case NFSATTRBIT_TIMEDELTA:
1657 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1661 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1662 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1663 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1664 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1667 *retcmpp = NFSERR_NOTSAME;
1670 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1673 attrsum += NFSX_V4TIME;
1675 case NFSATTRBIT_TIMEMETADATA:
1676 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1677 fxdr_nfsv4time(tl, &temptime);
1680 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1681 *retcmpp = NFSERR_NOTSAME;
1683 } else if (nap != NULL) {
1684 nap->na_ctime = temptime;
1686 attrsum += NFSX_V4TIME;
1688 case NFSATTRBIT_TIMEMODIFY:
1689 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1690 fxdr_nfsv4time(tl, &temptime);
1693 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1694 *retcmpp = NFSERR_NOTSAME;
1696 } else if (nap != NULL) {
1697 nap->na_mtime = temptime;
1699 attrsum += NFSX_V4TIME;
1701 case NFSATTRBIT_TIMEMODIFYSET:
1702 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1703 attrsum += NFSX_UNSIGNED;
1704 i = fxdr_unsigned(int, *tl);
1705 if (i == NFSV4SATTRTIME_TOCLIENT) {
1706 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1707 attrsum += NFSX_V4TIME;
1709 if (compare && !(*retcmpp))
1710 *retcmpp = NFSERR_INVAL;
1712 case NFSATTRBIT_MOUNTEDONFILEID:
1713 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1714 thyp = fxdr_hyper(tl);
1718 *retcmpp = NFSERR_NOTSAME;
1720 if (!vp || !nfsrv_atroot(vp, &fid))
1721 fid = nap->na_fileid;
1722 if ((u_int64_t)fid != thyp)
1723 *retcmpp = NFSERR_NOTSAME;
1726 } else if (nap != NULL) {
1728 printf("NFSv4 mounted on fileid > 32bits\n");
1729 nap->na_mntonfileno = thyp;
1731 attrsum += NFSX_HYPER;
1734 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1736 if (compare && !(*retcmpp))
1737 *retcmpp = NFSERR_ATTRNOTSUPP;
1739 * and get out of the loop, since we can't parse
1740 * the unknown attrbute data.
1742 bitpos = NFSATTRBIT_MAX;
1748 * some clients pad the attrlist, so we need to skip over the
1751 if (attrsum > attrsize) {
1752 error = NFSERR_BADXDR;
1754 attrsize = NFSM_RNDUP(attrsize);
1755 if (attrsum < attrsize)
1756 error = nfsm_advance(nd, attrsize - attrsum, -1);
1759 NFSEXITCODE2(error, nd);
1764 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1765 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1766 * The first argument is a pointer to an nfsv4lock structure.
1767 * The second argument is 1 iff a blocking lock is wanted.
1768 * If this argument is 0, the call waits until no thread either wants nor
1769 * holds an exclusive lock.
1770 * It returns 1 if the lock was acquired, 0 otherwise.
1771 * If several processes call this function concurrently wanting the exclusive
1772 * lock, one will get the lock and the rest will return without getting the
1773 * lock. (If the caller must have the lock, it simply calls this function in a
1774 * loop until the function returns 1 to indicate the lock was acquired.)
1775 * Any usecnt must be decremented by calling nfsv4_relref() before
1776 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1777 * be called in a loop.
1778 * The isleptp argument is set to indicate if the call slept, iff not NULL
1779 * and the mp argument indicates to check for a forced dismount, iff not
1783 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1784 void *mutex, struct mount *mp)
1790 * If a lock is wanted, loop around until the lock is acquired by
1791 * someone and then released. If I want the lock, try to acquire it.
1792 * For a lock to be issued, no lock must be in force and the usecnt
1796 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1797 lp->nfslock_usecnt == 0) {
1798 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1799 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1802 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1804 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1805 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1806 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1809 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1812 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1813 PZERO - 1, "nfsv4lck", NULL);
1814 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1815 lp->nfslock_usecnt == 0) {
1816 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1817 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1825 * Release the lock acquired by nfsv4_lock().
1826 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1827 * incremented, as well.
1830 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1833 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1835 lp->nfslock_usecnt++;
1840 * Release a reference cnt.
1843 nfsv4_relref(struct nfsv4lock *lp)
1846 if (lp->nfslock_usecnt <= 0)
1847 panic("nfsv4root ref cnt");
1848 lp->nfslock_usecnt--;
1849 if (lp->nfslock_usecnt == 0)
1854 * Get a reference cnt.
1855 * This function will wait for any exclusive lock to be released, but will
1856 * not wait for threads that want the exclusive lock. If priority needs
1857 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1858 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1859 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1860 * return without getting a refcnt for that case.
1863 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1871 * Wait for a lock held.
1873 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1874 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1876 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1879 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1880 PZERO - 1, "nfsv4gr", NULL);
1882 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1885 lp->nfslock_usecnt++;
1889 * Get a reference as above, but return failure instead of sleeping if
1890 * an exclusive lock is held.
1893 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1896 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1899 lp->nfslock_usecnt++;
1904 * Test for a lock. Return 1 if locked, 0 otherwise.
1907 nfsv4_testlock(struct nfsv4lock *lp)
1910 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1911 lp->nfslock_usecnt == 0)
1917 * Wake up anyone sleeping, waiting for this lock.
1920 nfsv4_wanted(struct nfsv4lock *lp)
1923 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1924 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1925 wakeup((caddr_t)&lp->nfslock_lock);
1930 * Copy a string from an mbuf list into a character array.
1931 * Return EBADRPC if there is an mbuf error,
1935 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1944 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1945 rem = NFSM_RNDUP(siz) - siz;
1951 NFSBCOPY(cp, str, xfer);
1960 cp = NFSMTOD(mp, caddr_t);
1972 error = nfsm_advance(nd, rem, len);
1978 NFSEXITCODE2(error, nd);
1983 * Fill in the attributes as marked by the bitmap (V4).
1986 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
1987 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
1988 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
1989 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1991 int bitpos, retnum = 0;
1993 int siz, prefixnum, error;
1994 u_char *cp, namestr[NFSV4_SMALLSTR];
1995 nfsattrbit_t attrbits, retbits;
1996 nfsattrbit_t *retbitp = &retbits;
1997 u_int32_t freenum, *retnump;
2000 struct nfsfsinfo fsinf;
2001 struct timespec temptime;
2002 NFSACL_T *aclp, *naclp = NULL;
2009 * First, set the bits that can be filled and get fsinfo.
2011 NFSSET_ATTRBIT(retbitp, attrbitp);
2012 /* If p and cred are NULL, it is a client side call */
2013 if (p == NULL && cred == NULL) {
2014 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2017 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2018 naclp = acl_alloc(M_WAITOK);
2021 nfsvno_getfs(&fsinf, isdgram);
2024 * Get the VFS_STATFS(), since some attributes need them.
2026 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2027 error = VFS_STATFS(mp, &fs);
2030 nd->nd_repstat = NFSERR_ACCES;
2033 NFSCLRSTATFS_ATTRBIT(retbitp);
2039 * And the NFSv4 ACL...
2041 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2042 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2043 supports_nfsv4acls == 0))) {
2044 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2046 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2047 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2048 supports_nfsv4acls == 0)) {
2049 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2050 } else if (naclp != NULL) {
2051 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2052 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2054 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2056 NFSVOPUNLOCK(vp, 0);
2058 error = NFSERR_PERM;
2061 nd->nd_repstat = NFSERR_ACCES;
2064 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2069 * Put out the attribute bitmap for the ones being filled in
2070 * and get the field for the number of attributes returned.
2072 prefixnum = nfsrv_putattrbit(nd, retbitp);
2073 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2074 prefixnum += NFSX_UNSIGNED;
2077 * Now, loop around filling in the attributes for each bit set.
2079 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2080 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2082 case NFSATTRBIT_SUPPORTEDATTRS:
2083 NFSSETSUPP_ATTRBIT(&attrbits);
2084 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2085 && supports_nfsv4acls == 0)) {
2086 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2087 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2089 retnum += nfsrv_putattrbit(nd, &attrbits);
2091 case NFSATTRBIT_TYPE:
2092 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2093 *tl = vtonfsv34_type(vap->va_type);
2094 retnum += NFSX_UNSIGNED;
2096 case NFSATTRBIT_FHEXPIRETYPE:
2097 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2098 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2099 retnum += NFSX_UNSIGNED;
2101 case NFSATTRBIT_CHANGE:
2102 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2103 txdr_hyper(vap->va_filerev, tl);
2104 retnum += NFSX_HYPER;
2106 case NFSATTRBIT_SIZE:
2107 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2108 txdr_hyper(vap->va_size, tl);
2109 retnum += NFSX_HYPER;
2111 case NFSATTRBIT_LINKSUPPORT:
2112 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2113 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2117 retnum += NFSX_UNSIGNED;
2119 case NFSATTRBIT_SYMLINKSUPPORT:
2120 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2121 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2125 retnum += NFSX_UNSIGNED;
2127 case NFSATTRBIT_NAMEDATTR:
2128 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2130 retnum += NFSX_UNSIGNED;
2132 case NFSATTRBIT_FSID:
2133 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2135 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2137 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2138 retnum += NFSX_V4FSID;
2140 case NFSATTRBIT_UNIQUEHANDLES:
2141 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2143 retnum += NFSX_UNSIGNED;
2145 case NFSATTRBIT_LEASETIME:
2146 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2147 *tl = txdr_unsigned(nfsrv_lease);
2148 retnum += NFSX_UNSIGNED;
2150 case NFSATTRBIT_RDATTRERROR:
2151 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2152 *tl = txdr_unsigned(rderror);
2153 retnum += NFSX_UNSIGNED;
2156 * Recommended Attributes. (Only the supported ones.)
2158 case NFSATTRBIT_ACL:
2159 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2161 case NFSATTRBIT_ACLSUPPORT:
2162 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2163 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2164 retnum += NFSX_UNSIGNED;
2166 case NFSATTRBIT_CANSETTIME:
2167 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2168 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2172 retnum += NFSX_UNSIGNED;
2174 case NFSATTRBIT_CASEINSENSITIVE:
2175 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2177 retnum += NFSX_UNSIGNED;
2179 case NFSATTRBIT_CASEPRESERVING:
2180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2182 retnum += NFSX_UNSIGNED;
2184 case NFSATTRBIT_CHOWNRESTRICTED:
2185 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2187 retnum += NFSX_UNSIGNED;
2189 case NFSATTRBIT_FILEHANDLE:
2190 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2192 case NFSATTRBIT_FILEID:
2193 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2195 *tl = txdr_unsigned(vap->va_fileid);
2196 retnum += NFSX_HYPER;
2198 case NFSATTRBIT_FILESAVAIL:
2200 * Check quota and use min(quota, f_ffree).
2202 freenum = fs.f_ffree;
2205 * ufs_quotactl() insists that the uid argument
2206 * equal p_ruid for non-root quota access, so
2207 * we'll just make sure that's the case.
2209 savuid = p->p_cred->p_ruid;
2210 p->p_cred->p_ruid = cred->cr_uid;
2211 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2212 cred->cr_uid, (caddr_t)&dqb))
2213 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2215 p->p_cred->p_ruid = savuid;
2217 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2219 *tl = txdr_unsigned(freenum);
2220 retnum += NFSX_HYPER;
2222 case NFSATTRBIT_FILESFREE:
2223 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2225 *tl = txdr_unsigned(fs.f_ffree);
2226 retnum += NFSX_HYPER;
2228 case NFSATTRBIT_FILESTOTAL:
2229 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2231 *tl = txdr_unsigned(fs.f_files);
2232 retnum += NFSX_HYPER;
2234 case NFSATTRBIT_FSLOCATIONS:
2235 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2238 retnum += 2 * NFSX_UNSIGNED;
2240 case NFSATTRBIT_HOMOGENEOUS:
2241 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2242 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2246 retnum += NFSX_UNSIGNED;
2248 case NFSATTRBIT_MAXFILESIZE:
2249 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2250 uquad = NFSRV_MAXFILESIZE;
2251 txdr_hyper(uquad, tl);
2252 retnum += NFSX_HYPER;
2254 case NFSATTRBIT_MAXLINK:
2255 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2256 *tl = txdr_unsigned(LINK_MAX);
2257 retnum += NFSX_UNSIGNED;
2259 case NFSATTRBIT_MAXNAME:
2260 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2261 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2262 retnum += NFSX_UNSIGNED;
2264 case NFSATTRBIT_MAXREAD:
2265 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2267 *tl = txdr_unsigned(fsinf.fs_rtmax);
2268 retnum += NFSX_HYPER;
2270 case NFSATTRBIT_MAXWRITE:
2271 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2273 *tl = txdr_unsigned(fsinf.fs_wtmax);
2274 retnum += NFSX_HYPER;
2276 case NFSATTRBIT_MODE:
2277 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2278 *tl = vtonfsv34_mode(vap->va_mode);
2279 retnum += NFSX_UNSIGNED;
2281 case NFSATTRBIT_NOTRUNC:
2282 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2284 retnum += NFSX_UNSIGNED;
2286 case NFSATTRBIT_NUMLINKS:
2287 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2288 *tl = txdr_unsigned(vap->va_nlink);
2289 retnum += NFSX_UNSIGNED;
2291 case NFSATTRBIT_OWNER:
2293 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2294 retnum += nfsm_strtom(nd, cp, siz);
2296 free(cp, M_NFSSTRING);
2298 case NFSATTRBIT_OWNERGROUP:
2300 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2301 retnum += nfsm_strtom(nd, cp, siz);
2303 free(cp, M_NFSSTRING);
2305 case NFSATTRBIT_QUOTAHARD:
2306 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2307 freenum = fs.f_bfree;
2309 freenum = fs.f_bavail;
2312 * ufs_quotactl() insists that the uid argument
2313 * equal p_ruid for non-root quota access, so
2314 * we'll just make sure that's the case.
2316 savuid = p->p_cred->p_ruid;
2317 p->p_cred->p_ruid = cred->cr_uid;
2318 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2319 cred->cr_uid, (caddr_t)&dqb))
2320 freenum = min(dqb.dqb_bhardlimit, freenum);
2321 p->p_cred->p_ruid = savuid;
2323 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2324 uquad = (u_int64_t)freenum;
2325 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2326 txdr_hyper(uquad, tl);
2327 retnum += NFSX_HYPER;
2329 case NFSATTRBIT_QUOTASOFT:
2330 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2331 freenum = fs.f_bfree;
2333 freenum = fs.f_bavail;
2336 * ufs_quotactl() insists that the uid argument
2337 * equal p_ruid for non-root quota access, so
2338 * we'll just make sure that's the case.
2340 savuid = p->p_cred->p_ruid;
2341 p->p_cred->p_ruid = cred->cr_uid;
2342 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2343 cred->cr_uid, (caddr_t)&dqb))
2344 freenum = min(dqb.dqb_bsoftlimit, freenum);
2345 p->p_cred->p_ruid = savuid;
2347 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2348 uquad = (u_int64_t)freenum;
2349 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2350 txdr_hyper(uquad, tl);
2351 retnum += NFSX_HYPER;
2353 case NFSATTRBIT_QUOTAUSED:
2357 * ufs_quotactl() insists that the uid argument
2358 * equal p_ruid for non-root quota access, so
2359 * we'll just make sure that's the case.
2361 savuid = p->p_cred->p_ruid;
2362 p->p_cred->p_ruid = cred->cr_uid;
2363 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2364 cred->cr_uid, (caddr_t)&dqb))
2365 freenum = dqb.dqb_curblocks;
2366 p->p_cred->p_ruid = savuid;
2368 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2369 uquad = (u_int64_t)freenum;
2370 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2371 txdr_hyper(uquad, tl);
2372 retnum += NFSX_HYPER;
2374 case NFSATTRBIT_RAWDEV:
2375 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2376 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2377 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2378 retnum += NFSX_V4SPECDATA;
2380 case NFSATTRBIT_SPACEAVAIL:
2381 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2382 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2383 uquad = (u_int64_t)fs.f_bfree;
2385 uquad = (u_int64_t)fs.f_bavail;
2386 uquad *= fs.f_bsize;
2387 txdr_hyper(uquad, tl);
2388 retnum += NFSX_HYPER;
2390 case NFSATTRBIT_SPACEFREE:
2391 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2392 uquad = (u_int64_t)fs.f_bfree;
2393 uquad *= fs.f_bsize;
2394 txdr_hyper(uquad, tl);
2395 retnum += NFSX_HYPER;
2397 case NFSATTRBIT_SPACETOTAL:
2398 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2399 uquad = (u_int64_t)fs.f_blocks;
2400 uquad *= fs.f_bsize;
2401 txdr_hyper(uquad, tl);
2402 retnum += NFSX_HYPER;
2404 case NFSATTRBIT_SPACEUSED:
2405 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2406 txdr_hyper(vap->va_bytes, tl);
2407 retnum += NFSX_HYPER;
2409 case NFSATTRBIT_TIMEACCESS:
2410 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2411 txdr_nfsv4time(&vap->va_atime, tl);
2412 retnum += NFSX_V4TIME;
2414 case NFSATTRBIT_TIMEACCESSSET:
2415 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2416 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2417 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2418 txdr_nfsv4time(&vap->va_atime, tl);
2419 retnum += NFSX_V4SETTIME;
2421 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2422 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2423 retnum += NFSX_UNSIGNED;
2426 case NFSATTRBIT_TIMEDELTA:
2427 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2428 temptime.tv_sec = 0;
2429 temptime.tv_nsec = 1000000000 / hz;
2430 txdr_nfsv4time(&temptime, tl);
2431 retnum += NFSX_V4TIME;
2433 case NFSATTRBIT_TIMEMETADATA:
2434 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2435 txdr_nfsv4time(&vap->va_ctime, tl);
2436 retnum += NFSX_V4TIME;
2438 case NFSATTRBIT_TIMEMODIFY:
2439 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2440 txdr_nfsv4time(&vap->va_mtime, tl);
2441 retnum += NFSX_V4TIME;
2443 case NFSATTRBIT_TIMEMODIFYSET:
2444 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2445 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2446 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2447 txdr_nfsv4time(&vap->va_mtime, tl);
2448 retnum += NFSX_V4SETTIME;
2450 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2451 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2452 retnum += NFSX_UNSIGNED;
2455 case NFSATTRBIT_MOUNTEDONFILEID:
2456 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2458 uquad = mounted_on_fileno;
2460 uquad = (u_int64_t)vap->va_fileid;
2461 txdr_hyper(uquad, tl);
2462 retnum += NFSX_HYPER;
2465 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2471 *retnump = txdr_unsigned(retnum);
2472 return (retnum + prefixnum);
2476 * Put the attribute bits onto an mbuf list.
2477 * Return the number of bytes of output generated.
2480 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2483 int cnt, i, bytesize;
2485 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2486 if (attrbitp->bits[cnt - 1])
2488 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2489 NFSM_BUILD(tl, u_int32_t *, bytesize);
2490 *tl++ = txdr_unsigned(cnt);
2491 for (i = 0; i < cnt; i++)
2492 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2497 * Convert a uid to a string.
2498 * If the lookup fails, just output the digits.
2500 * cpp - points to a buffer of size NFSV4_SMALLSTR
2501 * (malloc a larger one, as required)
2502 * retlenp - pointer to length to be returned
2505 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2508 struct nfsusrgrp *usrp;
2511 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2516 if (nfsrv_dnsname) {
2518 * Always map nfsrv_defaultuid to "nobody".
2520 if (uid == nfsrv_defaultuid) {
2521 i = nfsrv_dnsnamelen + 7;
2524 if (len > NFSV4_SMALLSTR)
2525 free(cp, M_NFSSTRING);
2526 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2532 NFSBCOPY("nobody@", cp, 7);
2534 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2539 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2540 if (usrp->lug_uid == uid) {
2541 if (usrp->lug_expiry < NFSD_MONOSEC)
2544 * If the name doesn't already have an '@'
2545 * in it, append @domainname to it.
2547 for (i = 0; i < usrp->lug_namelen; i++) {
2548 if (usrp->lug_name[i] == '@') {
2554 i = usrp->lug_namelen;
2556 i = usrp->lug_namelen +
2557 nfsrv_dnsnamelen + 1;
2560 if (len > NFSV4_SMALLSTR)
2561 free(cp, M_NFSSTRING);
2562 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2568 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2569 if (!hasampersand) {
2570 cp += usrp->lug_namelen;
2572 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2574 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2575 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2582 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2584 if (ret == 0 && cnt < 2)
2591 * No match, just return a string of digits.
2595 while (tmp || i == 0) {
2599 len = (i > len) ? len : i;
2603 for (i = 0; i < len; i++) {
2604 *cp-- = '0' + (tmp % 10);
2611 * Convert a string to a uid.
2612 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2614 * If this is called from a client side mount using AUTH_SYS and the
2615 * string is made up entirely of digits, just convert the string to
2619 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2623 char *cp, *endstr, *str0;
2624 struct nfsusrgrp *usrp;
2630 error = NFSERR_BADOWNER;
2633 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2635 tuid = (uid_t)strtoul(str0, &endstr, 10);
2636 if ((endstr - str0) == len &&
2637 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2644 cp = strchr(str0, '@');
2646 i = (int)(cp++ - str0);
2654 * If an '@' is found and the domain name matches, search for the name
2655 * with dns stripped off.
2656 * Mixed case alpahbetics will match for the domain name, but all
2657 * upper case will not.
2659 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2660 (len - 1 - i) == nfsrv_dnsnamelen &&
2661 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2662 len -= (nfsrv_dnsnamelen + 1);
2667 * Check for the special case of "nobody".
2669 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2670 *uidp = nfsrv_defaultuid;
2676 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2677 if (usrp->lug_namelen == len &&
2678 !NFSBCMP(usrp->lug_name, str, len)) {
2679 if (usrp->lug_expiry < NFSD_MONOSEC)
2681 *uidp = usrp->lug_uid;
2682 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2683 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2691 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2693 if (ret == 0 && cnt < 2)
2695 error = NFSERR_BADOWNER;
2703 * Convert a gid to a string.
2704 * gid - the group id
2705 * cpp - points to a buffer of size NFSV4_SMALLSTR
2706 * (malloc a larger one, as required)
2707 * retlenp - pointer to length to be returned
2710 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2713 struct nfsusrgrp *usrp;
2716 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2721 if (nfsrv_dnsname) {
2723 * Always map nfsrv_defaultgid to "nogroup".
2725 if (gid == nfsrv_defaultgid) {
2726 i = nfsrv_dnsnamelen + 8;
2729 if (len > NFSV4_SMALLSTR)
2730 free(cp, M_NFSSTRING);
2731 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2737 NFSBCOPY("nogroup@", cp, 8);
2739 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2744 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2745 if (usrp->lug_gid == gid) {
2746 if (usrp->lug_expiry < NFSD_MONOSEC)
2749 * If the name doesn't already have an '@'
2750 * in it, append @domainname to it.
2752 for (i = 0; i < usrp->lug_namelen; i++) {
2753 if (usrp->lug_name[i] == '@') {
2759 i = usrp->lug_namelen;
2761 i = usrp->lug_namelen +
2762 nfsrv_dnsnamelen + 1;
2765 if (len > NFSV4_SMALLSTR)
2766 free(cp, M_NFSSTRING);
2767 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2773 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2774 if (!hasampersand) {
2775 cp += usrp->lug_namelen;
2777 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2779 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2780 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2787 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2789 if (ret == 0 && cnt < 2)
2796 * No match, just return a string of digits.
2800 while (tmp || i == 0) {
2804 len = (i > len) ? len : i;
2808 for (i = 0; i < len; i++) {
2809 *cp-- = '0' + (tmp % 10);
2816 * Convert a string to a gid.
2817 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2819 * If this is called from a client side mount using AUTH_SYS and the
2820 * string is made up entirely of digits, just convert the string to
2824 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2828 char *cp, *endstr, *str0;
2829 struct nfsusrgrp *usrp;
2835 error = NFSERR_BADOWNER;
2838 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2840 tgid = (gid_t)strtoul(str0, &endstr, 10);
2841 if ((endstr - str0) == len &&
2842 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2849 cp = strchr(str0, '@');
2851 i = (int)(cp++ - str0);
2859 * If an '@' is found and the dns name matches, search for the name
2860 * with the dns stripped off.
2862 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2863 (len - 1 - i) == nfsrv_dnsnamelen &&
2864 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2865 len -= (nfsrv_dnsnamelen + 1);
2870 * Check for the special case of "nogroup".
2872 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2873 *gidp = nfsrv_defaultgid;
2879 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2880 if (usrp->lug_namelen == len &&
2881 !NFSBCMP(usrp->lug_name, str, len)) {
2882 if (usrp->lug_expiry < NFSD_MONOSEC)
2884 *gidp = usrp->lug_gid;
2885 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2886 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2894 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2896 if (ret == 0 && cnt < 2)
2898 error = NFSERR_BADOWNER;
2906 * Cmp len chars, allowing mixed case in the first argument to match lower
2907 * case in the second, but not if the first argument is all upper case.
2908 * Return 0 for a match, 1 otherwise.
2911 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2917 for (i = 0; i < len; i++) {
2918 if (*cp >= 'A' && *cp <= 'Z') {
2919 tmp = *cp++ + ('a' - 'A');
2922 if (tmp >= 'a' && tmp <= 'z')
2935 * Set the port for the nfsuserd.
2938 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2940 struct nfssockreq *rp;
2941 struct sockaddr_in *ad;
2945 if (nfsrv_nfsuserd) {
2953 * Set up the socket record and connect.
2955 rp = &nfsrv_nfsuserdsock;
2956 rp->nr_client = NULL;
2957 rp->nr_sotype = SOCK_DGRAM;
2958 rp->nr_soproto = IPPROTO_UDP;
2959 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2961 NFSSOCKADDRALLOC(rp->nr_nam);
2962 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2963 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2964 ad->sin_family = AF_INET;
2965 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2966 ad->sin_port = port;
2967 rp->nr_prog = RPCPROG_NFSUSERD;
2968 rp->nr_vers = RPCNFSUSERD_VERS;
2969 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2971 NFSSOCKADDRFREE(rp->nr_nam);
2980 * Delete the nfsuserd port.
2983 nfsrv_nfsuserddelport(void)
2987 if (nfsrv_nfsuserd == 0) {
2993 newnfs_disconnect(&nfsrv_nfsuserdsock);
2994 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2998 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3000 * Returns 0 upon success, non-zero otherwise.
3003 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3006 struct nfsrv_descript *nd;
3008 struct nfsrv_descript nfsd;
3013 if (nfsrv_nfsuserd == 0) {
3020 cred = newnfs_getcred();
3021 nd->nd_flag = ND_GSSINITREPLY;
3024 nd->nd_procnum = procnum;
3025 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3026 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3027 if (procnum == RPCNFSUSERD_GETUID)
3028 *tl = txdr_unsigned(uid);
3030 *tl = txdr_unsigned(gid);
3033 (void) nfsm_strtom(nd, name, len);
3035 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3036 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3039 mbuf_freem(nd->nd_mrep);
3040 error = nd->nd_repstat;
3048 * This function is called from the nfssvc(2) system call, to update the
3049 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3052 nfssvc_idname(struct nfsd_idargs *nidp)
3054 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3055 struct nfsuserhashhead *hp;
3060 if (nidp->nid_flag & NFSID_INITIALIZE) {
3061 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3062 M_NFSSTRING, M_WAITOK);
3063 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3066 if (nfsrv_dnsname) {
3068 * Free up all the old stuff and reinitialize hash lists.
3070 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3071 nfsrv_removeuser(usrp);
3073 free(nfsrv_dnsname, M_NFSSTRING);
3074 nfsrv_dnsname = NULL;
3076 TAILQ_INIT(&nfsuserlruhead);
3077 for (i = 0; i < NFSUSERHASHSIZE; i++)
3078 LIST_INIT(&nfsuserhash[i]);
3079 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3080 LIST_INIT(&nfsgrouphash[i]);
3081 for (i = 0; i < NFSUSERHASHSIZE; i++)
3082 LIST_INIT(&nfsusernamehash[i]);
3083 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3084 LIST_INIT(&nfsgroupnamehash[i]);
3087 * Put name in "DNS" string.
3091 nfsrv_dnsnamelen = nidp->nid_namelen;
3092 nfsrv_defaultuid = nidp->nid_uid;
3093 nfsrv_defaultgid = nidp->nid_gid;
3095 nfsrv_usermax = nidp->nid_usermax;
3099 free(cp, M_NFSSTRING);
3104 * malloc the new one now, so any potential sleep occurs before
3105 * manipulation of the lists.
3107 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3108 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3109 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3112 free((caddr_t)newusrp, M_NFSUSERGROUP);
3115 newusrp->lug_namelen = nidp->nid_namelen;
3119 * Delete old entries, as required.
3121 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3122 hp = NFSUSERHASH(nidp->nid_uid);
3123 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3124 if (usrp->lug_uid == nidp->nid_uid)
3125 nfsrv_removeuser(usrp);
3128 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3129 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3130 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3131 if (usrp->lug_namelen == newusrp->lug_namelen &&
3132 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3134 nfsrv_removeuser(usrp);
3137 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3138 hp = NFSGROUPHASH(nidp->nid_gid);
3139 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3140 if (usrp->lug_gid == nidp->nid_gid)
3141 nfsrv_removeuser(usrp);
3144 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3145 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3146 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3147 if (usrp->lug_namelen == newusrp->lug_namelen &&
3148 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3150 nfsrv_removeuser(usrp);
3153 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3154 if (usrp->lug_expiry < NFSD_MONOSEC)
3155 nfsrv_removeuser(usrp);
3157 while (nfsrv_usercnt >= nfsrv_usermax) {
3158 usrp = TAILQ_FIRST(&nfsuserlruhead);
3159 nfsrv_removeuser(usrp);
3163 * Now, we can add the new one.
3165 if (nidp->nid_usertimeout)
3166 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3168 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3169 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3170 newusrp->lug_uid = nidp->nid_uid;
3171 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3173 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3174 newusrp->lug_namelen), newusrp, lug_namehash);
3175 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3177 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3178 newusrp->lug_gid = nidp->nid_gid;
3179 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3181 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3182 newusrp->lug_namelen), newusrp, lug_namehash);
3183 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3186 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3194 * Remove a user/group name element.
3197 nfsrv_removeuser(struct nfsusrgrp *usrp)
3200 NFSNAMEIDREQUIRED();
3201 LIST_REMOVE(usrp, lug_numhash);
3202 LIST_REMOVE(usrp, lug_namehash);
3203 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3205 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3209 * This function scans a byte string and checks for UTF-8 compliance.
3210 * It returns 0 if it conforms and NFSERR_INVAL if not.
3213 nfsrv_checkutf8(u_int8_t *cp, int len)
3215 u_int32_t val = 0x0;
3216 int cnt = 0, gotd = 0, shift = 0;
3218 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3222 * Here are what the variables are used for:
3223 * val - the calculated value of a multibyte char, used to check
3224 * that it was coded with the correct range
3225 * cnt - the number of 10xxxxxx bytes to follow
3226 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3227 * shift - lower order bits of range (ie. "val >> shift" should
3228 * not be 0, in other words, dividing by the lower bound
3229 * of the range should get a non-zero value)
3230 * byte - used to calculate cnt
3234 /* This handles the 10xxxxxx bytes */
3235 if ((*cp & 0xc0) != 0x80 ||
3236 (gotd && (*cp & 0x20))) {
3237 error = NFSERR_INVAL;
3242 val |= (*cp & 0x3f);
3244 if (cnt == 0 && (val >> shift) == 0x0) {
3245 error = NFSERR_INVAL;
3248 } else if (*cp & 0x80) {
3249 /* first byte of multi byte char */
3251 while ((byte & 0x40) && cnt < 6) {
3255 if (cnt == 0 || cnt == 6) {
3256 error = NFSERR_INVAL;
3259 val = (*cp & (0x3f >> cnt));
3260 shift = utf8_shift[cnt - 1];
3261 if (cnt == 2 && val == 0xd)
3262 /* Check for the 0xd800-0xdfff case */
3269 error = NFSERR_INVAL;
3277 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3278 * strings, one with the root path in it and the other with the list of
3279 * locations. The list is in the same format as is found in nfr_refs.
3280 * It is a "," separated list of entries, where each of them is of the
3281 * form <server>:<rootpath>. For example
3282 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3283 * The nilp argument is set to 1 for the special case of a null fs_root
3284 * and an empty server list.
3285 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3286 * number of xdr bytes parsed in sump.
3289 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3290 int *sump, int *nilp)
3293 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3294 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3296 SLIST_ENTRY(list) next;
3300 SLIST_HEAD(, list) head;
3307 * Get the fs_root path and check for the special case of null path
3308 * and 0 length server list.
3310 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3311 len = fxdr_unsigned(int, *tl);
3312 if (len < 0 || len > 10240) {
3313 error = NFSERR_BADXDR;
3317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3319 error = NFSERR_BADXDR;
3323 *sump = 2 * NFSX_UNSIGNED;
3327 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3328 error = nfsrv_mtostr(nd, cp, len);
3330 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3331 cnt = fxdr_unsigned(int, *tl);
3333 error = NFSERR_BADXDR;
3339 * Now, loop through the location list and make up the srvlist.
3341 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3342 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3345 for (i = 0; i < cnt; i++) {
3347 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3348 nsrv = fxdr_unsigned(int, *tl);
3350 error = NFSERR_BADXDR;
3355 * Handle the first server by putting it in the srvstr.
3357 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3358 len = fxdr_unsigned(int, *tl);
3359 if (len <= 0 || len > 1024) {
3360 error = NFSERR_BADXDR;
3363 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3368 error = nfsrv_mtostr(nd, cp3, len);
3374 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3375 for (j = 1; j < nsrv; j++) {
3377 * Yuck, put them in an slist and process them later.
3379 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3380 len = fxdr_unsigned(int, *tl);
3381 if (len <= 0 || len > 1024) {
3382 error = NFSERR_BADXDR;
3385 lsp = (struct list *)malloc(sizeof (struct list)
3386 + len, M_TEMP, M_WAITOK);
3387 error = nfsrv_mtostr(nd, lsp->host, len);
3390 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3392 SLIST_INSERT_HEAD(&head, lsp, next);
3396 * Finally, we can get the path.
3398 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3399 len = fxdr_unsigned(int, *tl);
3400 if (len <= 0 || len > 1024) {
3401 error = NFSERR_BADXDR;
3404 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3405 error = nfsrv_mtostr(nd, cp3, len);
3408 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3413 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3414 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3417 NFSBCOPY(lsp->host, cp3, lsp->len);
3420 NFSBCOPY(str, cp3, stringlen);
3423 siz += (lsp->len + stringlen + 2);
3424 free((caddr_t)lsp, M_TEMP);
3430 NFSEXITCODE2(0, nd);
3434 free(cp, M_NFSSTRING);
3436 free(cp2, M_NFSSTRING);
3437 NFSEXITCODE2(error, nd);
3442 * Make the malloc'd space large enough. This is a pain, but the xdr
3443 * doesn't set an upper bound on the side, so...
3446 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3453 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3454 NFSBCOPY(*cpp, cp, *slenp);
3455 free(*cpp, M_NFSSTRING);
3459 *slenp = siz + 1024;
3463 * Initialize the reply header data structures.
3466 nfsrvd_rephead(struct nfsrv_descript *nd)
3471 * If this is a big reply, use a cluster.
3473 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3474 nfs_bigreply[nd->nd_procnum]) {
3475 NFSMCLGET(mreq, M_WAITOK);
3483 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3484 mbuf_setlen(mreq, 0);
3486 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3487 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3491 * Lock a socket against others.
3492 * Currently used to serialize connect/disconnect attempts.
3495 newnfs_sndlock(int *flagp)
3500 while (*flagp & NFSR_SNDLOCK) {
3501 *flagp |= NFSR_WANTSND;
3504 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3505 PZERO - 1, "nfsndlck", &ts);
3507 *flagp |= NFSR_SNDLOCK;
3513 * Unlock the stream socket for others.
3516 newnfs_sndunlock(int *flagp)
3520 if ((*flagp & NFSR_SNDLOCK) == 0)
3521 panic("nfs sndunlock");
3522 *flagp &= ~NFSR_SNDLOCK;
3523 if (*flagp & NFSR_WANTSND) {
3524 *flagp &= ~NFSR_WANTSND;
3525 wakeup((caddr_t)flagp);
3531 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3534 struct sockaddr_in *sad;
3535 struct sockaddr_in6 *sad6;
3536 struct in_addr saddr;
3537 uint32_t portnum, *tl;
3538 int af = 0, i, j, k;
3539 char addr[64], protocol[5], *cp;
3540 int cantparse = 0, error = 0;
3543 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3544 i = fxdr_unsigned(int, *tl);
3545 if (i >= 3 && i <= 4) {
3546 error = nfsrv_mtostr(nd, protocol, i);
3549 if (strcmp(protocol, "tcp") == 0) {
3552 } else if (strcmp(protocol, "udp") == 0) {
3555 } else if (strcmp(protocol, "tcp6") == 0) {
3558 } else if (strcmp(protocol, "udp6") == 0) {
3566 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3571 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3572 i = fxdr_unsigned(int, *tl);
3574 error = NFSERR_BADXDR;
3576 } else if (cantparse == 0 && i >= 11 && i < 64) {
3578 * The shortest address is 11chars and the longest is < 64.
3580 error = nfsrv_mtostr(nd, addr, i);
3584 /* Find the port# at the end and extract that. */
3588 /* Count back two '.'s from end to get port# field. */
3589 for (j = 0; j < i; j++) {
3599 * The NFSv4 port# is appended as .N.N, where N is
3600 * a decimal # in the range 0-255, just like an inet4
3601 * address. Cheat and use inet_aton(), which will
3602 * return a Class A address and then shift the high
3603 * order 8bits over to convert it to the port#.
3606 if (inet_aton(cp, &saddr) == 1) {
3607 portnum = ntohl(saddr.s_addr);
3608 portv = (uint16_t)((portnum >> 16) |
3614 if (cantparse == 0) {
3615 if (af == AF_INET) {
3616 sad = (struct sockaddr_in *)sa;
3617 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
3618 sad->sin_len = sizeof(*sad);
3619 sad->sin_family = AF_INET;
3620 sad->sin_port = htons(portv);
3624 sad6 = (struct sockaddr_in6 *)sa;
3625 if (inet_pton(af, addr, &sad6->sin6_addr)
3627 sad6->sin6_len = sizeof(*sad6);
3628 sad6->sin6_family = AF_INET6;
3629 sad6->sin6_port = htons(portv);
3636 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3647 * Handle an NFSv4.1 Sequence request for the session.
3650 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
3651 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
3657 if (slotid > maxslot)
3658 return (NFSERR_BADSLOT);
3659 if (seqid == slots[slotid].nfssl_seq) {
3661 if (slots[slotid].nfssl_inprog != 0)
3662 error = NFSERR_DELAY;
3663 else if (slots[slotid].nfssl_reply != NULL) {
3664 *reply = slots[slotid].nfssl_reply;
3665 slots[slotid].nfssl_reply = NULL;
3666 slots[slotid].nfssl_inprog = 1;
3668 error = NFSERR_SEQMISORDERED;
3669 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
3670 m_freem(slots[slotid].nfssl_reply);
3671 slots[slotid].nfssl_reply = NULL;
3672 slots[slotid].nfssl_inprog = 1;
3673 slots[slotid].nfssl_seq++;
3675 error = NFSERR_SEQMISORDERED;
3680 * Cache this reply for the slot.
3683 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep)
3686 slots[slotid].nfssl_reply = rep;
3687 slots[slotid].nfssl_inprog = 0;
3691 * Generate the xdr for an NFSv4.1 Sequence Operation.
3694 nfsv4_setsequence(struct nfsrv_descript *nd, struct nfsclsession *sep,
3695 int dont_replycache)
3697 uint32_t *tl, slotseq = 0;
3698 int i, maxslot, slotpos;
3700 uint8_t sessionid[NFSX_V4SESSIONID];
3702 /* Find an unused slot. */
3705 mtx_lock(&sep->nfsess_mtx);
3708 for (i = 0; i < sep->nfsess_foreslots; i++) {
3709 if ((bitval & sep->nfsess_slots) == 0) {
3711 sep->nfsess_slots |= bitval;
3712 sep->nfsess_slotseq[i]++;
3713 slotseq = sep->nfsess_slotseq[i];
3719 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
3720 PZERO, "nfsclseq", 0);
3721 } while (slotpos == -1);
3722 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
3724 for (i = 0; i < 64; i++) {
3725 if ((bitval & sep->nfsess_slots) != 0)
3729 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
3730 mtx_unlock(&sep->nfsess_mtx);
3731 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
3733 /* Build the Sequence arguments. */
3734 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
3735 bcopy(sessionid, tl, NFSX_V4SESSIONID);
3736 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
3737 nd->nd_slotseq = tl;
3738 *tl++ = txdr_unsigned(slotseq);
3739 *tl++ = txdr_unsigned(slotpos);
3740 *tl++ = txdr_unsigned(maxslot);
3741 if (dont_replycache == 0)
3745 nd->nd_flag |= ND_HASSEQUENCE;
3749 * Free a session slot.
3752 nfsv4_freeslot(struct nfsclsession *sep, int slot)
3759 mtx_lock(&sep->nfsess_mtx);
3760 if ((bitval & sep->nfsess_slots) == 0)
3761 printf("freeing free slot!!\n");
3762 sep->nfsess_slots &= ~bitval;
3763 wakeup(&sep->nfsess_slots);
3764 mtx_unlock(&sep->nfsess_mtx);