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, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */
105 { 1, 2, 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);
2015 * If both p and cred are NULL, it is a client side setattr call.
2016 * If both p and cred are not NULL, it is a server side reply call.
2017 * If p is not NULL and cred is NULL, it is a client side callback
2020 if (p == NULL && cred == NULL) {
2021 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2024 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2025 naclp = acl_alloc(M_WAITOK);
2028 nfsvno_getfs(&fsinf, isdgram);
2031 * Get the VFS_STATFS(), since some attributes need them.
2033 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2034 error = VFS_STATFS(mp, &fs);
2037 nd->nd_repstat = NFSERR_ACCES;
2040 NFSCLRSTATFS_ATTRBIT(retbitp);
2046 * And the NFSv4 ACL...
2048 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2049 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2050 supports_nfsv4acls == 0))) {
2051 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2053 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2054 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2055 supports_nfsv4acls == 0)) {
2056 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2057 } else if (naclp != NULL) {
2058 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2059 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2061 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2063 NFSVOPUNLOCK(vp, 0);
2065 error = NFSERR_PERM;
2068 nd->nd_repstat = NFSERR_ACCES;
2071 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2076 * Put out the attribute bitmap for the ones being filled in
2077 * and get the field for the number of attributes returned.
2079 prefixnum = nfsrv_putattrbit(nd, retbitp);
2080 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2081 prefixnum += NFSX_UNSIGNED;
2084 * Now, loop around filling in the attributes for each bit set.
2086 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2087 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2089 case NFSATTRBIT_SUPPORTEDATTRS:
2090 NFSSETSUPP_ATTRBIT(&attrbits);
2091 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2092 && supports_nfsv4acls == 0)) {
2093 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2094 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2096 retnum += nfsrv_putattrbit(nd, &attrbits);
2098 case NFSATTRBIT_TYPE:
2099 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2100 *tl = vtonfsv34_type(vap->va_type);
2101 retnum += NFSX_UNSIGNED;
2103 case NFSATTRBIT_FHEXPIRETYPE:
2104 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2105 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2106 retnum += NFSX_UNSIGNED;
2108 case NFSATTRBIT_CHANGE:
2109 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2110 txdr_hyper(vap->va_filerev, tl);
2111 retnum += NFSX_HYPER;
2113 case NFSATTRBIT_SIZE:
2114 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2115 txdr_hyper(vap->va_size, tl);
2116 retnum += NFSX_HYPER;
2118 case NFSATTRBIT_LINKSUPPORT:
2119 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2120 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2124 retnum += NFSX_UNSIGNED;
2126 case NFSATTRBIT_SYMLINKSUPPORT:
2127 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2128 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2132 retnum += NFSX_UNSIGNED;
2134 case NFSATTRBIT_NAMEDATTR:
2135 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2137 retnum += NFSX_UNSIGNED;
2139 case NFSATTRBIT_FSID:
2140 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2142 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2144 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2145 retnum += NFSX_V4FSID;
2147 case NFSATTRBIT_UNIQUEHANDLES:
2148 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2150 retnum += NFSX_UNSIGNED;
2152 case NFSATTRBIT_LEASETIME:
2153 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2154 *tl = txdr_unsigned(nfsrv_lease);
2155 retnum += NFSX_UNSIGNED;
2157 case NFSATTRBIT_RDATTRERROR:
2158 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2159 *tl = txdr_unsigned(rderror);
2160 retnum += NFSX_UNSIGNED;
2163 * Recommended Attributes. (Only the supported ones.)
2165 case NFSATTRBIT_ACL:
2166 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2168 case NFSATTRBIT_ACLSUPPORT:
2169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2170 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2171 retnum += NFSX_UNSIGNED;
2173 case NFSATTRBIT_CANSETTIME:
2174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2175 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2179 retnum += NFSX_UNSIGNED;
2181 case NFSATTRBIT_CASEINSENSITIVE:
2182 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2184 retnum += NFSX_UNSIGNED;
2186 case NFSATTRBIT_CASEPRESERVING:
2187 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2189 retnum += NFSX_UNSIGNED;
2191 case NFSATTRBIT_CHOWNRESTRICTED:
2192 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2194 retnum += NFSX_UNSIGNED;
2196 case NFSATTRBIT_FILEHANDLE:
2197 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2199 case NFSATTRBIT_FILEID:
2200 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2202 *tl = txdr_unsigned(vap->va_fileid);
2203 retnum += NFSX_HYPER;
2205 case NFSATTRBIT_FILESAVAIL:
2207 * Check quota and use min(quota, f_ffree).
2209 freenum = fs.f_ffree;
2212 * ufs_quotactl() insists that the uid argument
2213 * equal p_ruid for non-root quota access, so
2214 * we'll just make sure that's the case.
2216 savuid = p->p_cred->p_ruid;
2217 p->p_cred->p_ruid = cred->cr_uid;
2218 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2219 cred->cr_uid, (caddr_t)&dqb))
2220 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2222 p->p_cred->p_ruid = savuid;
2224 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2226 *tl = txdr_unsigned(freenum);
2227 retnum += NFSX_HYPER;
2229 case NFSATTRBIT_FILESFREE:
2230 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2232 *tl = txdr_unsigned(fs.f_ffree);
2233 retnum += NFSX_HYPER;
2235 case NFSATTRBIT_FILESTOTAL:
2236 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2238 *tl = txdr_unsigned(fs.f_files);
2239 retnum += NFSX_HYPER;
2241 case NFSATTRBIT_FSLOCATIONS:
2242 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2245 retnum += 2 * NFSX_UNSIGNED;
2247 case NFSATTRBIT_HOMOGENEOUS:
2248 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2249 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2253 retnum += NFSX_UNSIGNED;
2255 case NFSATTRBIT_MAXFILESIZE:
2256 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2257 uquad = NFSRV_MAXFILESIZE;
2258 txdr_hyper(uquad, tl);
2259 retnum += NFSX_HYPER;
2261 case NFSATTRBIT_MAXLINK:
2262 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2263 *tl = txdr_unsigned(LINK_MAX);
2264 retnum += NFSX_UNSIGNED;
2266 case NFSATTRBIT_MAXNAME:
2267 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2268 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2269 retnum += NFSX_UNSIGNED;
2271 case NFSATTRBIT_MAXREAD:
2272 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2274 *tl = txdr_unsigned(fsinf.fs_rtmax);
2275 retnum += NFSX_HYPER;
2277 case NFSATTRBIT_MAXWRITE:
2278 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2280 *tl = txdr_unsigned(fsinf.fs_wtmax);
2281 retnum += NFSX_HYPER;
2283 case NFSATTRBIT_MODE:
2284 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2285 *tl = vtonfsv34_mode(vap->va_mode);
2286 retnum += NFSX_UNSIGNED;
2288 case NFSATTRBIT_NOTRUNC:
2289 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2291 retnum += NFSX_UNSIGNED;
2293 case NFSATTRBIT_NUMLINKS:
2294 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2295 *tl = txdr_unsigned(vap->va_nlink);
2296 retnum += NFSX_UNSIGNED;
2298 case NFSATTRBIT_OWNER:
2300 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2301 retnum += nfsm_strtom(nd, cp, siz);
2303 free(cp, M_NFSSTRING);
2305 case NFSATTRBIT_OWNERGROUP:
2307 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2308 retnum += nfsm_strtom(nd, cp, siz);
2310 free(cp, M_NFSSTRING);
2312 case NFSATTRBIT_QUOTAHARD:
2313 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2314 freenum = fs.f_bfree;
2316 freenum = fs.f_bavail;
2319 * ufs_quotactl() insists that the uid argument
2320 * equal p_ruid for non-root quota access, so
2321 * we'll just make sure that's the case.
2323 savuid = p->p_cred->p_ruid;
2324 p->p_cred->p_ruid = cred->cr_uid;
2325 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2326 cred->cr_uid, (caddr_t)&dqb))
2327 freenum = min(dqb.dqb_bhardlimit, freenum);
2328 p->p_cred->p_ruid = savuid;
2330 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2331 uquad = (u_int64_t)freenum;
2332 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2333 txdr_hyper(uquad, tl);
2334 retnum += NFSX_HYPER;
2336 case NFSATTRBIT_QUOTASOFT:
2337 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2338 freenum = fs.f_bfree;
2340 freenum = fs.f_bavail;
2343 * ufs_quotactl() insists that the uid argument
2344 * equal p_ruid for non-root quota access, so
2345 * we'll just make sure that's the case.
2347 savuid = p->p_cred->p_ruid;
2348 p->p_cred->p_ruid = cred->cr_uid;
2349 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2350 cred->cr_uid, (caddr_t)&dqb))
2351 freenum = min(dqb.dqb_bsoftlimit, freenum);
2352 p->p_cred->p_ruid = savuid;
2354 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2355 uquad = (u_int64_t)freenum;
2356 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2357 txdr_hyper(uquad, tl);
2358 retnum += NFSX_HYPER;
2360 case NFSATTRBIT_QUOTAUSED:
2364 * ufs_quotactl() insists that the uid argument
2365 * equal p_ruid for non-root quota access, so
2366 * we'll just make sure that's the case.
2368 savuid = p->p_cred->p_ruid;
2369 p->p_cred->p_ruid = cred->cr_uid;
2370 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2371 cred->cr_uid, (caddr_t)&dqb))
2372 freenum = dqb.dqb_curblocks;
2373 p->p_cred->p_ruid = savuid;
2375 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2376 uquad = (u_int64_t)freenum;
2377 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2378 txdr_hyper(uquad, tl);
2379 retnum += NFSX_HYPER;
2381 case NFSATTRBIT_RAWDEV:
2382 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2383 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2384 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2385 retnum += NFSX_V4SPECDATA;
2387 case NFSATTRBIT_SPACEAVAIL:
2388 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2389 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2390 uquad = (u_int64_t)fs.f_bfree;
2392 uquad = (u_int64_t)fs.f_bavail;
2393 uquad *= fs.f_bsize;
2394 txdr_hyper(uquad, tl);
2395 retnum += NFSX_HYPER;
2397 case NFSATTRBIT_SPACEFREE:
2398 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2399 uquad = (u_int64_t)fs.f_bfree;
2400 uquad *= fs.f_bsize;
2401 txdr_hyper(uquad, tl);
2402 retnum += NFSX_HYPER;
2404 case NFSATTRBIT_SPACETOTAL:
2405 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2406 uquad = (u_int64_t)fs.f_blocks;
2407 uquad *= fs.f_bsize;
2408 txdr_hyper(uquad, tl);
2409 retnum += NFSX_HYPER;
2411 case NFSATTRBIT_SPACEUSED:
2412 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2413 txdr_hyper(vap->va_bytes, tl);
2414 retnum += NFSX_HYPER;
2416 case NFSATTRBIT_TIMEACCESS:
2417 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2418 txdr_nfsv4time(&vap->va_atime, tl);
2419 retnum += NFSX_V4TIME;
2421 case NFSATTRBIT_TIMEACCESSSET:
2422 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2423 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2424 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2425 txdr_nfsv4time(&vap->va_atime, tl);
2426 retnum += NFSX_V4SETTIME;
2428 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2429 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2430 retnum += NFSX_UNSIGNED;
2433 case NFSATTRBIT_TIMEDELTA:
2434 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2435 temptime.tv_sec = 0;
2436 temptime.tv_nsec = 1000000000 / hz;
2437 txdr_nfsv4time(&temptime, tl);
2438 retnum += NFSX_V4TIME;
2440 case NFSATTRBIT_TIMEMETADATA:
2441 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2442 txdr_nfsv4time(&vap->va_ctime, tl);
2443 retnum += NFSX_V4TIME;
2445 case NFSATTRBIT_TIMEMODIFY:
2446 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2447 txdr_nfsv4time(&vap->va_mtime, tl);
2448 retnum += NFSX_V4TIME;
2450 case NFSATTRBIT_TIMEMODIFYSET:
2451 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2452 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2453 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2454 txdr_nfsv4time(&vap->va_mtime, tl);
2455 retnum += NFSX_V4SETTIME;
2457 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2458 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2459 retnum += NFSX_UNSIGNED;
2462 case NFSATTRBIT_MOUNTEDONFILEID:
2463 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2465 uquad = mounted_on_fileno;
2467 uquad = (u_int64_t)vap->va_fileid;
2468 txdr_hyper(uquad, tl);
2469 retnum += NFSX_HYPER;
2472 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2478 *retnump = txdr_unsigned(retnum);
2479 return (retnum + prefixnum);
2483 * Put the attribute bits onto an mbuf list.
2484 * Return the number of bytes of output generated.
2487 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2490 int cnt, i, bytesize;
2492 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2493 if (attrbitp->bits[cnt - 1])
2495 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2496 NFSM_BUILD(tl, u_int32_t *, bytesize);
2497 *tl++ = txdr_unsigned(cnt);
2498 for (i = 0; i < cnt; i++)
2499 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2504 * Convert a uid to a string.
2505 * If the lookup fails, just output the digits.
2507 * cpp - points to a buffer of size NFSV4_SMALLSTR
2508 * (malloc a larger one, as required)
2509 * retlenp - pointer to length to be returned
2512 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2515 struct nfsusrgrp *usrp;
2518 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2523 if (nfsrv_dnsname) {
2525 * Always map nfsrv_defaultuid to "nobody".
2527 if (uid == nfsrv_defaultuid) {
2528 i = nfsrv_dnsnamelen + 7;
2531 if (len > NFSV4_SMALLSTR)
2532 free(cp, M_NFSSTRING);
2533 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2539 NFSBCOPY("nobody@", cp, 7);
2541 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2546 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2547 if (usrp->lug_uid == uid) {
2548 if (usrp->lug_expiry < NFSD_MONOSEC)
2551 * If the name doesn't already have an '@'
2552 * in it, append @domainname to it.
2554 for (i = 0; i < usrp->lug_namelen; i++) {
2555 if (usrp->lug_name[i] == '@') {
2561 i = usrp->lug_namelen;
2563 i = usrp->lug_namelen +
2564 nfsrv_dnsnamelen + 1;
2567 if (len > NFSV4_SMALLSTR)
2568 free(cp, M_NFSSTRING);
2569 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2575 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2576 if (!hasampersand) {
2577 cp += usrp->lug_namelen;
2579 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2581 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2582 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2589 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2591 if (ret == 0 && cnt < 2)
2598 * No match, just return a string of digits.
2602 while (tmp || i == 0) {
2606 len = (i > len) ? len : i;
2610 for (i = 0; i < len; i++) {
2611 *cp-- = '0' + (tmp % 10);
2618 * Convert a string to a uid.
2619 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2621 * If this is called from a client side mount using AUTH_SYS and the
2622 * string is made up entirely of digits, just convert the string to
2626 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2630 char *cp, *endstr, *str0;
2631 struct nfsusrgrp *usrp;
2637 error = NFSERR_BADOWNER;
2640 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2642 tuid = (uid_t)strtoul(str0, &endstr, 10);
2643 if ((endstr - str0) == len &&
2644 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2651 cp = strchr(str0, '@');
2653 i = (int)(cp++ - str0);
2661 * If an '@' is found and the domain name matches, search for the name
2662 * with dns stripped off.
2663 * Mixed case alpahbetics will match for the domain name, but all
2664 * upper case will not.
2666 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2667 (len - 1 - i) == nfsrv_dnsnamelen &&
2668 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2669 len -= (nfsrv_dnsnamelen + 1);
2674 * Check for the special case of "nobody".
2676 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2677 *uidp = nfsrv_defaultuid;
2683 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2684 if (usrp->lug_namelen == len &&
2685 !NFSBCMP(usrp->lug_name, str, len)) {
2686 if (usrp->lug_expiry < NFSD_MONOSEC)
2688 *uidp = usrp->lug_uid;
2689 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2690 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2698 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2700 if (ret == 0 && cnt < 2)
2702 error = NFSERR_BADOWNER;
2710 * Convert a gid to a string.
2711 * gid - the group id
2712 * cpp - points to a buffer of size NFSV4_SMALLSTR
2713 * (malloc a larger one, as required)
2714 * retlenp - pointer to length to be returned
2717 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2720 struct nfsusrgrp *usrp;
2723 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2728 if (nfsrv_dnsname) {
2730 * Always map nfsrv_defaultgid to "nogroup".
2732 if (gid == nfsrv_defaultgid) {
2733 i = nfsrv_dnsnamelen + 8;
2736 if (len > NFSV4_SMALLSTR)
2737 free(cp, M_NFSSTRING);
2738 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2744 NFSBCOPY("nogroup@", cp, 8);
2746 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2751 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2752 if (usrp->lug_gid == gid) {
2753 if (usrp->lug_expiry < NFSD_MONOSEC)
2756 * If the name doesn't already have an '@'
2757 * in it, append @domainname to it.
2759 for (i = 0; i < usrp->lug_namelen; i++) {
2760 if (usrp->lug_name[i] == '@') {
2766 i = usrp->lug_namelen;
2768 i = usrp->lug_namelen +
2769 nfsrv_dnsnamelen + 1;
2772 if (len > NFSV4_SMALLSTR)
2773 free(cp, M_NFSSTRING);
2774 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2780 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2781 if (!hasampersand) {
2782 cp += usrp->lug_namelen;
2784 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2786 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2787 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2794 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2796 if (ret == 0 && cnt < 2)
2803 * No match, just return a string of digits.
2807 while (tmp || i == 0) {
2811 len = (i > len) ? len : i;
2815 for (i = 0; i < len; i++) {
2816 *cp-- = '0' + (tmp % 10);
2823 * Convert a string to a gid.
2824 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2826 * If this is called from a client side mount using AUTH_SYS and the
2827 * string is made up entirely of digits, just convert the string to
2831 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2835 char *cp, *endstr, *str0;
2836 struct nfsusrgrp *usrp;
2842 error = NFSERR_BADOWNER;
2845 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2847 tgid = (gid_t)strtoul(str0, &endstr, 10);
2848 if ((endstr - str0) == len &&
2849 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2856 cp = strchr(str0, '@');
2858 i = (int)(cp++ - str0);
2866 * If an '@' is found and the dns name matches, search for the name
2867 * with the dns stripped off.
2869 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2870 (len - 1 - i) == nfsrv_dnsnamelen &&
2871 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2872 len -= (nfsrv_dnsnamelen + 1);
2877 * Check for the special case of "nogroup".
2879 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2880 *gidp = nfsrv_defaultgid;
2886 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2887 if (usrp->lug_namelen == len &&
2888 !NFSBCMP(usrp->lug_name, str, len)) {
2889 if (usrp->lug_expiry < NFSD_MONOSEC)
2891 *gidp = usrp->lug_gid;
2892 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2893 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2901 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2903 if (ret == 0 && cnt < 2)
2905 error = NFSERR_BADOWNER;
2913 * Cmp len chars, allowing mixed case in the first argument to match lower
2914 * case in the second, but not if the first argument is all upper case.
2915 * Return 0 for a match, 1 otherwise.
2918 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2924 for (i = 0; i < len; i++) {
2925 if (*cp >= 'A' && *cp <= 'Z') {
2926 tmp = *cp++ + ('a' - 'A');
2929 if (tmp >= 'a' && tmp <= 'z')
2942 * Set the port for the nfsuserd.
2945 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2947 struct nfssockreq *rp;
2948 struct sockaddr_in *ad;
2952 if (nfsrv_nfsuserd) {
2960 * Set up the socket record and connect.
2962 rp = &nfsrv_nfsuserdsock;
2963 rp->nr_client = NULL;
2964 rp->nr_sotype = SOCK_DGRAM;
2965 rp->nr_soproto = IPPROTO_UDP;
2966 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2968 NFSSOCKADDRALLOC(rp->nr_nam);
2969 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2970 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2971 ad->sin_family = AF_INET;
2972 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2973 ad->sin_port = port;
2974 rp->nr_prog = RPCPROG_NFSUSERD;
2975 rp->nr_vers = RPCNFSUSERD_VERS;
2976 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2978 NFSSOCKADDRFREE(rp->nr_nam);
2987 * Delete the nfsuserd port.
2990 nfsrv_nfsuserddelport(void)
2994 if (nfsrv_nfsuserd == 0) {
3000 newnfs_disconnect(&nfsrv_nfsuserdsock);
3001 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3005 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3007 * Returns 0 upon success, non-zero otherwise.
3010 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3013 struct nfsrv_descript *nd;
3015 struct nfsrv_descript nfsd;
3020 if (nfsrv_nfsuserd == 0) {
3027 cred = newnfs_getcred();
3028 nd->nd_flag = ND_GSSINITREPLY;
3031 nd->nd_procnum = procnum;
3032 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3033 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3034 if (procnum == RPCNFSUSERD_GETUID)
3035 *tl = txdr_unsigned(uid);
3037 *tl = txdr_unsigned(gid);
3040 (void) nfsm_strtom(nd, name, len);
3042 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3043 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3046 mbuf_freem(nd->nd_mrep);
3047 error = nd->nd_repstat;
3055 * This function is called from the nfssvc(2) system call, to update the
3056 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3059 nfssvc_idname(struct nfsd_idargs *nidp)
3061 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3062 struct nfsuserhashhead *hp;
3067 if (nidp->nid_flag & NFSID_INITIALIZE) {
3068 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3069 M_NFSSTRING, M_WAITOK);
3070 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3073 if (nfsrv_dnsname) {
3075 * Free up all the old stuff and reinitialize hash lists.
3077 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3078 nfsrv_removeuser(usrp);
3080 free(nfsrv_dnsname, M_NFSSTRING);
3081 nfsrv_dnsname = NULL;
3083 TAILQ_INIT(&nfsuserlruhead);
3084 for (i = 0; i < NFSUSERHASHSIZE; i++)
3085 LIST_INIT(&nfsuserhash[i]);
3086 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3087 LIST_INIT(&nfsgrouphash[i]);
3088 for (i = 0; i < NFSUSERHASHSIZE; i++)
3089 LIST_INIT(&nfsusernamehash[i]);
3090 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3091 LIST_INIT(&nfsgroupnamehash[i]);
3094 * Put name in "DNS" string.
3098 nfsrv_dnsnamelen = nidp->nid_namelen;
3099 nfsrv_defaultuid = nidp->nid_uid;
3100 nfsrv_defaultgid = nidp->nid_gid;
3102 nfsrv_usermax = nidp->nid_usermax;
3106 free(cp, M_NFSSTRING);
3111 * malloc the new one now, so any potential sleep occurs before
3112 * manipulation of the lists.
3114 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3115 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3116 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3119 free((caddr_t)newusrp, M_NFSUSERGROUP);
3122 newusrp->lug_namelen = nidp->nid_namelen;
3126 * Delete old entries, as required.
3128 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3129 hp = NFSUSERHASH(nidp->nid_uid);
3130 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3131 if (usrp->lug_uid == nidp->nid_uid)
3132 nfsrv_removeuser(usrp);
3135 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3136 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3137 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3138 if (usrp->lug_namelen == newusrp->lug_namelen &&
3139 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3141 nfsrv_removeuser(usrp);
3144 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3145 hp = NFSGROUPHASH(nidp->nid_gid);
3146 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3147 if (usrp->lug_gid == nidp->nid_gid)
3148 nfsrv_removeuser(usrp);
3151 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3152 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3153 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3154 if (usrp->lug_namelen == newusrp->lug_namelen &&
3155 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3157 nfsrv_removeuser(usrp);
3160 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3161 if (usrp->lug_expiry < NFSD_MONOSEC)
3162 nfsrv_removeuser(usrp);
3164 while (nfsrv_usercnt >= nfsrv_usermax) {
3165 usrp = TAILQ_FIRST(&nfsuserlruhead);
3166 nfsrv_removeuser(usrp);
3170 * Now, we can add the new one.
3172 if (nidp->nid_usertimeout)
3173 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3175 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3176 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3177 newusrp->lug_uid = nidp->nid_uid;
3178 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3180 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3181 newusrp->lug_namelen), newusrp, lug_namehash);
3182 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3184 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3185 newusrp->lug_gid = nidp->nid_gid;
3186 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3188 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3189 newusrp->lug_namelen), newusrp, lug_namehash);
3190 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3193 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3201 * Remove a user/group name element.
3204 nfsrv_removeuser(struct nfsusrgrp *usrp)
3207 NFSNAMEIDREQUIRED();
3208 LIST_REMOVE(usrp, lug_numhash);
3209 LIST_REMOVE(usrp, lug_namehash);
3210 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3212 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3216 * This function scans a byte string and checks for UTF-8 compliance.
3217 * It returns 0 if it conforms and NFSERR_INVAL if not.
3220 nfsrv_checkutf8(u_int8_t *cp, int len)
3222 u_int32_t val = 0x0;
3223 int cnt = 0, gotd = 0, shift = 0;
3225 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3229 * Here are what the variables are used for:
3230 * val - the calculated value of a multibyte char, used to check
3231 * that it was coded with the correct range
3232 * cnt - the number of 10xxxxxx bytes to follow
3233 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3234 * shift - lower order bits of range (ie. "val >> shift" should
3235 * not be 0, in other words, dividing by the lower bound
3236 * of the range should get a non-zero value)
3237 * byte - used to calculate cnt
3241 /* This handles the 10xxxxxx bytes */
3242 if ((*cp & 0xc0) != 0x80 ||
3243 (gotd && (*cp & 0x20))) {
3244 error = NFSERR_INVAL;
3249 val |= (*cp & 0x3f);
3251 if (cnt == 0 && (val >> shift) == 0x0) {
3252 error = NFSERR_INVAL;
3255 } else if (*cp & 0x80) {
3256 /* first byte of multi byte char */
3258 while ((byte & 0x40) && cnt < 6) {
3262 if (cnt == 0 || cnt == 6) {
3263 error = NFSERR_INVAL;
3266 val = (*cp & (0x3f >> cnt));
3267 shift = utf8_shift[cnt - 1];
3268 if (cnt == 2 && val == 0xd)
3269 /* Check for the 0xd800-0xdfff case */
3276 error = NFSERR_INVAL;
3284 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3285 * strings, one with the root path in it and the other with the list of
3286 * locations. The list is in the same format as is found in nfr_refs.
3287 * It is a "," separated list of entries, where each of them is of the
3288 * form <server>:<rootpath>. For example
3289 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3290 * The nilp argument is set to 1 for the special case of a null fs_root
3291 * and an empty server list.
3292 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3293 * number of xdr bytes parsed in sump.
3296 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3297 int *sump, int *nilp)
3300 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3301 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3303 SLIST_ENTRY(list) next;
3307 SLIST_HEAD(, list) head;
3314 * Get the fs_root path and check for the special case of null path
3315 * and 0 length server list.
3317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3318 len = fxdr_unsigned(int, *tl);
3319 if (len < 0 || len > 10240) {
3320 error = NFSERR_BADXDR;
3324 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3326 error = NFSERR_BADXDR;
3330 *sump = 2 * NFSX_UNSIGNED;
3334 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3335 error = nfsrv_mtostr(nd, cp, len);
3337 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3338 cnt = fxdr_unsigned(int, *tl);
3340 error = NFSERR_BADXDR;
3346 * Now, loop through the location list and make up the srvlist.
3348 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3349 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3352 for (i = 0; i < cnt; i++) {
3354 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3355 nsrv = fxdr_unsigned(int, *tl);
3357 error = NFSERR_BADXDR;
3362 * Handle the first server by putting it in the srvstr.
3364 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3365 len = fxdr_unsigned(int, *tl);
3366 if (len <= 0 || len > 1024) {
3367 error = NFSERR_BADXDR;
3370 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3375 error = nfsrv_mtostr(nd, cp3, len);
3381 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3382 for (j = 1; j < nsrv; j++) {
3384 * Yuck, put them in an slist and process them later.
3386 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3387 len = fxdr_unsigned(int, *tl);
3388 if (len <= 0 || len > 1024) {
3389 error = NFSERR_BADXDR;
3392 lsp = (struct list *)malloc(sizeof (struct list)
3393 + len, M_TEMP, M_WAITOK);
3394 error = nfsrv_mtostr(nd, lsp->host, len);
3397 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3399 SLIST_INSERT_HEAD(&head, lsp, next);
3403 * Finally, we can get the path.
3405 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3406 len = fxdr_unsigned(int, *tl);
3407 if (len <= 0 || len > 1024) {
3408 error = NFSERR_BADXDR;
3411 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3412 error = nfsrv_mtostr(nd, cp3, len);
3415 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3420 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3421 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3424 NFSBCOPY(lsp->host, cp3, lsp->len);
3427 NFSBCOPY(str, cp3, stringlen);
3430 siz += (lsp->len + stringlen + 2);
3431 free((caddr_t)lsp, M_TEMP);
3437 NFSEXITCODE2(0, nd);
3441 free(cp, M_NFSSTRING);
3443 free(cp2, M_NFSSTRING);
3444 NFSEXITCODE2(error, nd);
3449 * Make the malloc'd space large enough. This is a pain, but the xdr
3450 * doesn't set an upper bound on the side, so...
3453 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3460 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3461 NFSBCOPY(*cpp, cp, *slenp);
3462 free(*cpp, M_NFSSTRING);
3466 *slenp = siz + 1024;
3470 * Initialize the reply header data structures.
3473 nfsrvd_rephead(struct nfsrv_descript *nd)
3478 * If this is a big reply, use a cluster.
3480 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3481 nfs_bigreply[nd->nd_procnum]) {
3482 NFSMCLGET(mreq, M_WAITOK);
3490 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3491 mbuf_setlen(mreq, 0);
3493 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3494 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3498 * Lock a socket against others.
3499 * Currently used to serialize connect/disconnect attempts.
3502 newnfs_sndlock(int *flagp)
3507 while (*flagp & NFSR_SNDLOCK) {
3508 *flagp |= NFSR_WANTSND;
3511 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3512 PZERO - 1, "nfsndlck", &ts);
3514 *flagp |= NFSR_SNDLOCK;
3520 * Unlock the stream socket for others.
3523 newnfs_sndunlock(int *flagp)
3527 if ((*flagp & NFSR_SNDLOCK) == 0)
3528 panic("nfs sndunlock");
3529 *flagp &= ~NFSR_SNDLOCK;
3530 if (*flagp & NFSR_WANTSND) {
3531 *flagp &= ~NFSR_WANTSND;
3532 wakeup((caddr_t)flagp);
3538 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3541 struct sockaddr_in *sad;
3542 struct sockaddr_in6 *sad6;
3543 struct in_addr saddr;
3544 uint32_t portnum, *tl;
3545 int af = 0, i, j, k;
3546 char addr[64], protocol[5], *cp;
3547 int cantparse = 0, error = 0;
3550 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3551 i = fxdr_unsigned(int, *tl);
3552 if (i >= 3 && i <= 4) {
3553 error = nfsrv_mtostr(nd, protocol, i);
3556 if (strcmp(protocol, "tcp") == 0) {
3559 } else if (strcmp(protocol, "udp") == 0) {
3562 } else if (strcmp(protocol, "tcp6") == 0) {
3565 } else if (strcmp(protocol, "udp6") == 0) {
3573 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3578 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3579 i = fxdr_unsigned(int, *tl);
3581 error = NFSERR_BADXDR;
3583 } else if (cantparse == 0 && i >= 11 && i < 64) {
3585 * The shortest address is 11chars and the longest is < 64.
3587 error = nfsrv_mtostr(nd, addr, i);
3591 /* Find the port# at the end and extract that. */
3595 /* Count back two '.'s from end to get port# field. */
3596 for (j = 0; j < i; j++) {
3606 * The NFSv4 port# is appended as .N.N, where N is
3607 * a decimal # in the range 0-255, just like an inet4
3608 * address. Cheat and use inet_aton(), which will
3609 * return a Class A address and then shift the high
3610 * order 8bits over to convert it to the port#.
3613 if (inet_aton(cp, &saddr) == 1) {
3614 portnum = ntohl(saddr.s_addr);
3615 portv = (uint16_t)((portnum >> 16) |
3621 if (cantparse == 0) {
3622 if (af == AF_INET) {
3623 sad = (struct sockaddr_in *)sa;
3624 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
3625 sad->sin_len = sizeof(*sad);
3626 sad->sin_family = AF_INET;
3627 sad->sin_port = htons(portv);
3631 sad6 = (struct sockaddr_in6 *)sa;
3632 if (inet_pton(af, addr, &sad6->sin6_addr)
3634 sad6->sin6_len = sizeof(*sad6);
3635 sad6->sin6_family = AF_INET6;
3636 sad6->sin6_port = htons(portv);
3643 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3654 * Handle an NFSv4.1 Sequence request for the session.
3657 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
3658 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
3664 if (slotid > maxslot)
3665 return (NFSERR_BADSLOT);
3666 if (seqid == slots[slotid].nfssl_seq) {
3668 if (slots[slotid].nfssl_inprog != 0)
3669 error = NFSERR_DELAY;
3670 else if (slots[slotid].nfssl_reply != NULL) {
3671 *reply = slots[slotid].nfssl_reply;
3672 slots[slotid].nfssl_reply = NULL;
3673 slots[slotid].nfssl_inprog = 1;
3675 error = NFSERR_SEQMISORDERED;
3676 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
3677 m_freem(slots[slotid].nfssl_reply);
3678 slots[slotid].nfssl_reply = NULL;
3679 slots[slotid].nfssl_inprog = 1;
3680 slots[slotid].nfssl_seq++;
3682 error = NFSERR_SEQMISORDERED;
3687 * Cache this reply for the slot.
3690 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep)
3693 slots[slotid].nfssl_reply = rep;
3694 slots[slotid].nfssl_inprog = 0;
3698 * Generate the xdr for an NFSv4.1 Sequence Operation.
3701 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
3702 struct nfsclsession *sep, int dont_replycache)
3704 uint32_t *tl, slotseq = 0;
3705 int i, maxslot, slotpos;
3707 uint8_t sessionid[NFSX_V4SESSIONID];
3709 /* Find an unused slot. */
3712 mtx_lock(&sep->nfsess_mtx);
3715 for (i = 0; i < sep->nfsess_foreslots; i++) {
3716 if ((bitval & sep->nfsess_slots) == 0) {
3718 sep->nfsess_slots |= bitval;
3719 sep->nfsess_slotseq[i]++;
3720 slotseq = sep->nfsess_slotseq[i];
3725 if (slotpos == -1) {
3727 * If a forced dismount is in progress, just return.
3728 * This RPC attempt will fail when it calls
3731 if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
3733 mtx_unlock(&sep->nfsess_mtx);
3736 /* Wake up once/sec, to check for a forced dismount. */
3737 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
3738 PZERO, "nfsclseq", hz);
3740 } while (slotpos == -1);
3741 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
3743 for (i = 0; i < 64; i++) {
3744 if ((bitval & sep->nfsess_slots) != 0)
3748 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
3749 mtx_unlock(&sep->nfsess_mtx);
3750 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
3752 /* Build the Sequence arguments. */
3753 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
3754 bcopy(sessionid, tl, NFSX_V4SESSIONID);
3755 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
3756 nd->nd_slotseq = tl;
3757 *tl++ = txdr_unsigned(slotseq);
3758 *tl++ = txdr_unsigned(slotpos);
3759 *tl++ = txdr_unsigned(maxslot);
3760 if (dont_replycache == 0)
3764 nd->nd_flag |= ND_HASSEQUENCE;
3768 * Free a session slot.
3771 nfsv4_freeslot(struct nfsclsession *sep, int slot)
3778 mtx_lock(&sep->nfsess_mtx);
3779 if ((bitval & sep->nfsess_slots) == 0)
3780 printf("freeing free slot!!\n");
3781 sep->nfsess_slots &= ~bitval;
3782 wakeup(&sep->nfsess_slots);
3783 mtx_unlock(&sep->nfsess_mtx);