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, int how)
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");
299 MGET(mp2, MT_DATA, how);
302 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
303 mbuf_setnext(nd->nd_md, mp2);
304 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
306 retp = p = NFSMTOD(mp2, caddr_t);
307 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
310 mp2 = mbuf_next(mp2);
311 /* Loop around copying up the siz2 bytes */
315 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
317 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
318 NFSM_DATAP(mp2, xfer);
319 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
324 mp2 = mbuf_next(mp2);
326 mbuf_setlen(nd->nd_md, siz);
328 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
334 * Advance the position in the mbuf chain.
335 * If offs == 0, this is a no-op, but it is simpler to just return from
336 * here than check for offs > 0 for all calls to nfsm_advance.
337 * If left == -1, it should be calculated here.
340 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
347 * A negative offs should be considered a serious problem.
350 panic("nfsrv_advance");
353 * If left == -1, calculate it here.
356 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
360 * Loop around, advancing over the mbuf data.
362 while (offs > left) {
364 nd->nd_md = mbuf_next(nd->nd_md);
365 if (nd->nd_md == NULL) {
369 left = mbuf_len(nd->nd_md);
370 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
380 * Copy a string into mbuf(s).
381 * Return the number of bytes output, including XDR overheads.
384 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
393 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
394 *tl = txdr_unsigned(siz);
395 rem = NFSM_RNDUP(siz) - siz;
396 bytesize = NFSX_UNSIGNED + siz + rem;
399 left = M_TRAILINGSPACE(m2);
402 * Loop around copying the string to mbuf(s).
406 if (siz > ncl_mbuf_mlen)
407 NFSMCLGET(m1, M_WAITOK);
411 mbuf_setnext(m2, m1);
413 cp2 = NFSMTOD(m2, caddr_t);
414 left = M_TRAILINGSPACE(m2);
420 NFSBCOPY(cp, cp2, xfer);
422 mbuf_setlen(m2, mbuf_len(m2) + xfer);
425 if (siz == 0 && rem) {
427 panic("nfsm_strtom");
428 NFSBZERO(cp2 + xfer, rem);
429 mbuf_setlen(m2, mbuf_len(m2) + rem);
433 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
438 * Called once to initialize data structures...
443 static int nfs_inited = 0;
449 newnfs_true = txdr_unsigned(TRUE);
450 newnfs_false = txdr_unsigned(FALSE);
451 newnfs_xdrneg1 = txdr_unsigned(-1);
452 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
455 NFSSETBOOTTIME(nfsboottime);
458 * Initialize reply list and start timer
460 TAILQ_INIT(&nfsd_reqq);
465 * Put a file handle in an mbuf list.
466 * If the size argument == 0, just use the default size.
467 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
468 * Return the number of bytes output, including XDR overhead.
471 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
475 int fullsiz, rem, bytesize = 0;
479 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
481 if (size > NFSX_V2FH)
482 panic("fh size > NFSX_V2FH for NFSv2");
483 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
484 NFSBCOPY(fhp, cp, size);
485 if (size < NFSX_V2FH)
486 NFSBZERO(cp + size, NFSX_V2FH - size);
487 bytesize = NFSX_V2FH;
491 fullsiz = NFSM_RNDUP(size);
492 rem = fullsiz - size;
494 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
495 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
498 bytesize = NFSX_UNSIGNED + fullsiz;
500 (void) nfsm_strtom(nd, fhp, size);
507 * This function compares two net addresses by family and returns TRUE
508 * if they are the same host.
509 * If there is any doubt, return FALSE.
510 * The AF_INET family is handled as a special case so that address mbufs
511 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
514 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
516 struct sockaddr_in *inetaddr;
520 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
521 if (inetaddr->sin_family == AF_INET &&
522 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
528 struct sockaddr_in6 *inetaddr6;
530 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
531 /* XXX - should test sin6_scope_id ? */
532 if (inetaddr6->sin6_family == AF_INET6 &&
533 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
544 * Similar to the above, but takes to NFSSOCKADDR_T args.
547 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
549 struct sockaddr_in *addr1, *addr2;
550 struct sockaddr *inaddr;
552 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
553 switch (inaddr->sa_family) {
555 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
556 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
557 if (addr2->sin_family == AF_INET &&
558 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
564 struct sockaddr_in6 *inet6addr1, *inet6addr2;
566 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
567 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
568 /* XXX - should test sin6_scope_id ? */
569 if (inet6addr2->sin6_family == AF_INET6 &&
570 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
571 &inet6addr2->sin6_addr))
582 * Trim the stuff already dissected off the mbuf list.
585 newnfs_trimleading(nd)
586 struct nfsrv_descript *nd;
592 * First, free up leading mbufs.
594 if (nd->nd_mrep != nd->nd_md) {
596 while (mbuf_next(m) != nd->nd_md) {
597 if (mbuf_next(m) == NULL)
598 panic("nfsm trim leading");
601 mbuf_setnext(m, NULL);
602 mbuf_freem(nd->nd_mrep);
607 * Now, adjust this mbuf, based on nd_dpos.
609 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
610 if (offs == mbuf_len(m)) {
614 panic("nfsm trim leading2");
615 mbuf_setnext(n, NULL);
617 } else if (offs > 0) {
618 mbuf_setlen(m, mbuf_len(m) - offs);
621 panic("nfsm trimleading offs");
624 nd->nd_dpos = NFSMTOD(m, caddr_t);
628 * Trim trailing data off the mbuf list being built.
631 newnfs_trimtrailing(nd, mb, bpos)
632 struct nfsrv_descript *nd;
638 mbuf_freem(mbuf_next(mb));
639 mbuf_setnext(mb, NULL);
641 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
647 * Dissect a file handle on the client.
650 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
657 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
658 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
659 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
666 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
668 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
670 FREE((caddr_t)nfhp, M_NFSFH);
676 NFSEXITCODE2(error, nd);
681 * Break down the nfsv4 acl.
682 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
685 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
686 int *aclsizep, __unused NFSPROC_T *p)
690 int acecnt, error = 0, aceerr = 0, acesize;
696 * Parse out the ace entries and expect them to conform to
697 * what can be supported by R/W/X bits.
699 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
700 aclsize = NFSX_UNSIGNED;
701 acecnt = fxdr_unsigned(int, *tl);
702 if (acecnt > ACL_MAX_ENTRIES)
703 aceerr = NFSERR_ATTRNOTSUPP;
704 if (nfsrv_useacl == 0)
705 aceerr = NFSERR_ATTRNOTSUPP;
706 for (i = 0; i < acecnt; i++) {
708 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
709 &aceerr, &acesize, p);
711 error = nfsrv_skipace(nd, &acesize);
717 aclp->acl_cnt = acecnt;
723 NFSEXITCODE2(error, nd);
728 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
731 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
736 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
737 len = fxdr_unsigned(int, *(tl + 3));
738 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
740 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
741 NFSEXITCODE2(error, nd);
746 * Get attribute bits from an mbuf list.
747 * Returns EBADRPC for a parsing error, 0 otherwise.
748 * If the clearinvalid flag is set, clear the bits not supported.
751 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
758 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
759 cnt = fxdr_unsigned(int, *tl);
761 error = NFSERR_BADXDR;
764 if (cnt > NFSATTRBIT_MAXWORDS)
765 outcnt = NFSATTRBIT_MAXWORDS;
768 NFSZERO_ATTRBIT(attrbitp);
770 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
771 for (i = 0; i < outcnt; i++)
772 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
774 for (i = 0; i < (cnt - outcnt); i++) {
775 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
776 if (retnotsupp != NULL && *tl != 0)
777 *retnotsupp = NFSERR_ATTRNOTSUPP;
780 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
782 NFSEXITCODE2(error, nd);
787 * Get the attributes for V4.
788 * If the compare flag is true, test for any attribute changes,
789 * otherwise return the attribute values.
790 * These attributes cover fields in "struct vattr", "struct statfs",
791 * "struct nfsfsinfo", the file handle and the lease duration.
792 * The value of retcmpp is set to 1 if all attributes are the same,
794 * Returns EBADRPC if it can't be parsed, 0 otherwise.
797 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
798 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
799 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
800 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
801 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
804 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
805 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
806 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
807 nfsattrbit_t attrbits, retattrbits, checkattrbits;
809 struct nfsreferral *refp;
812 struct timespec temptime;
816 u_int32_t freenum = 0, tuint;
817 u_int64_t uquad = 0, thyp, thyp2;
825 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
827 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
833 *retcmpp = retnotsup;
836 * Just set default values to some of the important ones.
841 nap->na_rdev = (NFSDEV_T)0;
842 nap->na_mtime.tv_sec = 0;
843 nap->na_mtime.tv_nsec = 0;
846 nap->na_blocksize = NFS_FABLKSIZE;
849 sbp->f_bsize = NFS_FABLKSIZE;
857 fsp->fs_rtmax = 8192;
858 fsp->fs_rtpref = 8192;
859 fsp->fs_maxname = NFS_MAXNAMLEN;
860 fsp->fs_wtmax = 8192;
861 fsp->fs_wtpref = 8192;
862 fsp->fs_wtmult = NFS_FABLKSIZE;
863 fsp->fs_dtpref = 8192;
864 fsp->fs_maxfilesize = 0xffffffffffffffffull;
865 fsp->fs_timedelta.tv_sec = 0;
866 fsp->fs_timedelta.tv_nsec = 1;
867 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
868 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
871 pc->pc_linkmax = LINK_MAX;
872 pc->pc_namemax = NAME_MAX;
874 pc->pc_chownrestricted = 0;
875 pc->pc_caseinsensitive = 0;
876 pc->pc_casepreserving = 1;
881 * Loop around getting the attributes.
883 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
884 attrsize = fxdr_unsigned(int, *tl);
885 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
886 if (attrsum > attrsize) {
887 error = NFSERR_BADXDR;
890 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
892 case NFSATTRBIT_SUPPORTEDATTRS:
894 if (compare || nap == NULL)
895 error = nfsrv_getattrbits(nd, &retattrbits,
898 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
902 if (compare && !(*retcmpp)) {
903 NFSSETSUPP_ATTRBIT(&checkattrbits);
904 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
906 *retcmpp = NFSERR_NOTSAME;
910 case NFSATTRBIT_TYPE:
911 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
914 if (nap->na_type != nfsv34tov_type(*tl))
915 *retcmpp = NFSERR_NOTSAME;
917 } else if (nap != NULL) {
918 nap->na_type = nfsv34tov_type(*tl);
920 attrsum += NFSX_UNSIGNED;
922 case NFSATTRBIT_FHEXPIRETYPE:
923 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
924 if (compare && !(*retcmpp)) {
925 if (fxdr_unsigned(int, *tl) !=
926 NFSV4FHTYPE_PERSISTENT)
927 *retcmpp = NFSERR_NOTSAME;
929 attrsum += NFSX_UNSIGNED;
931 case NFSATTRBIT_CHANGE:
932 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
935 if (nap->na_filerev != fxdr_hyper(tl))
936 *retcmpp = NFSERR_NOTSAME;
938 } else if (nap != NULL) {
939 nap->na_filerev = fxdr_hyper(tl);
941 attrsum += NFSX_HYPER;
943 case NFSATTRBIT_SIZE:
944 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
947 if (nap->na_size != fxdr_hyper(tl))
948 *retcmpp = NFSERR_NOTSAME;
950 } else if (nap != NULL) {
951 nap->na_size = fxdr_hyper(tl);
953 attrsum += NFSX_HYPER;
955 case NFSATTRBIT_LINKSUPPORT:
956 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
959 if (fsp->fs_properties & NFSV3_FSFLINK) {
960 if (*tl == newnfs_false)
961 *retcmpp = NFSERR_NOTSAME;
963 if (*tl == newnfs_true)
964 *retcmpp = NFSERR_NOTSAME;
967 } else if (fsp != NULL) {
968 if (*tl == newnfs_true)
969 fsp->fs_properties |= NFSV3_FSFLINK;
971 fsp->fs_properties &= ~NFSV3_FSFLINK;
973 attrsum += NFSX_UNSIGNED;
975 case NFSATTRBIT_SYMLINKSUPPORT:
976 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
979 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
980 if (*tl == newnfs_false)
981 *retcmpp = NFSERR_NOTSAME;
983 if (*tl == newnfs_true)
984 *retcmpp = NFSERR_NOTSAME;
987 } else if (fsp != NULL) {
988 if (*tl == newnfs_true)
989 fsp->fs_properties |= NFSV3_FSFSYMLINK;
991 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
993 attrsum += NFSX_UNSIGNED;
995 case NFSATTRBIT_NAMEDATTR:
996 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
997 if (compare && !(*retcmpp)) {
998 if (*tl != newnfs_false)
999 *retcmpp = NFSERR_NOTSAME;
1001 attrsum += NFSX_UNSIGNED;
1003 case NFSATTRBIT_FSID:
1004 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1005 thyp = fxdr_hyper(tl);
1007 thyp2 = fxdr_hyper(tl);
1009 if (*retcmpp == 0) {
1010 if (thyp != (u_int64_t)
1011 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1012 thyp2 != (u_int64_t)
1013 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1014 *retcmpp = NFSERR_NOTSAME;
1016 } else if (nap != NULL) {
1017 nap->na_filesid[0] = thyp;
1018 nap->na_filesid[1] = thyp2;
1020 attrsum += (4 * NFSX_UNSIGNED);
1022 case NFSATTRBIT_UNIQUEHANDLES:
1023 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1024 if (compare && !(*retcmpp)) {
1025 if (*tl != newnfs_true)
1026 *retcmpp = NFSERR_NOTSAME;
1028 attrsum += NFSX_UNSIGNED;
1030 case NFSATTRBIT_LEASETIME:
1031 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1033 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1035 *retcmpp = NFSERR_NOTSAME;
1036 } else if (leasep != NULL) {
1037 *leasep = fxdr_unsigned(u_int32_t, *tl);
1039 attrsum += NFSX_UNSIGNED;
1041 case NFSATTRBIT_RDATTRERROR:
1042 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1045 *retcmpp = NFSERR_INVAL;
1046 } else if (rderrp != NULL) {
1047 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1049 attrsum += NFSX_UNSIGNED;
1051 case NFSATTRBIT_ACL:
1057 naclp = acl_alloc(M_WAITOK);
1058 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1064 if (aceerr || aclp == NULL ||
1065 nfsrv_compareacl(aclp, naclp))
1066 *retcmpp = NFSERR_NOTSAME;
1069 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1071 *retcmpp = NFSERR_ATTRNOTSUPP;
1075 if (vp != NULL && aclp != NULL)
1076 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1079 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1086 case NFSATTRBIT_ACLSUPPORT:
1087 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1088 if (compare && !(*retcmpp)) {
1090 if (fxdr_unsigned(u_int32_t, *tl) !=
1092 *retcmpp = NFSERR_NOTSAME;
1094 *retcmpp = NFSERR_ATTRNOTSUPP;
1097 attrsum += NFSX_UNSIGNED;
1099 case NFSATTRBIT_ARCHIVE:
1100 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1101 if (compare && !(*retcmpp))
1102 *retcmpp = NFSERR_ATTRNOTSUPP;
1103 attrsum += NFSX_UNSIGNED;
1105 case NFSATTRBIT_CANSETTIME:
1106 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1109 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1110 if (*tl == newnfs_false)
1111 *retcmpp = NFSERR_NOTSAME;
1113 if (*tl == newnfs_true)
1114 *retcmpp = NFSERR_NOTSAME;
1117 } else if (fsp != NULL) {
1118 if (*tl == newnfs_true)
1119 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1121 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1123 attrsum += NFSX_UNSIGNED;
1125 case NFSATTRBIT_CASEINSENSITIVE:
1126 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1129 if (*tl != newnfs_false)
1130 *retcmpp = NFSERR_NOTSAME;
1132 } else if (pc != NULL) {
1133 pc->pc_caseinsensitive =
1134 fxdr_unsigned(u_int32_t, *tl);
1136 attrsum += NFSX_UNSIGNED;
1138 case NFSATTRBIT_CASEPRESERVING:
1139 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1142 if (*tl != newnfs_true)
1143 *retcmpp = NFSERR_NOTSAME;
1145 } else if (pc != NULL) {
1146 pc->pc_casepreserving =
1147 fxdr_unsigned(u_int32_t, *tl);
1149 attrsum += NFSX_UNSIGNED;
1151 case NFSATTRBIT_CHOWNRESTRICTED:
1152 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1155 if (*tl != newnfs_true)
1156 *retcmpp = NFSERR_NOTSAME;
1158 } else if (pc != NULL) {
1159 pc->pc_chownrestricted =
1160 fxdr_unsigned(u_int32_t, *tl);
1162 attrsum += NFSX_UNSIGNED;
1164 case NFSATTRBIT_FILEHANDLE:
1165 error = nfsm_getfh(nd, &tnfhp);
1168 tfhsize = tnfhp->nfh_len;
1171 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1173 *retcmpp = NFSERR_NOTSAME;
1174 FREE((caddr_t)tnfhp, M_NFSFH);
1175 } else if (nfhpp != NULL) {
1178 FREE((caddr_t)tnfhp, M_NFSFH);
1180 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1182 case NFSATTRBIT_FILEID:
1183 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1184 thyp = fxdr_hyper(tl);
1187 if ((u_int64_t)nap->na_fileid != thyp)
1188 *retcmpp = NFSERR_NOTSAME;
1190 } else if (nap != NULL) {
1192 printf("NFSv4 fileid > 32bits\n");
1193 nap->na_fileid = thyp;
1195 attrsum += NFSX_HYPER;
1197 case NFSATTRBIT_FILESAVAIL:
1198 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1201 sfp->sf_afiles != fxdr_hyper(tl))
1202 *retcmpp = NFSERR_NOTSAME;
1203 } else if (sfp != NULL) {
1204 sfp->sf_afiles = fxdr_hyper(tl);
1206 attrsum += NFSX_HYPER;
1208 case NFSATTRBIT_FILESFREE:
1209 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1212 sfp->sf_ffiles != fxdr_hyper(tl))
1213 *retcmpp = NFSERR_NOTSAME;
1214 } else if (sfp != NULL) {
1215 sfp->sf_ffiles = fxdr_hyper(tl);
1217 attrsum += NFSX_HYPER;
1219 case NFSATTRBIT_FILESTOTAL:
1220 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1223 sfp->sf_tfiles != fxdr_hyper(tl))
1224 *retcmpp = NFSERR_NOTSAME;
1225 } else if (sfp != NULL) {
1226 sfp->sf_tfiles = fxdr_hyper(tl);
1228 attrsum += NFSX_HYPER;
1230 case NFSATTRBIT_FSLOCATIONS:
1231 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1235 if (compare && !(*retcmpp)) {
1236 refp = nfsv4root_getreferral(vp, NULL, 0);
1238 if (cp == NULL || cp2 == NULL ||
1240 strcmp(cp2, refp->nfr_srvlist))
1241 *retcmpp = NFSERR_NOTSAME;
1242 } else if (m == 0) {
1243 *retcmpp = NFSERR_NOTSAME;
1247 free(cp, M_NFSSTRING);
1249 free(cp2, M_NFSSTRING);
1251 case NFSATTRBIT_HIDDEN:
1252 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1253 if (compare && !(*retcmpp))
1254 *retcmpp = NFSERR_ATTRNOTSUPP;
1255 attrsum += NFSX_UNSIGNED;
1257 case NFSATTRBIT_HOMOGENEOUS:
1258 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1261 if (fsp->fs_properties &
1262 NFSV3_FSFHOMOGENEOUS) {
1263 if (*tl == newnfs_false)
1264 *retcmpp = NFSERR_NOTSAME;
1266 if (*tl == newnfs_true)
1267 *retcmpp = NFSERR_NOTSAME;
1270 } else if (fsp != NULL) {
1271 if (*tl == newnfs_true)
1272 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1274 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1276 attrsum += NFSX_UNSIGNED;
1278 case NFSATTRBIT_MAXFILESIZE:
1279 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1280 tnfsquad.qval = fxdr_hyper(tl);
1283 tquad = NFSRV_MAXFILESIZE;
1284 if (tquad != tnfsquad.qval)
1285 *retcmpp = NFSERR_NOTSAME;
1287 } else if (fsp != NULL) {
1288 fsp->fs_maxfilesize = tnfsquad.qval;
1290 attrsum += NFSX_HYPER;
1292 case NFSATTRBIT_MAXLINK:
1293 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1296 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1297 *retcmpp = NFSERR_NOTSAME;
1299 } else if (pc != NULL) {
1300 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1302 attrsum += NFSX_UNSIGNED;
1304 case NFSATTRBIT_MAXNAME:
1305 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1308 if (fsp->fs_maxname !=
1309 fxdr_unsigned(u_int32_t, *tl))
1310 *retcmpp = NFSERR_NOTSAME;
1313 tuint = fxdr_unsigned(u_int32_t, *tl);
1315 * Some Linux NFSv4 servers report this
1316 * as 0 or 4billion, so I'll set it to
1317 * NFS_MAXNAMLEN. If a server actually creates
1318 * a name longer than NFS_MAXNAMLEN, it will
1319 * get an error back.
1321 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1322 tuint = NFS_MAXNAMLEN;
1324 fsp->fs_maxname = tuint;
1326 pc->pc_namemax = tuint;
1328 attrsum += NFSX_UNSIGNED;
1330 case NFSATTRBIT_MAXREAD:
1331 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1334 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1335 *(tl + 1)) || *tl != 0)
1336 *retcmpp = NFSERR_NOTSAME;
1338 } else if (fsp != NULL) {
1339 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1340 fsp->fs_rtpref = fsp->fs_rtmax;
1341 fsp->fs_dtpref = fsp->fs_rtpref;
1343 attrsum += NFSX_HYPER;
1345 case NFSATTRBIT_MAXWRITE:
1346 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1349 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1350 *(tl + 1)) || *tl != 0)
1351 *retcmpp = NFSERR_NOTSAME;
1353 } else if (fsp != NULL) {
1354 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1355 fsp->fs_wtpref = fsp->fs_wtmax;
1357 attrsum += NFSX_HYPER;
1359 case NFSATTRBIT_MIMETYPE:
1360 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1361 i = fxdr_unsigned(int, *tl);
1362 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1363 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1366 if (compare && !(*retcmpp))
1367 *retcmpp = NFSERR_ATTRNOTSUPP;
1369 case NFSATTRBIT_MODE:
1370 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1373 if (nap->na_mode != nfstov_mode(*tl))
1374 *retcmpp = NFSERR_NOTSAME;
1376 } else if (nap != NULL) {
1377 nap->na_mode = nfstov_mode(*tl);
1379 attrsum += NFSX_UNSIGNED;
1381 case NFSATTRBIT_NOTRUNC:
1382 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1385 if (*tl != newnfs_true)
1386 *retcmpp = NFSERR_NOTSAME;
1388 } else if (pc != NULL) {
1389 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1391 attrsum += NFSX_UNSIGNED;
1393 case NFSATTRBIT_NUMLINKS:
1394 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1395 tuint = fxdr_unsigned(u_int32_t, *tl);
1398 if ((u_int32_t)nap->na_nlink != tuint)
1399 *retcmpp = NFSERR_NOTSAME;
1401 } else if (nap != NULL) {
1402 nap->na_nlink = tuint;
1404 attrsum += NFSX_UNSIGNED;
1406 case NFSATTRBIT_OWNER:
1407 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1408 j = fxdr_unsigned(int, *tl);
1410 error = NFSERR_BADXDR;
1413 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1414 if (j > NFSV4_SMALLSTR)
1415 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1418 error = nfsrv_mtostr(nd, cp, j);
1420 if (j > NFSV4_SMALLSTR)
1421 free(cp, M_NFSSTRING);
1426 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1428 *retcmpp = NFSERR_NOTSAME;
1430 } else if (nap != NULL) {
1431 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1432 nap->na_uid = nfsrv_defaultuid;
1436 if (j > NFSV4_SMALLSTR)
1437 free(cp, M_NFSSTRING);
1439 case NFSATTRBIT_OWNERGROUP:
1440 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1441 j = fxdr_unsigned(int, *tl);
1443 error = NFSERR_BADXDR;
1446 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1447 if (j > NFSV4_SMALLSTR)
1448 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1451 error = nfsrv_mtostr(nd, cp, j);
1453 if (j > NFSV4_SMALLSTR)
1454 free(cp, M_NFSSTRING);
1459 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1461 *retcmpp = NFSERR_NOTSAME;
1463 } else if (nap != NULL) {
1464 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1465 nap->na_gid = nfsrv_defaultgid;
1469 if (j > NFSV4_SMALLSTR)
1470 free(cp, M_NFSSTRING);
1472 case NFSATTRBIT_QUOTAHARD:
1473 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1475 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1476 freenum = sbp->f_bfree;
1478 freenum = sbp->f_bavail;
1481 * ufs_quotactl() insists that the uid argument
1482 * equal p_ruid for non-root quota access, so
1483 * we'll just make sure that's the case.
1485 savuid = p->p_cred->p_ruid;
1486 p->p_cred->p_ruid = cred->cr_uid;
1487 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1488 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1489 freenum = min(dqb.dqb_bhardlimit, freenum);
1490 p->p_cred->p_ruid = savuid;
1492 uquad = (u_int64_t)freenum;
1493 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1495 if (compare && !(*retcmpp)) {
1496 if (uquad != fxdr_hyper(tl))
1497 *retcmpp = NFSERR_NOTSAME;
1499 attrsum += NFSX_HYPER;
1501 case NFSATTRBIT_QUOTASOFT:
1502 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1504 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1505 freenum = sbp->f_bfree;
1507 freenum = sbp->f_bavail;
1510 * ufs_quotactl() insists that the uid argument
1511 * equal p_ruid for non-root quota access, so
1512 * we'll just make sure that's the case.
1514 savuid = p->p_cred->p_ruid;
1515 p->p_cred->p_ruid = cred->cr_uid;
1516 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1517 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1518 freenum = min(dqb.dqb_bsoftlimit, freenum);
1519 p->p_cred->p_ruid = savuid;
1521 uquad = (u_int64_t)freenum;
1522 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1524 if (compare && !(*retcmpp)) {
1525 if (uquad != fxdr_hyper(tl))
1526 *retcmpp = NFSERR_NOTSAME;
1528 attrsum += NFSX_HYPER;
1530 case NFSATTRBIT_QUOTAUSED:
1531 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1536 * ufs_quotactl() insists that the uid argument
1537 * equal p_ruid for non-root quota access, so
1538 * we'll just make sure that's the case.
1540 savuid = p->p_cred->p_ruid;
1541 p->p_cred->p_ruid = cred->cr_uid;
1542 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1543 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1544 freenum = dqb.dqb_curblocks;
1545 p->p_cred->p_ruid = savuid;
1547 uquad = (u_int64_t)freenum;
1548 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1550 if (compare && !(*retcmpp)) {
1551 if (uquad != fxdr_hyper(tl))
1552 *retcmpp = NFSERR_NOTSAME;
1554 attrsum += NFSX_HYPER;
1556 case NFSATTRBIT_RAWDEV:
1557 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1558 j = fxdr_unsigned(int, *tl++);
1559 k = fxdr_unsigned(int, *tl);
1562 if (nap->na_rdev != NFSMAKEDEV(j, k))
1563 *retcmpp = NFSERR_NOTSAME;
1565 } else if (nap != NULL) {
1566 nap->na_rdev = NFSMAKEDEV(j, k);
1568 attrsum += NFSX_V4SPECDATA;
1570 case NFSATTRBIT_SPACEAVAIL:
1571 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1574 sfp->sf_abytes != fxdr_hyper(tl))
1575 *retcmpp = NFSERR_NOTSAME;
1576 } else if (sfp != NULL) {
1577 sfp->sf_abytes = fxdr_hyper(tl);
1579 attrsum += NFSX_HYPER;
1581 case NFSATTRBIT_SPACEFREE:
1582 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1585 sfp->sf_fbytes != fxdr_hyper(tl))
1586 *retcmpp = NFSERR_NOTSAME;
1587 } else if (sfp != NULL) {
1588 sfp->sf_fbytes = fxdr_hyper(tl);
1590 attrsum += NFSX_HYPER;
1592 case NFSATTRBIT_SPACETOTAL:
1593 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1596 sfp->sf_tbytes != fxdr_hyper(tl))
1597 *retcmpp = NFSERR_NOTSAME;
1598 } else if (sfp != NULL) {
1599 sfp->sf_tbytes = fxdr_hyper(tl);
1601 attrsum += NFSX_HYPER;
1603 case NFSATTRBIT_SPACEUSED:
1604 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1605 thyp = fxdr_hyper(tl);
1608 if ((u_int64_t)nap->na_bytes != thyp)
1609 *retcmpp = NFSERR_NOTSAME;
1611 } else if (nap != NULL) {
1612 nap->na_bytes = thyp;
1614 attrsum += NFSX_HYPER;
1616 case NFSATTRBIT_SYSTEM:
1617 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1618 if (compare && !(*retcmpp))
1619 *retcmpp = NFSERR_ATTRNOTSUPP;
1620 attrsum += NFSX_UNSIGNED;
1622 case NFSATTRBIT_TIMEACCESS:
1623 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1624 fxdr_nfsv4time(tl, &temptime);
1627 if (!NFS_CMPTIME(temptime, nap->na_atime))
1628 *retcmpp = NFSERR_NOTSAME;
1630 } else if (nap != NULL) {
1631 nap->na_atime = temptime;
1633 attrsum += NFSX_V4TIME;
1635 case NFSATTRBIT_TIMEACCESSSET:
1636 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1637 attrsum += NFSX_UNSIGNED;
1638 i = fxdr_unsigned(int, *tl);
1639 if (i == NFSV4SATTRTIME_TOCLIENT) {
1640 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1641 attrsum += NFSX_V4TIME;
1643 if (compare && !(*retcmpp))
1644 *retcmpp = NFSERR_INVAL;
1646 case NFSATTRBIT_TIMEBACKUP:
1647 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1648 if (compare && !(*retcmpp))
1649 *retcmpp = NFSERR_ATTRNOTSUPP;
1650 attrsum += NFSX_V4TIME;
1652 case NFSATTRBIT_TIMECREATE:
1653 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1654 if (compare && !(*retcmpp))
1655 *retcmpp = NFSERR_ATTRNOTSUPP;
1656 attrsum += NFSX_V4TIME;
1658 case NFSATTRBIT_TIMEDELTA:
1659 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1663 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1664 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1665 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1666 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1669 *retcmpp = NFSERR_NOTSAME;
1672 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1675 attrsum += NFSX_V4TIME;
1677 case NFSATTRBIT_TIMEMETADATA:
1678 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1679 fxdr_nfsv4time(tl, &temptime);
1682 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1683 *retcmpp = NFSERR_NOTSAME;
1685 } else if (nap != NULL) {
1686 nap->na_ctime = temptime;
1688 attrsum += NFSX_V4TIME;
1690 case NFSATTRBIT_TIMEMODIFY:
1691 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1692 fxdr_nfsv4time(tl, &temptime);
1695 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1696 *retcmpp = NFSERR_NOTSAME;
1698 } else if (nap != NULL) {
1699 nap->na_mtime = temptime;
1701 attrsum += NFSX_V4TIME;
1703 case NFSATTRBIT_TIMEMODIFYSET:
1704 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1705 attrsum += NFSX_UNSIGNED;
1706 i = fxdr_unsigned(int, *tl);
1707 if (i == NFSV4SATTRTIME_TOCLIENT) {
1708 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1709 attrsum += NFSX_V4TIME;
1711 if (compare && !(*retcmpp))
1712 *retcmpp = NFSERR_INVAL;
1714 case NFSATTRBIT_MOUNTEDONFILEID:
1715 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1716 thyp = fxdr_hyper(tl);
1720 *retcmpp = NFSERR_NOTSAME;
1722 if (!vp || !nfsrv_atroot(vp, &fid))
1723 fid = nap->na_fileid;
1724 if ((u_int64_t)fid != thyp)
1725 *retcmpp = NFSERR_NOTSAME;
1728 } else if (nap != NULL) {
1730 printf("NFSv4 mounted on fileid > 32bits\n");
1731 nap->na_mntonfileno = thyp;
1733 attrsum += NFSX_HYPER;
1736 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1738 if (compare && !(*retcmpp))
1739 *retcmpp = NFSERR_ATTRNOTSUPP;
1741 * and get out of the loop, since we can't parse
1742 * the unknown attrbute data.
1744 bitpos = NFSATTRBIT_MAX;
1750 * some clients pad the attrlist, so we need to skip over the
1753 if (attrsum > attrsize) {
1754 error = NFSERR_BADXDR;
1756 attrsize = NFSM_RNDUP(attrsize);
1757 if (attrsum < attrsize)
1758 error = nfsm_advance(nd, attrsize - attrsum, -1);
1761 NFSEXITCODE2(error, nd);
1766 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1767 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1768 * The first argument is a pointer to an nfsv4lock structure.
1769 * The second argument is 1 iff a blocking lock is wanted.
1770 * If this argument is 0, the call waits until no thread either wants nor
1771 * holds an exclusive lock.
1772 * It returns 1 if the lock was acquired, 0 otherwise.
1773 * If several processes call this function concurrently wanting the exclusive
1774 * lock, one will get the lock and the rest will return without getting the
1775 * lock. (If the caller must have the lock, it simply calls this function in a
1776 * loop until the function returns 1 to indicate the lock was acquired.)
1777 * Any usecnt must be decremented by calling nfsv4_relref() before
1778 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1779 * be called in a loop.
1780 * The isleptp argument is set to indicate if the call slept, iff not NULL
1781 * and the mp argument indicates to check for a forced dismount, iff not
1785 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1786 void *mutex, struct mount *mp)
1792 * If a lock is wanted, loop around until the lock is acquired by
1793 * someone and then released. If I want the lock, try to acquire it.
1794 * For a lock to be issued, no lock must be in force and the usecnt
1798 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1799 lp->nfslock_usecnt == 0) {
1800 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1801 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1804 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1806 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1807 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1808 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1811 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1814 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1815 PZERO - 1, "nfsv4lck", NULL);
1816 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1817 lp->nfslock_usecnt == 0) {
1818 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1819 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1827 * Release the lock acquired by nfsv4_lock().
1828 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1829 * incremented, as well.
1832 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1835 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1837 lp->nfslock_usecnt++;
1842 * Release a reference cnt.
1845 nfsv4_relref(struct nfsv4lock *lp)
1848 if (lp->nfslock_usecnt <= 0)
1849 panic("nfsv4root ref cnt");
1850 lp->nfslock_usecnt--;
1851 if (lp->nfslock_usecnt == 0)
1856 * Get a reference cnt.
1857 * This function will wait for any exclusive lock to be released, but will
1858 * not wait for threads that want the exclusive lock. If priority needs
1859 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1860 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1861 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1862 * return without getting a refcnt for that case.
1865 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1873 * Wait for a lock held.
1875 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1876 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1878 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1881 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1882 PZERO - 1, "nfsv4gr", NULL);
1884 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1887 lp->nfslock_usecnt++;
1891 * Get a reference as above, but return failure instead of sleeping if
1892 * an exclusive lock is held.
1895 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1898 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1901 lp->nfslock_usecnt++;
1906 * Test for a lock. Return 1 if locked, 0 otherwise.
1909 nfsv4_testlock(struct nfsv4lock *lp)
1912 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1913 lp->nfslock_usecnt == 0)
1919 * Wake up anyone sleeping, waiting for this lock.
1922 nfsv4_wanted(struct nfsv4lock *lp)
1925 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1926 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1927 wakeup((caddr_t)&lp->nfslock_lock);
1932 * Copy a string from an mbuf list into a character array.
1933 * Return EBADRPC if there is an mbuf error,
1937 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1946 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1947 rem = NFSM_RNDUP(siz) - siz;
1953 NFSBCOPY(cp, str, xfer);
1962 cp = NFSMTOD(mp, caddr_t);
1974 error = nfsm_advance(nd, rem, len);
1980 NFSEXITCODE2(error, nd);
1985 * Fill in the attributes as marked by the bitmap (V4).
1988 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
1989 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
1990 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
1991 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1993 int bitpos, retnum = 0;
1995 int siz, prefixnum, error;
1996 u_char *cp, namestr[NFSV4_SMALLSTR];
1997 nfsattrbit_t attrbits, retbits;
1998 nfsattrbit_t *retbitp = &retbits;
1999 u_int32_t freenum, *retnump;
2002 struct nfsfsinfo fsinf;
2003 struct timespec temptime;
2004 NFSACL_T *aclp, *naclp = NULL;
2011 * First, set the bits that can be filled and get fsinfo.
2013 NFSSET_ATTRBIT(retbitp, attrbitp);
2014 /* If p and cred are NULL, it is a client side call */
2015 if (p == NULL && cred == NULL) {
2016 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2019 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2020 naclp = acl_alloc(M_WAITOK);
2023 nfsvno_getfs(&fsinf, isdgram);
2026 * Get the VFS_STATFS(), since some attributes need them.
2028 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2029 error = VFS_STATFS(mp, &fs);
2032 nd->nd_repstat = NFSERR_ACCES;
2035 NFSCLRSTATFS_ATTRBIT(retbitp);
2041 * And the NFSv4 ACL...
2043 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2044 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2045 supports_nfsv4acls == 0))) {
2046 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2048 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2049 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2050 supports_nfsv4acls == 0)) {
2051 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2052 } else if (naclp != NULL) {
2053 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2054 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2056 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2058 NFSVOPUNLOCK(vp, 0);
2060 error = NFSERR_PERM;
2063 nd->nd_repstat = NFSERR_ACCES;
2066 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2071 * Put out the attribute bitmap for the ones being filled in
2072 * and get the field for the number of attributes returned.
2074 prefixnum = nfsrv_putattrbit(nd, retbitp);
2075 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2076 prefixnum += NFSX_UNSIGNED;
2079 * Now, loop around filling in the attributes for each bit set.
2081 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2082 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2084 case NFSATTRBIT_SUPPORTEDATTRS:
2085 NFSSETSUPP_ATTRBIT(&attrbits);
2086 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2087 && supports_nfsv4acls == 0)) {
2088 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2089 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2091 retnum += nfsrv_putattrbit(nd, &attrbits);
2093 case NFSATTRBIT_TYPE:
2094 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2095 *tl = vtonfsv34_type(vap->va_type);
2096 retnum += NFSX_UNSIGNED;
2098 case NFSATTRBIT_FHEXPIRETYPE:
2099 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2100 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2101 retnum += NFSX_UNSIGNED;
2103 case NFSATTRBIT_CHANGE:
2104 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2105 txdr_hyper(vap->va_filerev, tl);
2106 retnum += NFSX_HYPER;
2108 case NFSATTRBIT_SIZE:
2109 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2110 txdr_hyper(vap->va_size, tl);
2111 retnum += NFSX_HYPER;
2113 case NFSATTRBIT_LINKSUPPORT:
2114 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2115 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2119 retnum += NFSX_UNSIGNED;
2121 case NFSATTRBIT_SYMLINKSUPPORT:
2122 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2123 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2127 retnum += NFSX_UNSIGNED;
2129 case NFSATTRBIT_NAMEDATTR:
2130 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2132 retnum += NFSX_UNSIGNED;
2134 case NFSATTRBIT_FSID:
2135 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2137 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2139 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2140 retnum += NFSX_V4FSID;
2142 case NFSATTRBIT_UNIQUEHANDLES:
2143 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2145 retnum += NFSX_UNSIGNED;
2147 case NFSATTRBIT_LEASETIME:
2148 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2149 *tl = txdr_unsigned(nfsrv_lease);
2150 retnum += NFSX_UNSIGNED;
2152 case NFSATTRBIT_RDATTRERROR:
2153 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2154 *tl = txdr_unsigned(rderror);
2155 retnum += NFSX_UNSIGNED;
2158 * Recommended Attributes. (Only the supported ones.)
2160 case NFSATTRBIT_ACL:
2161 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2163 case NFSATTRBIT_ACLSUPPORT:
2164 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2165 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2166 retnum += NFSX_UNSIGNED;
2168 case NFSATTRBIT_CANSETTIME:
2169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2170 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2174 retnum += NFSX_UNSIGNED;
2176 case NFSATTRBIT_CASEINSENSITIVE:
2177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2179 retnum += NFSX_UNSIGNED;
2181 case NFSATTRBIT_CASEPRESERVING:
2182 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2184 retnum += NFSX_UNSIGNED;
2186 case NFSATTRBIT_CHOWNRESTRICTED:
2187 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2189 retnum += NFSX_UNSIGNED;
2191 case NFSATTRBIT_FILEHANDLE:
2192 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2194 case NFSATTRBIT_FILEID:
2195 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2197 *tl = txdr_unsigned(vap->va_fileid);
2198 retnum += NFSX_HYPER;
2200 case NFSATTRBIT_FILESAVAIL:
2202 * Check quota and use min(quota, f_ffree).
2204 freenum = fs.f_ffree;
2207 * ufs_quotactl() insists that the uid argument
2208 * equal p_ruid for non-root quota access, so
2209 * we'll just make sure that's the case.
2211 savuid = p->p_cred->p_ruid;
2212 p->p_cred->p_ruid = cred->cr_uid;
2213 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2214 cred->cr_uid, (caddr_t)&dqb))
2215 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2217 p->p_cred->p_ruid = savuid;
2219 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2221 *tl = txdr_unsigned(freenum);
2222 retnum += NFSX_HYPER;
2224 case NFSATTRBIT_FILESFREE:
2225 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2227 *tl = txdr_unsigned(fs.f_ffree);
2228 retnum += NFSX_HYPER;
2230 case NFSATTRBIT_FILESTOTAL:
2231 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2233 *tl = txdr_unsigned(fs.f_files);
2234 retnum += NFSX_HYPER;
2236 case NFSATTRBIT_FSLOCATIONS:
2237 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2240 retnum += 2 * NFSX_UNSIGNED;
2242 case NFSATTRBIT_HOMOGENEOUS:
2243 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2244 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2248 retnum += NFSX_UNSIGNED;
2250 case NFSATTRBIT_MAXFILESIZE:
2251 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2252 uquad = NFSRV_MAXFILESIZE;
2253 txdr_hyper(uquad, tl);
2254 retnum += NFSX_HYPER;
2256 case NFSATTRBIT_MAXLINK:
2257 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2258 *tl = txdr_unsigned(LINK_MAX);
2259 retnum += NFSX_UNSIGNED;
2261 case NFSATTRBIT_MAXNAME:
2262 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2263 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2264 retnum += NFSX_UNSIGNED;
2266 case NFSATTRBIT_MAXREAD:
2267 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2269 *tl = txdr_unsigned(fsinf.fs_rtmax);
2270 retnum += NFSX_HYPER;
2272 case NFSATTRBIT_MAXWRITE:
2273 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2275 *tl = txdr_unsigned(fsinf.fs_wtmax);
2276 retnum += NFSX_HYPER;
2278 case NFSATTRBIT_MODE:
2279 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2280 *tl = vtonfsv34_mode(vap->va_mode);
2281 retnum += NFSX_UNSIGNED;
2283 case NFSATTRBIT_NOTRUNC:
2284 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2286 retnum += NFSX_UNSIGNED;
2288 case NFSATTRBIT_NUMLINKS:
2289 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2290 *tl = txdr_unsigned(vap->va_nlink);
2291 retnum += NFSX_UNSIGNED;
2293 case NFSATTRBIT_OWNER:
2295 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2296 retnum += nfsm_strtom(nd, cp, siz);
2298 free(cp, M_NFSSTRING);
2300 case NFSATTRBIT_OWNERGROUP:
2302 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2303 retnum += nfsm_strtom(nd, cp, siz);
2305 free(cp, M_NFSSTRING);
2307 case NFSATTRBIT_QUOTAHARD:
2308 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2309 freenum = fs.f_bfree;
2311 freenum = fs.f_bavail;
2314 * ufs_quotactl() insists that the uid argument
2315 * equal p_ruid for non-root quota access, so
2316 * we'll just make sure that's the case.
2318 savuid = p->p_cred->p_ruid;
2319 p->p_cred->p_ruid = cred->cr_uid;
2320 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2321 cred->cr_uid, (caddr_t)&dqb))
2322 freenum = min(dqb.dqb_bhardlimit, freenum);
2323 p->p_cred->p_ruid = savuid;
2325 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2326 uquad = (u_int64_t)freenum;
2327 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2328 txdr_hyper(uquad, tl);
2329 retnum += NFSX_HYPER;
2331 case NFSATTRBIT_QUOTASOFT:
2332 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2333 freenum = fs.f_bfree;
2335 freenum = fs.f_bavail;
2338 * ufs_quotactl() insists that the uid argument
2339 * equal p_ruid for non-root quota access, so
2340 * we'll just make sure that's the case.
2342 savuid = p->p_cred->p_ruid;
2343 p->p_cred->p_ruid = cred->cr_uid;
2344 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2345 cred->cr_uid, (caddr_t)&dqb))
2346 freenum = min(dqb.dqb_bsoftlimit, freenum);
2347 p->p_cred->p_ruid = savuid;
2349 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2350 uquad = (u_int64_t)freenum;
2351 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2352 txdr_hyper(uquad, tl);
2353 retnum += NFSX_HYPER;
2355 case NFSATTRBIT_QUOTAUSED:
2359 * ufs_quotactl() insists that the uid argument
2360 * equal p_ruid for non-root quota access, so
2361 * we'll just make sure that's the case.
2363 savuid = p->p_cred->p_ruid;
2364 p->p_cred->p_ruid = cred->cr_uid;
2365 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2366 cred->cr_uid, (caddr_t)&dqb))
2367 freenum = dqb.dqb_curblocks;
2368 p->p_cred->p_ruid = savuid;
2370 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2371 uquad = (u_int64_t)freenum;
2372 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2373 txdr_hyper(uquad, tl);
2374 retnum += NFSX_HYPER;
2376 case NFSATTRBIT_RAWDEV:
2377 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2378 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2379 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2380 retnum += NFSX_V4SPECDATA;
2382 case NFSATTRBIT_SPACEAVAIL:
2383 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2384 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2385 uquad = (u_int64_t)fs.f_bfree;
2387 uquad = (u_int64_t)fs.f_bavail;
2388 uquad *= fs.f_bsize;
2389 txdr_hyper(uquad, tl);
2390 retnum += NFSX_HYPER;
2392 case NFSATTRBIT_SPACEFREE:
2393 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2394 uquad = (u_int64_t)fs.f_bfree;
2395 uquad *= fs.f_bsize;
2396 txdr_hyper(uquad, tl);
2397 retnum += NFSX_HYPER;
2399 case NFSATTRBIT_SPACETOTAL:
2400 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2401 uquad = (u_int64_t)fs.f_blocks;
2402 uquad *= fs.f_bsize;
2403 txdr_hyper(uquad, tl);
2404 retnum += NFSX_HYPER;
2406 case NFSATTRBIT_SPACEUSED:
2407 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2408 txdr_hyper(vap->va_bytes, tl);
2409 retnum += NFSX_HYPER;
2411 case NFSATTRBIT_TIMEACCESS:
2412 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2413 txdr_nfsv4time(&vap->va_atime, tl);
2414 retnum += NFSX_V4TIME;
2416 case NFSATTRBIT_TIMEACCESSSET:
2417 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2418 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2419 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2420 txdr_nfsv4time(&vap->va_atime, tl);
2421 retnum += NFSX_V4SETTIME;
2423 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2424 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2425 retnum += NFSX_UNSIGNED;
2428 case NFSATTRBIT_TIMEDELTA:
2429 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2430 temptime.tv_sec = 0;
2431 temptime.tv_nsec = 1000000000 / hz;
2432 txdr_nfsv4time(&temptime, tl);
2433 retnum += NFSX_V4TIME;
2435 case NFSATTRBIT_TIMEMETADATA:
2436 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2437 txdr_nfsv4time(&vap->va_ctime, tl);
2438 retnum += NFSX_V4TIME;
2440 case NFSATTRBIT_TIMEMODIFY:
2441 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2442 txdr_nfsv4time(&vap->va_mtime, tl);
2443 retnum += NFSX_V4TIME;
2445 case NFSATTRBIT_TIMEMODIFYSET:
2446 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2447 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2448 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2449 txdr_nfsv4time(&vap->va_mtime, tl);
2450 retnum += NFSX_V4SETTIME;
2452 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2453 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2454 retnum += NFSX_UNSIGNED;
2457 case NFSATTRBIT_MOUNTEDONFILEID:
2458 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2460 uquad = mounted_on_fileno;
2462 uquad = (u_int64_t)vap->va_fileid;
2463 txdr_hyper(uquad, tl);
2464 retnum += NFSX_HYPER;
2467 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2473 *retnump = txdr_unsigned(retnum);
2474 return (retnum + prefixnum);
2478 * Put the attribute bits onto an mbuf list.
2479 * Return the number of bytes of output generated.
2482 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2485 int cnt, i, bytesize;
2487 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2488 if (attrbitp->bits[cnt - 1])
2490 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2491 NFSM_BUILD(tl, u_int32_t *, bytesize);
2492 *tl++ = txdr_unsigned(cnt);
2493 for (i = 0; i < cnt; i++)
2494 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2499 * Convert a uid to a string.
2500 * If the lookup fails, just output the digits.
2502 * cpp - points to a buffer of size NFSV4_SMALLSTR
2503 * (malloc a larger one, as required)
2504 * retlenp - pointer to length to be returned
2507 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2510 struct nfsusrgrp *usrp;
2513 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2518 if (nfsrv_dnsname) {
2520 * Always map nfsrv_defaultuid to "nobody".
2522 if (uid == nfsrv_defaultuid) {
2523 i = nfsrv_dnsnamelen + 7;
2526 if (len > NFSV4_SMALLSTR)
2527 free(cp, M_NFSSTRING);
2528 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2534 NFSBCOPY("nobody@", cp, 7);
2536 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2541 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2542 if (usrp->lug_uid == uid) {
2543 if (usrp->lug_expiry < NFSD_MONOSEC)
2546 * If the name doesn't already have an '@'
2547 * in it, append @domainname to it.
2549 for (i = 0; i < usrp->lug_namelen; i++) {
2550 if (usrp->lug_name[i] == '@') {
2556 i = usrp->lug_namelen;
2558 i = usrp->lug_namelen +
2559 nfsrv_dnsnamelen + 1;
2562 if (len > NFSV4_SMALLSTR)
2563 free(cp, M_NFSSTRING);
2564 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2570 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2571 if (!hasampersand) {
2572 cp += usrp->lug_namelen;
2574 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2576 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2577 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2584 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2586 if (ret == 0 && cnt < 2)
2593 * No match, just return a string of digits.
2597 while (tmp || i == 0) {
2601 len = (i > len) ? len : i;
2605 for (i = 0; i < len; i++) {
2606 *cp-- = '0' + (tmp % 10);
2613 * Convert a string to a uid.
2614 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2616 * If this is called from a client side mount using AUTH_SYS and the
2617 * string is made up entirely of digits, just convert the string to
2621 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2625 char *cp, *endstr, *str0;
2626 struct nfsusrgrp *usrp;
2632 error = NFSERR_BADOWNER;
2635 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2637 tuid = (uid_t)strtoul(str0, &endstr, 10);
2638 if ((endstr - str0) == len &&
2639 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2646 cp = strchr(str0, '@');
2648 i = (int)(cp++ - str0);
2656 * If an '@' is found and the domain name matches, search for the name
2657 * with dns stripped off.
2658 * Mixed case alpahbetics will match for the domain name, but all
2659 * upper case will not.
2661 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2662 (len - 1 - i) == nfsrv_dnsnamelen &&
2663 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2664 len -= (nfsrv_dnsnamelen + 1);
2669 * Check for the special case of "nobody".
2671 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2672 *uidp = nfsrv_defaultuid;
2678 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2679 if (usrp->lug_namelen == len &&
2680 !NFSBCMP(usrp->lug_name, str, len)) {
2681 if (usrp->lug_expiry < NFSD_MONOSEC)
2683 *uidp = usrp->lug_uid;
2684 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2685 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2693 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2695 if (ret == 0 && cnt < 2)
2697 error = NFSERR_BADOWNER;
2705 * Convert a gid to a string.
2706 * gid - the group id
2707 * cpp - points to a buffer of size NFSV4_SMALLSTR
2708 * (malloc a larger one, as required)
2709 * retlenp - pointer to length to be returned
2712 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2715 struct nfsusrgrp *usrp;
2718 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2723 if (nfsrv_dnsname) {
2725 * Always map nfsrv_defaultgid to "nogroup".
2727 if (gid == nfsrv_defaultgid) {
2728 i = nfsrv_dnsnamelen + 8;
2731 if (len > NFSV4_SMALLSTR)
2732 free(cp, M_NFSSTRING);
2733 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2739 NFSBCOPY("nogroup@", cp, 8);
2741 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2746 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2747 if (usrp->lug_gid == gid) {
2748 if (usrp->lug_expiry < NFSD_MONOSEC)
2751 * If the name doesn't already have an '@'
2752 * in it, append @domainname to it.
2754 for (i = 0; i < usrp->lug_namelen; i++) {
2755 if (usrp->lug_name[i] == '@') {
2761 i = usrp->lug_namelen;
2763 i = usrp->lug_namelen +
2764 nfsrv_dnsnamelen + 1;
2767 if (len > NFSV4_SMALLSTR)
2768 free(cp, M_NFSSTRING);
2769 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2775 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2776 if (!hasampersand) {
2777 cp += usrp->lug_namelen;
2779 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2781 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2782 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2789 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2791 if (ret == 0 && cnt < 2)
2798 * No match, just return a string of digits.
2802 while (tmp || i == 0) {
2806 len = (i > len) ? len : i;
2810 for (i = 0; i < len; i++) {
2811 *cp-- = '0' + (tmp % 10);
2818 * Convert a string to a gid.
2819 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2821 * If this is called from a client side mount using AUTH_SYS and the
2822 * string is made up entirely of digits, just convert the string to
2826 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2830 char *cp, *endstr, *str0;
2831 struct nfsusrgrp *usrp;
2837 error = NFSERR_BADOWNER;
2840 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2842 tgid = (gid_t)strtoul(str0, &endstr, 10);
2843 if ((endstr - str0) == len &&
2844 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2851 cp = strchr(str0, '@');
2853 i = (int)(cp++ - str0);
2861 * If an '@' is found and the dns name matches, search for the name
2862 * with the dns stripped off.
2864 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2865 (len - 1 - i) == nfsrv_dnsnamelen &&
2866 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2867 len -= (nfsrv_dnsnamelen + 1);
2872 * Check for the special case of "nogroup".
2874 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2875 *gidp = nfsrv_defaultgid;
2881 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2882 if (usrp->lug_namelen == len &&
2883 !NFSBCMP(usrp->lug_name, str, len)) {
2884 if (usrp->lug_expiry < NFSD_MONOSEC)
2886 *gidp = usrp->lug_gid;
2887 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2888 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2896 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2898 if (ret == 0 && cnt < 2)
2900 error = NFSERR_BADOWNER;
2908 * Cmp len chars, allowing mixed case in the first argument to match lower
2909 * case in the second, but not if the first argument is all upper case.
2910 * Return 0 for a match, 1 otherwise.
2913 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2919 for (i = 0; i < len; i++) {
2920 if (*cp >= 'A' && *cp <= 'Z') {
2921 tmp = *cp++ + ('a' - 'A');
2924 if (tmp >= 'a' && tmp <= 'z')
2937 * Set the port for the nfsuserd.
2940 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2942 struct nfssockreq *rp;
2943 struct sockaddr_in *ad;
2947 if (nfsrv_nfsuserd) {
2955 * Set up the socket record and connect.
2957 rp = &nfsrv_nfsuserdsock;
2958 rp->nr_client = NULL;
2959 rp->nr_sotype = SOCK_DGRAM;
2960 rp->nr_soproto = IPPROTO_UDP;
2961 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2963 NFSSOCKADDRALLOC(rp->nr_nam);
2964 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2965 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2966 ad->sin_family = AF_INET;
2967 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2968 ad->sin_port = port;
2969 rp->nr_prog = RPCPROG_NFSUSERD;
2970 rp->nr_vers = RPCNFSUSERD_VERS;
2971 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2973 NFSSOCKADDRFREE(rp->nr_nam);
2982 * Delete the nfsuserd port.
2985 nfsrv_nfsuserddelport(void)
2989 if (nfsrv_nfsuserd == 0) {
2995 newnfs_disconnect(&nfsrv_nfsuserdsock);
2996 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3000 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3002 * Returns 0 upon success, non-zero otherwise.
3005 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3008 struct nfsrv_descript *nd;
3010 struct nfsrv_descript nfsd;
3015 if (nfsrv_nfsuserd == 0) {
3022 cred = newnfs_getcred();
3023 nd->nd_flag = ND_GSSINITREPLY;
3026 nd->nd_procnum = procnum;
3027 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3028 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3029 if (procnum == RPCNFSUSERD_GETUID)
3030 *tl = txdr_unsigned(uid);
3032 *tl = txdr_unsigned(gid);
3035 (void) nfsm_strtom(nd, name, len);
3037 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3038 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3041 mbuf_freem(nd->nd_mrep);
3042 error = nd->nd_repstat;
3050 * This function is called from the nfssvc(2) system call, to update the
3051 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3054 nfssvc_idname(struct nfsd_idargs *nidp)
3056 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3057 struct nfsuserhashhead *hp;
3062 if (nidp->nid_flag & NFSID_INITIALIZE) {
3063 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3064 M_NFSSTRING, M_WAITOK);
3065 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3068 if (nfsrv_dnsname) {
3070 * Free up all the old stuff and reinitialize hash lists.
3072 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3073 nfsrv_removeuser(usrp);
3075 free(nfsrv_dnsname, M_NFSSTRING);
3076 nfsrv_dnsname = NULL;
3078 TAILQ_INIT(&nfsuserlruhead);
3079 for (i = 0; i < NFSUSERHASHSIZE; i++)
3080 LIST_INIT(&nfsuserhash[i]);
3081 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3082 LIST_INIT(&nfsgrouphash[i]);
3083 for (i = 0; i < NFSUSERHASHSIZE; i++)
3084 LIST_INIT(&nfsusernamehash[i]);
3085 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3086 LIST_INIT(&nfsgroupnamehash[i]);
3089 * Put name in "DNS" string.
3093 nfsrv_dnsnamelen = nidp->nid_namelen;
3094 nfsrv_defaultuid = nidp->nid_uid;
3095 nfsrv_defaultgid = nidp->nid_gid;
3097 nfsrv_usermax = nidp->nid_usermax;
3101 free(cp, M_NFSSTRING);
3106 * malloc the new one now, so any potential sleep occurs before
3107 * manipulation of the lists.
3109 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3110 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3111 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3114 free((caddr_t)newusrp, M_NFSUSERGROUP);
3117 newusrp->lug_namelen = nidp->nid_namelen;
3121 * Delete old entries, as required.
3123 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3124 hp = NFSUSERHASH(nidp->nid_uid);
3125 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3126 if (usrp->lug_uid == nidp->nid_uid)
3127 nfsrv_removeuser(usrp);
3130 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3131 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3132 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3133 if (usrp->lug_namelen == newusrp->lug_namelen &&
3134 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3136 nfsrv_removeuser(usrp);
3139 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3140 hp = NFSGROUPHASH(nidp->nid_gid);
3141 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3142 if (usrp->lug_gid == nidp->nid_gid)
3143 nfsrv_removeuser(usrp);
3146 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3147 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3148 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3149 if (usrp->lug_namelen == newusrp->lug_namelen &&
3150 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3152 nfsrv_removeuser(usrp);
3155 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3156 if (usrp->lug_expiry < NFSD_MONOSEC)
3157 nfsrv_removeuser(usrp);
3159 while (nfsrv_usercnt >= nfsrv_usermax) {
3160 usrp = TAILQ_FIRST(&nfsuserlruhead);
3161 nfsrv_removeuser(usrp);
3165 * Now, we can add the new one.
3167 if (nidp->nid_usertimeout)
3168 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3170 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3171 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3172 newusrp->lug_uid = nidp->nid_uid;
3173 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3175 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3176 newusrp->lug_namelen), newusrp, lug_namehash);
3177 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3179 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3180 newusrp->lug_gid = nidp->nid_gid;
3181 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3183 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3184 newusrp->lug_namelen), newusrp, lug_namehash);
3185 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3188 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3196 * Remove a user/group name element.
3199 nfsrv_removeuser(struct nfsusrgrp *usrp)
3202 NFSNAMEIDREQUIRED();
3203 LIST_REMOVE(usrp, lug_numhash);
3204 LIST_REMOVE(usrp, lug_namehash);
3205 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3207 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3211 * This function scans a byte string and checks for UTF-8 compliance.
3212 * It returns 0 if it conforms and NFSERR_INVAL if not.
3215 nfsrv_checkutf8(u_int8_t *cp, int len)
3217 u_int32_t val = 0x0;
3218 int cnt = 0, gotd = 0, shift = 0;
3220 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3224 * Here are what the variables are used for:
3225 * val - the calculated value of a multibyte char, used to check
3226 * that it was coded with the correct range
3227 * cnt - the number of 10xxxxxx bytes to follow
3228 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3229 * shift - lower order bits of range (ie. "val >> shift" should
3230 * not be 0, in other words, dividing by the lower bound
3231 * of the range should get a non-zero value)
3232 * byte - used to calculate cnt
3236 /* This handles the 10xxxxxx bytes */
3237 if ((*cp & 0xc0) != 0x80 ||
3238 (gotd && (*cp & 0x20))) {
3239 error = NFSERR_INVAL;
3244 val |= (*cp & 0x3f);
3246 if (cnt == 0 && (val >> shift) == 0x0) {
3247 error = NFSERR_INVAL;
3250 } else if (*cp & 0x80) {
3251 /* first byte of multi byte char */
3253 while ((byte & 0x40) && cnt < 6) {
3257 if (cnt == 0 || cnt == 6) {
3258 error = NFSERR_INVAL;
3261 val = (*cp & (0x3f >> cnt));
3262 shift = utf8_shift[cnt - 1];
3263 if (cnt == 2 && val == 0xd)
3264 /* Check for the 0xd800-0xdfff case */
3271 error = NFSERR_INVAL;
3279 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3280 * strings, one with the root path in it and the other with the list of
3281 * locations. The list is in the same format as is found in nfr_refs.
3282 * It is a "," separated list of entries, where each of them is of the
3283 * form <server>:<rootpath>. For example
3284 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3285 * The nilp argument is set to 1 for the special case of a null fs_root
3286 * and an empty server list.
3287 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3288 * number of xdr bytes parsed in sump.
3291 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3292 int *sump, int *nilp)
3295 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3296 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3298 SLIST_ENTRY(list) next;
3302 SLIST_HEAD(, list) head;
3309 * Get the fs_root path and check for the special case of null path
3310 * and 0 length server list.
3312 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3313 len = fxdr_unsigned(int, *tl);
3314 if (len < 0 || len > 10240) {
3315 error = NFSERR_BADXDR;
3319 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3321 error = NFSERR_BADXDR;
3325 *sump = 2 * NFSX_UNSIGNED;
3329 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3330 error = nfsrv_mtostr(nd, cp, len);
3332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3333 cnt = fxdr_unsigned(int, *tl);
3335 error = NFSERR_BADXDR;
3341 * Now, loop through the location list and make up the srvlist.
3343 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3344 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3347 for (i = 0; i < cnt; i++) {
3349 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3350 nsrv = fxdr_unsigned(int, *tl);
3352 error = NFSERR_BADXDR;
3357 * Handle the first server by putting it in the srvstr.
3359 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3360 len = fxdr_unsigned(int, *tl);
3361 if (len <= 0 || len > 1024) {
3362 error = NFSERR_BADXDR;
3365 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3370 error = nfsrv_mtostr(nd, cp3, len);
3376 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3377 for (j = 1; j < nsrv; j++) {
3379 * Yuck, put them in an slist and process them later.
3381 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3382 len = fxdr_unsigned(int, *tl);
3383 if (len <= 0 || len > 1024) {
3384 error = NFSERR_BADXDR;
3387 lsp = (struct list *)malloc(sizeof (struct list)
3388 + len, M_TEMP, M_WAITOK);
3389 error = nfsrv_mtostr(nd, lsp->host, len);
3392 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3394 SLIST_INSERT_HEAD(&head, lsp, next);
3398 * Finally, we can get the path.
3400 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3401 len = fxdr_unsigned(int, *tl);
3402 if (len <= 0 || len > 1024) {
3403 error = NFSERR_BADXDR;
3406 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3407 error = nfsrv_mtostr(nd, cp3, len);
3410 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3415 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3416 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3419 NFSBCOPY(lsp->host, cp3, lsp->len);
3422 NFSBCOPY(str, cp3, stringlen);
3425 siz += (lsp->len + stringlen + 2);
3426 free((caddr_t)lsp, M_TEMP);
3432 NFSEXITCODE2(0, nd);
3436 free(cp, M_NFSSTRING);
3438 free(cp2, M_NFSSTRING);
3439 NFSEXITCODE2(error, nd);
3444 * Make the malloc'd space large enough. This is a pain, but the xdr
3445 * doesn't set an upper bound on the side, so...
3448 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3455 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3456 NFSBCOPY(*cpp, cp, *slenp);
3457 free(*cpp, M_NFSSTRING);
3461 *slenp = siz + 1024;
3465 * Initialize the reply header data structures.
3468 nfsrvd_rephead(struct nfsrv_descript *nd)
3473 * If this is a big reply, use a cluster.
3475 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3476 nfs_bigreply[nd->nd_procnum]) {
3477 NFSMCLGET(mreq, M_WAITOK);
3485 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3486 mbuf_setlen(mreq, 0);
3488 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3489 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3493 * Lock a socket against others.
3494 * Currently used to serialize connect/disconnect attempts.
3497 newnfs_sndlock(int *flagp)
3502 while (*flagp & NFSR_SNDLOCK) {
3503 *flagp |= NFSR_WANTSND;
3506 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3507 PZERO - 1, "nfsndlck", &ts);
3509 *flagp |= NFSR_SNDLOCK;
3515 * Unlock the stream socket for others.
3518 newnfs_sndunlock(int *flagp)
3522 if ((*flagp & NFSR_SNDLOCK) == 0)
3523 panic("nfs sndunlock");
3524 *flagp &= ~NFSR_SNDLOCK;
3525 if (*flagp & NFSR_WANTSND) {
3526 *flagp &= ~NFSR_WANTSND;
3527 wakeup((caddr_t)flagp);
3533 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3536 struct sockaddr_in *sad;
3537 struct sockaddr_in6 *sad6;
3538 struct in_addr saddr;
3539 uint32_t portnum, *tl;
3540 int af = 0, i, j, k;
3541 char addr[64], protocol[5], *cp;
3542 int cantparse = 0, error = 0;
3545 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3546 i = fxdr_unsigned(int, *tl);
3547 if (i >= 3 && i <= 4) {
3548 error = nfsrv_mtostr(nd, protocol, i);
3551 if (strcmp(protocol, "tcp") == 0) {
3554 } else if (strcmp(protocol, "udp") == 0) {
3557 } else if (strcmp(protocol, "tcp6") == 0) {
3560 } else if (strcmp(protocol, "udp6") == 0) {
3568 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3573 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3574 i = fxdr_unsigned(int, *tl);
3576 error = NFSERR_BADXDR;
3578 } else if (cantparse == 0 && i >= 11 && i < 64) {
3580 * The shortest address is 11chars and the longest is < 64.
3582 error = nfsrv_mtostr(nd, addr, i);
3586 /* Find the port# at the end and extract that. */
3590 /* Count back two '.'s from end to get port# field. */
3591 for (j = 0; j < i; j++) {
3601 * The NFSv4 port# is appended as .N.N, where N is
3602 * a decimal # in the range 0-255, just like an inet4
3603 * address. Cheat and use inet_aton(), which will
3604 * return a Class A address and then shift the high
3605 * order 8bits over to convert it to the port#.
3608 if (inet_aton(cp, &saddr) == 1) {
3609 portnum = ntohl(saddr.s_addr);
3610 portv = (uint16_t)((portnum >> 16) |
3616 if (cantparse == 0) {
3617 if (af == AF_INET) {
3618 sad = (struct sockaddr_in *)sa;
3619 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
3620 sad->sin_len = sizeof(*sad);
3621 sad->sin_family = AF_INET;
3622 sad->sin_port = htons(portv);
3626 sad6 = (struct sockaddr_in6 *)sa;
3627 if (inet_pton(af, addr, &sad6->sin6_addr)
3629 sad6->sin6_len = sizeof(*sad6);
3630 sad6->sin6_family = AF_INET6;
3631 sad6->sin6_port = htons(portv);
3638 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3649 * Handle an NFSv4.1 Sequence request for the session.
3652 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
3653 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
3659 if (slotid > maxslot)
3660 return (NFSERR_BADSLOT);
3661 if (seqid == slots[slotid].nfssl_seq) {
3663 if (slots[slotid].nfssl_inprog != 0)
3664 error = NFSERR_DELAY;
3665 else if (slots[slotid].nfssl_reply != NULL) {
3666 *reply = slots[slotid].nfssl_reply;
3667 slots[slotid].nfssl_reply = NULL;
3668 slots[slotid].nfssl_inprog = 1;
3670 error = NFSERR_SEQMISORDERED;
3671 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
3672 m_freem(slots[slotid].nfssl_reply);
3673 slots[slotid].nfssl_reply = NULL;
3674 slots[slotid].nfssl_inprog = 1;
3675 slots[slotid].nfssl_seq++;
3677 error = NFSERR_SEQMISORDERED;
3682 * Cache this reply for the slot.
3685 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep)
3688 slots[slotid].nfssl_reply = rep;
3689 slots[slotid].nfssl_inprog = 0;
3693 * Generate the xdr for an NFSv4.1 Sequence Operation.
3696 nfsv4_setsequence(struct nfsrv_descript *nd, struct nfsclsession *sep,
3697 int dont_replycache)
3699 uint32_t *tl, slotseq = 0;
3700 int i, maxslot, slotpos;
3702 uint8_t sessionid[NFSX_V4SESSIONID];
3704 /* Find an unused slot. */
3707 mtx_lock(&sep->nfsess_mtx);
3710 for (i = 0; i < sep->nfsess_foreslots; i++) {
3711 if ((bitval & sep->nfsess_slots) == 0) {
3713 sep->nfsess_slots |= bitval;
3714 sep->nfsess_slotseq[i]++;
3715 slotseq = sep->nfsess_slotseq[i];
3721 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
3722 PZERO, "nfsclseq", 0);
3723 } while (slotpos == -1);
3724 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
3726 for (i = 0; i < 64; i++) {
3727 if ((bitval & sep->nfsess_slots) != 0)
3731 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
3732 mtx_unlock(&sep->nfsess_mtx);
3733 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
3735 /* Build the Sequence arguments. */
3736 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
3737 bcopy(sessionid, tl, NFSX_V4SESSIONID);
3738 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
3739 nd->nd_slotseq = tl;
3740 *tl++ = txdr_unsigned(slotseq);
3741 *tl++ = txdr_unsigned(slotpos);
3742 *tl++ = txdr_unsigned(maxslot);
3743 if (dont_replycache == 0)
3747 nd->nd_flag |= ND_HASSEQUENCE;
3751 * Free a session slot.
3754 nfsv4_freeslot(struct nfsclsession *sep, int slot)
3761 mtx_lock(&sep->nfsess_mtx);
3762 if ((bitval & sep->nfsess_slots) == 0)
3763 printf("freeing free slot!!\n");
3764 sep->nfsess_slots &= ~bitval;
3765 wakeup(&sep->nfsess_slots);
3766 mtx_unlock(&sep->nfsess_mtx);