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;
68 int nfsd_enable_stringtouid = 0;
73 * This array of structures indicates, for V4:
74 * retfh - which of 3 types of calling args are used
75 * 0 - doesn't change cfh or use a sfh
76 * 1 - replaces cfh with a new one (unless it returns an error status)
77 * 2 - uses cfh and sfh
78 * needscfh - if the op wants a cfh and premtime
79 * 0 - doesn't use a cfh
80 * 1 - uses a cfh, but doesn't want pre-op attributes
81 * 2 - uses a cfh and wants pre-op attributes
82 * savereply - indicates a non-idempotent Op
83 * 0 - not non-idempotent
85 * Ops that are ordered via seqid# are handled separately from these
87 * Define it here, since it is used by both the client and server.
89 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
90 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
91 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
92 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
93 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Access */
94 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Close */
95 { 0, 2, 0, 1, LK_EXCLUSIVE, 1 }, /* Commit */
96 { 1, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Create */
97 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegpurge */
98 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegreturn */
99 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Getattr */
100 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* GetFH */
101 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Link */
102 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lock */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockT */
104 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockU */
105 { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */
106 { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookupp */
107 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* NVerify */
108 { 1, 1, 0, 1, LK_EXCLUSIVE, 1 }, /* Open */
109 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenAttr */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenConfirm */
111 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenDowngrade */
112 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutFH */
113 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutPubFH */
114 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutRootFH */
115 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Read */
116 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Readdir */
117 { 0, 1, 0, 0, LK_SHARED, 1 }, /* ReadLink */
118 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Remove */
119 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Rename */
120 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Renew */
121 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* RestoreFH */
122 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SaveFH */
123 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SecInfo */
124 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Setattr */
125 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientID */
126 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientIDConfirm */
127 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Verify */
128 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Write */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* ReleaseLockOwner */
130 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Backchannel Ctrl */
131 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Bind Conn to Sess */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Exchange ID */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Create Session */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy Session */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Free StateID */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Dir Deleg */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device Info */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device List */
139 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Commit */
140 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Get */
141 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Return */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Secinfo No name */
143 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Sequence */
144 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Set SSV */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Test StateID */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Want Delegation */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy ClientID */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Reclaim Complete */
150 #endif /* !APPLEKEXT */
152 static int ncl_mbuf_mhlen = MHLEN;
153 static int nfsrv_usercnt = 0;
154 static int nfsrv_dnsnamelen;
155 static u_char *nfsrv_dnsname = NULL;
156 static int nfsrv_usermax = 999999999;
157 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
158 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
159 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
160 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
161 static struct nfsuserlruhead nfsuserlruhead;
164 * This static array indicates whether or not the RPC generates a large
165 * reply. This is used by nfs_reply() to decide whether or not an mbuf
166 * cluster should be allocated. (If a cluster is required by an RPC
167 * marked 0 in this array, the code will still work, just not quite as
170 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
171 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,
172 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
174 /* local functions */
175 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
176 static void nfsv4_wanted(struct nfsv4lock *lp);
177 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
178 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
180 static void nfsrv_removeuser(struct nfsusrgrp *usrp);
181 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
183 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
188 * copies mbuf chain to the uio scatter/gather list
191 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
193 char *mbufcp, *uiocp;
200 mbufcp = nd->nd_dpos;
201 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
202 rem = NFSM_RNDUP(siz) - siz;
204 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
208 left = uiop->uio_iov->iov_len;
209 uiocp = uiop->uio_iov->iov_base;
220 mbufcp = NFSMTOD(mp, caddr_t);
222 KASSERT(len > 0, ("len %d", len));
224 xfer = (left > len) ? len : left;
227 if (uiop->uio_iov->iov_op != NULL)
228 (*(uiop->uio_iov->iov_op))
229 (mbufcp, uiocp, xfer);
232 if (uiop->uio_segflg == UIO_SYSSPACE)
233 NFSBCOPY(mbufcp, uiocp, xfer);
235 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
240 uiop->uio_offset += xfer;
241 uiop->uio_resid -= xfer;
243 if (uiop->uio_iov->iov_len <= siz) {
247 uiop->uio_iov->iov_base = (void *)
248 ((char *)uiop->uio_iov->iov_base + uiosiz);
249 uiop->uio_iov->iov_len -= uiosiz;
253 nd->nd_dpos = mbufcp;
257 error = nfsm_advance(nd, rem, len);
263 NFSEXITCODE2(error, nd);
269 * Help break down an mbuf chain by setting the first siz bytes contiguous
270 * pointed to by returned val.
271 * This is used by the macro NFSM_DISSECT for tough
275 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
284 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
286 nd->nd_md = mbuf_next(nd->nd_md);
287 if (nd->nd_md == NULL)
289 left = mbuf_len(nd->nd_md);
290 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
295 } else if (mbuf_next(nd->nd_md) == NULL) {
297 } else if (siz > ncl_mbuf_mhlen) {
298 panic("nfs S too big");
300 MGET(mp2, MT_DATA, how);
303 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
304 mbuf_setnext(nd->nd_md, mp2);
305 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
307 retp = p = NFSMTOD(mp2, caddr_t);
308 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
311 mp2 = mbuf_next(mp2);
312 /* Loop around copying up the siz2 bytes */
316 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
318 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
319 NFSM_DATAP(mp2, xfer);
320 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
325 mp2 = mbuf_next(mp2);
327 mbuf_setlen(nd->nd_md, siz);
329 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
335 * Advance the position in the mbuf chain.
336 * If offs == 0, this is a no-op, but it is simpler to just return from
337 * here than check for offs > 0 for all calls to nfsm_advance.
338 * If left == -1, it should be calculated here.
341 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
348 * A negative offs should be considered a serious problem.
351 panic("nfsrv_advance");
354 * If left == -1, calculate it here.
357 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
361 * Loop around, advancing over the mbuf data.
363 while (offs > left) {
365 nd->nd_md = mbuf_next(nd->nd_md);
366 if (nd->nd_md == NULL) {
370 left = mbuf_len(nd->nd_md);
371 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
381 * Copy a string into mbuf(s).
382 * Return the number of bytes output, including XDR overheads.
385 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
394 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
395 *tl = txdr_unsigned(siz);
396 rem = NFSM_RNDUP(siz) - siz;
397 bytesize = NFSX_UNSIGNED + siz + rem;
400 left = M_TRAILINGSPACE(m2);
403 * Loop around copying the string to mbuf(s).
407 if (siz > ncl_mbuf_mlen)
408 NFSMCLGET(m1, M_WAITOK);
412 mbuf_setnext(m2, m1);
414 cp2 = NFSMTOD(m2, caddr_t);
415 left = M_TRAILINGSPACE(m2);
421 NFSBCOPY(cp, cp2, xfer);
423 mbuf_setlen(m2, mbuf_len(m2) + xfer);
426 if (siz == 0 && rem) {
428 panic("nfsm_strtom");
429 NFSBZERO(cp2 + xfer, rem);
430 mbuf_setlen(m2, mbuf_len(m2) + rem);
434 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
439 * Called once to initialize data structures...
444 static int nfs_inited = 0;
450 newnfs_true = txdr_unsigned(TRUE);
451 newnfs_false = txdr_unsigned(FALSE);
452 newnfs_xdrneg1 = txdr_unsigned(-1);
453 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
456 NFSSETBOOTTIME(nfsboottime);
459 * Initialize reply list and start timer
461 TAILQ_INIT(&nfsd_reqq);
466 * Put a file handle in an mbuf list.
467 * If the size argument == 0, just use the default size.
468 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
469 * Return the number of bytes output, including XDR overhead.
472 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
476 int fullsiz, rem, bytesize = 0;
480 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
482 if (size > NFSX_V2FH)
483 panic("fh size > NFSX_V2FH for NFSv2");
484 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
485 NFSBCOPY(fhp, cp, size);
486 if (size < NFSX_V2FH)
487 NFSBZERO(cp + size, NFSX_V2FH - size);
488 bytesize = NFSX_V2FH;
492 fullsiz = NFSM_RNDUP(size);
493 rem = fullsiz - size;
495 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
496 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
499 bytesize = NFSX_UNSIGNED + fullsiz;
501 (void) nfsm_strtom(nd, fhp, size);
508 * This function compares two net addresses by family and returns TRUE
509 * if they are the same host.
510 * If there is any doubt, return FALSE.
511 * The AF_INET family is handled as a special case so that address mbufs
512 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
515 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
517 struct sockaddr_in *inetaddr;
521 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
522 if (inetaddr->sin_family == AF_INET &&
523 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
529 struct sockaddr_in6 *inetaddr6;
531 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
532 /* XXX - should test sin6_scope_id ? */
533 if (inetaddr6->sin6_family == AF_INET6 &&
534 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
545 * Similar to the above, but takes to NFSSOCKADDR_T args.
548 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
550 struct sockaddr_in *addr1, *addr2;
551 struct sockaddr *inaddr;
553 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
554 switch (inaddr->sa_family) {
556 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
557 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
558 if (addr2->sin_family == AF_INET &&
559 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
565 struct sockaddr_in6 *inet6addr1, *inet6addr2;
567 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
568 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
569 /* XXX - should test sin6_scope_id ? */
570 if (inet6addr2->sin6_family == AF_INET6 &&
571 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
572 &inet6addr2->sin6_addr))
583 * Trim the stuff already dissected off the mbuf list.
586 newnfs_trimleading(nd)
587 struct nfsrv_descript *nd;
593 * First, free up leading mbufs.
595 if (nd->nd_mrep != nd->nd_md) {
597 while (mbuf_next(m) != nd->nd_md) {
598 if (mbuf_next(m) == NULL)
599 panic("nfsm trim leading");
602 mbuf_setnext(m, NULL);
603 mbuf_freem(nd->nd_mrep);
608 * Now, adjust this mbuf, based on nd_dpos.
610 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
611 if (offs == mbuf_len(m)) {
615 panic("nfsm trim leading2");
616 mbuf_setnext(n, NULL);
618 } else if (offs > 0) {
619 mbuf_setlen(m, mbuf_len(m) - offs);
622 panic("nfsm trimleading offs");
625 nd->nd_dpos = NFSMTOD(m, caddr_t);
629 * Trim trailing data off the mbuf list being built.
632 newnfs_trimtrailing(nd, mb, bpos)
633 struct nfsrv_descript *nd;
639 mbuf_freem(mbuf_next(mb));
640 mbuf_setnext(mb, NULL);
642 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
648 * Dissect a file handle on the client.
651 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
658 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
659 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
660 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
667 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
669 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
671 FREE((caddr_t)nfhp, M_NFSFH);
677 NFSEXITCODE2(error, nd);
682 * Break down the nfsv4 acl.
683 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
686 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
687 int *aclsizep, __unused NFSPROC_T *p)
691 int acecnt, error = 0, aceerr = 0, acesize;
697 * Parse out the ace entries and expect them to conform to
698 * what can be supported by R/W/X bits.
700 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
701 aclsize = NFSX_UNSIGNED;
702 acecnt = fxdr_unsigned(int, *tl);
703 if (acecnt > ACL_MAX_ENTRIES)
704 aceerr = NFSERR_ATTRNOTSUPP;
705 if (nfsrv_useacl == 0)
706 aceerr = NFSERR_ATTRNOTSUPP;
707 for (i = 0; i < acecnt; i++) {
709 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
710 &aceerr, &acesize, p);
712 error = nfsrv_skipace(nd, &acesize);
718 aclp->acl_cnt = acecnt;
724 NFSEXITCODE2(error, nd);
729 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
732 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
737 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
738 len = fxdr_unsigned(int, *(tl + 3));
739 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
741 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
742 NFSEXITCODE2(error, nd);
747 * Get attribute bits from an mbuf list.
748 * Returns EBADRPC for a parsing error, 0 otherwise.
749 * If the clearinvalid flag is set, clear the bits not supported.
752 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
759 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
760 cnt = fxdr_unsigned(int, *tl);
762 error = NFSERR_BADXDR;
765 if (cnt > NFSATTRBIT_MAXWORDS)
766 outcnt = NFSATTRBIT_MAXWORDS;
769 NFSZERO_ATTRBIT(attrbitp);
771 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
772 for (i = 0; i < outcnt; i++)
773 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
775 for (i = 0; i < (cnt - outcnt); i++) {
776 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
777 if (retnotsupp != NULL && *tl != 0)
778 *retnotsupp = NFSERR_ATTRNOTSUPP;
781 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
783 NFSEXITCODE2(error, nd);
788 * Get the attributes for V4.
789 * If the compare flag is true, test for any attribute changes,
790 * otherwise return the attribute values.
791 * These attributes cover fields in "struct vattr", "struct statfs",
792 * "struct nfsfsinfo", the file handle and the lease duration.
793 * The value of retcmpp is set to 1 if all attributes are the same,
795 * Returns EBADRPC if it can't be parsed, 0 otherwise.
798 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
799 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
800 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
801 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
802 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
805 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
806 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
807 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
808 nfsattrbit_t attrbits, retattrbits, checkattrbits;
810 struct nfsreferral *refp;
813 struct timespec temptime;
817 u_int32_t freenum = 0, tuint;
818 u_int64_t uquad = 0, thyp, thyp2;
826 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
828 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
834 *retcmpp = retnotsup;
837 * Just set default values to some of the important ones.
842 nap->na_rdev = (NFSDEV_T)0;
843 nap->na_mtime.tv_sec = 0;
844 nap->na_mtime.tv_nsec = 0;
847 nap->na_blocksize = NFS_FABLKSIZE;
850 sbp->f_bsize = NFS_FABLKSIZE;
858 fsp->fs_rtmax = 8192;
859 fsp->fs_rtpref = 8192;
860 fsp->fs_maxname = NFS_MAXNAMLEN;
861 fsp->fs_wtmax = 8192;
862 fsp->fs_wtpref = 8192;
863 fsp->fs_wtmult = NFS_FABLKSIZE;
864 fsp->fs_dtpref = 8192;
865 fsp->fs_maxfilesize = 0xffffffffffffffffull;
866 fsp->fs_timedelta.tv_sec = 0;
867 fsp->fs_timedelta.tv_nsec = 1;
868 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
869 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
872 pc->pc_linkmax = LINK_MAX;
873 pc->pc_namemax = NAME_MAX;
875 pc->pc_chownrestricted = 0;
876 pc->pc_caseinsensitive = 0;
877 pc->pc_casepreserving = 1;
882 * Loop around getting the attributes.
884 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
885 attrsize = fxdr_unsigned(int, *tl);
886 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
887 if (attrsum > attrsize) {
888 error = NFSERR_BADXDR;
891 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
893 case NFSATTRBIT_SUPPORTEDATTRS:
895 if (compare || nap == NULL)
896 error = nfsrv_getattrbits(nd, &retattrbits,
899 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
903 if (compare && !(*retcmpp)) {
904 NFSSETSUPP_ATTRBIT(&checkattrbits);
905 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
907 *retcmpp = NFSERR_NOTSAME;
911 case NFSATTRBIT_TYPE:
912 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
915 if (nap->na_type != nfsv34tov_type(*tl))
916 *retcmpp = NFSERR_NOTSAME;
918 } else if (nap != NULL) {
919 nap->na_type = nfsv34tov_type(*tl);
921 attrsum += NFSX_UNSIGNED;
923 case NFSATTRBIT_FHEXPIRETYPE:
924 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
925 if (compare && !(*retcmpp)) {
926 if (fxdr_unsigned(int, *tl) !=
927 NFSV4FHTYPE_PERSISTENT)
928 *retcmpp = NFSERR_NOTSAME;
930 attrsum += NFSX_UNSIGNED;
932 case NFSATTRBIT_CHANGE:
933 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
936 if (nap->na_filerev != fxdr_hyper(tl))
937 *retcmpp = NFSERR_NOTSAME;
939 } else if (nap != NULL) {
940 nap->na_filerev = fxdr_hyper(tl);
942 attrsum += NFSX_HYPER;
944 case NFSATTRBIT_SIZE:
945 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
948 if (nap->na_size != fxdr_hyper(tl))
949 *retcmpp = NFSERR_NOTSAME;
951 } else if (nap != NULL) {
952 nap->na_size = fxdr_hyper(tl);
954 attrsum += NFSX_HYPER;
956 case NFSATTRBIT_LINKSUPPORT:
957 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
960 if (fsp->fs_properties & NFSV3_FSFLINK) {
961 if (*tl == newnfs_false)
962 *retcmpp = NFSERR_NOTSAME;
964 if (*tl == newnfs_true)
965 *retcmpp = NFSERR_NOTSAME;
968 } else if (fsp != NULL) {
969 if (*tl == newnfs_true)
970 fsp->fs_properties |= NFSV3_FSFLINK;
972 fsp->fs_properties &= ~NFSV3_FSFLINK;
974 attrsum += NFSX_UNSIGNED;
976 case NFSATTRBIT_SYMLINKSUPPORT:
977 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
980 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
981 if (*tl == newnfs_false)
982 *retcmpp = NFSERR_NOTSAME;
984 if (*tl == newnfs_true)
985 *retcmpp = NFSERR_NOTSAME;
988 } else if (fsp != NULL) {
989 if (*tl == newnfs_true)
990 fsp->fs_properties |= NFSV3_FSFSYMLINK;
992 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
994 attrsum += NFSX_UNSIGNED;
996 case NFSATTRBIT_NAMEDATTR:
997 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
998 if (compare && !(*retcmpp)) {
999 if (*tl != newnfs_false)
1000 *retcmpp = NFSERR_NOTSAME;
1002 attrsum += NFSX_UNSIGNED;
1004 case NFSATTRBIT_FSID:
1005 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1006 thyp = fxdr_hyper(tl);
1008 thyp2 = fxdr_hyper(tl);
1010 if (*retcmpp == 0) {
1011 if (thyp != (u_int64_t)
1012 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1013 thyp2 != (u_int64_t)
1014 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1015 *retcmpp = NFSERR_NOTSAME;
1017 } else if (nap != NULL) {
1018 nap->na_filesid[0] = thyp;
1019 nap->na_filesid[1] = thyp2;
1021 attrsum += (4 * NFSX_UNSIGNED);
1023 case NFSATTRBIT_UNIQUEHANDLES:
1024 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1025 if (compare && !(*retcmpp)) {
1026 if (*tl != newnfs_true)
1027 *retcmpp = NFSERR_NOTSAME;
1029 attrsum += NFSX_UNSIGNED;
1031 case NFSATTRBIT_LEASETIME:
1032 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1034 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1036 *retcmpp = NFSERR_NOTSAME;
1037 } else if (leasep != NULL) {
1038 *leasep = fxdr_unsigned(u_int32_t, *tl);
1040 attrsum += NFSX_UNSIGNED;
1042 case NFSATTRBIT_RDATTRERROR:
1043 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1046 *retcmpp = NFSERR_INVAL;
1047 } else if (rderrp != NULL) {
1048 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1050 attrsum += NFSX_UNSIGNED;
1052 case NFSATTRBIT_ACL:
1058 naclp = acl_alloc(M_WAITOK);
1059 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1065 if (aceerr || aclp == NULL ||
1066 nfsrv_compareacl(aclp, naclp))
1067 *retcmpp = NFSERR_NOTSAME;
1070 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1072 *retcmpp = NFSERR_ATTRNOTSUPP;
1076 if (vp != NULL && aclp != NULL)
1077 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1080 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1087 case NFSATTRBIT_ACLSUPPORT:
1088 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1089 if (compare && !(*retcmpp)) {
1091 if (fxdr_unsigned(u_int32_t, *tl) !=
1093 *retcmpp = NFSERR_NOTSAME;
1095 *retcmpp = NFSERR_ATTRNOTSUPP;
1098 attrsum += NFSX_UNSIGNED;
1100 case NFSATTRBIT_ARCHIVE:
1101 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1102 if (compare && !(*retcmpp))
1103 *retcmpp = NFSERR_ATTRNOTSUPP;
1104 attrsum += NFSX_UNSIGNED;
1106 case NFSATTRBIT_CANSETTIME:
1107 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1110 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1111 if (*tl == newnfs_false)
1112 *retcmpp = NFSERR_NOTSAME;
1114 if (*tl == newnfs_true)
1115 *retcmpp = NFSERR_NOTSAME;
1118 } else if (fsp != NULL) {
1119 if (*tl == newnfs_true)
1120 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1122 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1124 attrsum += NFSX_UNSIGNED;
1126 case NFSATTRBIT_CASEINSENSITIVE:
1127 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1130 if (*tl != newnfs_false)
1131 *retcmpp = NFSERR_NOTSAME;
1133 } else if (pc != NULL) {
1134 pc->pc_caseinsensitive =
1135 fxdr_unsigned(u_int32_t, *tl);
1137 attrsum += NFSX_UNSIGNED;
1139 case NFSATTRBIT_CASEPRESERVING:
1140 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1143 if (*tl != newnfs_true)
1144 *retcmpp = NFSERR_NOTSAME;
1146 } else if (pc != NULL) {
1147 pc->pc_casepreserving =
1148 fxdr_unsigned(u_int32_t, *tl);
1150 attrsum += NFSX_UNSIGNED;
1152 case NFSATTRBIT_CHOWNRESTRICTED:
1153 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1156 if (*tl != newnfs_true)
1157 *retcmpp = NFSERR_NOTSAME;
1159 } else if (pc != NULL) {
1160 pc->pc_chownrestricted =
1161 fxdr_unsigned(u_int32_t, *tl);
1163 attrsum += NFSX_UNSIGNED;
1165 case NFSATTRBIT_FILEHANDLE:
1166 error = nfsm_getfh(nd, &tnfhp);
1169 tfhsize = tnfhp->nfh_len;
1172 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1174 *retcmpp = NFSERR_NOTSAME;
1175 FREE((caddr_t)tnfhp, M_NFSFH);
1176 } else if (nfhpp != NULL) {
1179 FREE((caddr_t)tnfhp, M_NFSFH);
1181 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1183 case NFSATTRBIT_FILEID:
1184 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1185 thyp = fxdr_hyper(tl);
1188 if ((u_int64_t)nap->na_fileid != thyp)
1189 *retcmpp = NFSERR_NOTSAME;
1191 } else if (nap != NULL) {
1193 printf("NFSv4 fileid > 32bits\n");
1194 nap->na_fileid = thyp;
1196 attrsum += NFSX_HYPER;
1198 case NFSATTRBIT_FILESAVAIL:
1199 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1202 sfp->sf_afiles != fxdr_hyper(tl))
1203 *retcmpp = NFSERR_NOTSAME;
1204 } else if (sfp != NULL) {
1205 sfp->sf_afiles = fxdr_hyper(tl);
1207 attrsum += NFSX_HYPER;
1209 case NFSATTRBIT_FILESFREE:
1210 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1213 sfp->sf_ffiles != fxdr_hyper(tl))
1214 *retcmpp = NFSERR_NOTSAME;
1215 } else if (sfp != NULL) {
1216 sfp->sf_ffiles = fxdr_hyper(tl);
1218 attrsum += NFSX_HYPER;
1220 case NFSATTRBIT_FILESTOTAL:
1221 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1224 sfp->sf_tfiles != fxdr_hyper(tl))
1225 *retcmpp = NFSERR_NOTSAME;
1226 } else if (sfp != NULL) {
1227 sfp->sf_tfiles = fxdr_hyper(tl);
1229 attrsum += NFSX_HYPER;
1231 case NFSATTRBIT_FSLOCATIONS:
1232 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1236 if (compare && !(*retcmpp)) {
1237 refp = nfsv4root_getreferral(vp, NULL, 0);
1239 if (cp == NULL || cp2 == NULL ||
1241 strcmp(cp2, refp->nfr_srvlist))
1242 *retcmpp = NFSERR_NOTSAME;
1243 } else if (m == 0) {
1244 *retcmpp = NFSERR_NOTSAME;
1248 free(cp, M_NFSSTRING);
1250 free(cp2, M_NFSSTRING);
1252 case NFSATTRBIT_HIDDEN:
1253 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1254 if (compare && !(*retcmpp))
1255 *retcmpp = NFSERR_ATTRNOTSUPP;
1256 attrsum += NFSX_UNSIGNED;
1258 case NFSATTRBIT_HOMOGENEOUS:
1259 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1262 if (fsp->fs_properties &
1263 NFSV3_FSFHOMOGENEOUS) {
1264 if (*tl == newnfs_false)
1265 *retcmpp = NFSERR_NOTSAME;
1267 if (*tl == newnfs_true)
1268 *retcmpp = NFSERR_NOTSAME;
1271 } else if (fsp != NULL) {
1272 if (*tl == newnfs_true)
1273 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1275 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1277 attrsum += NFSX_UNSIGNED;
1279 case NFSATTRBIT_MAXFILESIZE:
1280 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1281 tnfsquad.qval = fxdr_hyper(tl);
1284 tquad = NFSRV_MAXFILESIZE;
1285 if (tquad != tnfsquad.qval)
1286 *retcmpp = NFSERR_NOTSAME;
1288 } else if (fsp != NULL) {
1289 fsp->fs_maxfilesize = tnfsquad.qval;
1291 attrsum += NFSX_HYPER;
1293 case NFSATTRBIT_MAXLINK:
1294 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1297 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1298 *retcmpp = NFSERR_NOTSAME;
1300 } else if (pc != NULL) {
1301 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1303 attrsum += NFSX_UNSIGNED;
1305 case NFSATTRBIT_MAXNAME:
1306 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1309 if (fsp->fs_maxname !=
1310 fxdr_unsigned(u_int32_t, *tl))
1311 *retcmpp = NFSERR_NOTSAME;
1314 tuint = fxdr_unsigned(u_int32_t, *tl);
1316 * Some Linux NFSv4 servers report this
1317 * as 0 or 4billion, so I'll set it to
1318 * NFS_MAXNAMLEN. If a server actually creates
1319 * a name longer than NFS_MAXNAMLEN, it will
1320 * get an error back.
1322 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1323 tuint = NFS_MAXNAMLEN;
1325 fsp->fs_maxname = tuint;
1327 pc->pc_namemax = tuint;
1329 attrsum += NFSX_UNSIGNED;
1331 case NFSATTRBIT_MAXREAD:
1332 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1335 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1336 *(tl + 1)) || *tl != 0)
1337 *retcmpp = NFSERR_NOTSAME;
1339 } else if (fsp != NULL) {
1340 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1341 fsp->fs_rtpref = fsp->fs_rtmax;
1342 fsp->fs_dtpref = fsp->fs_rtpref;
1344 attrsum += NFSX_HYPER;
1346 case NFSATTRBIT_MAXWRITE:
1347 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1350 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1351 *(tl + 1)) || *tl != 0)
1352 *retcmpp = NFSERR_NOTSAME;
1354 } else if (fsp != NULL) {
1355 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1356 fsp->fs_wtpref = fsp->fs_wtmax;
1358 attrsum += NFSX_HYPER;
1360 case NFSATTRBIT_MIMETYPE:
1361 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1362 i = fxdr_unsigned(int, *tl);
1363 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1364 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1367 if (compare && !(*retcmpp))
1368 *retcmpp = NFSERR_ATTRNOTSUPP;
1370 case NFSATTRBIT_MODE:
1371 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1374 if (nap->na_mode != nfstov_mode(*tl))
1375 *retcmpp = NFSERR_NOTSAME;
1377 } else if (nap != NULL) {
1378 nap->na_mode = nfstov_mode(*tl);
1380 attrsum += NFSX_UNSIGNED;
1382 case NFSATTRBIT_NOTRUNC:
1383 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1386 if (*tl != newnfs_true)
1387 *retcmpp = NFSERR_NOTSAME;
1389 } else if (pc != NULL) {
1390 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1392 attrsum += NFSX_UNSIGNED;
1394 case NFSATTRBIT_NUMLINKS:
1395 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1396 tuint = fxdr_unsigned(u_int32_t, *tl);
1399 if ((u_int32_t)nap->na_nlink != tuint)
1400 *retcmpp = NFSERR_NOTSAME;
1402 } else if (nap != NULL) {
1403 nap->na_nlink = tuint;
1405 attrsum += NFSX_UNSIGNED;
1407 case NFSATTRBIT_OWNER:
1408 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1409 j = fxdr_unsigned(int, *tl);
1411 error = NFSERR_BADXDR;
1414 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1415 if (j > NFSV4_SMALLSTR)
1416 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1419 error = nfsrv_mtostr(nd, cp, j);
1421 if (j > NFSV4_SMALLSTR)
1422 free(cp, M_NFSSTRING);
1427 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1429 *retcmpp = NFSERR_NOTSAME;
1431 } else if (nap != NULL) {
1432 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1433 nap->na_uid = nfsrv_defaultuid;
1437 if (j > NFSV4_SMALLSTR)
1438 free(cp, M_NFSSTRING);
1440 case NFSATTRBIT_OWNERGROUP:
1441 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1442 j = fxdr_unsigned(int, *tl);
1444 error = NFSERR_BADXDR;
1447 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1448 if (j > NFSV4_SMALLSTR)
1449 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1452 error = nfsrv_mtostr(nd, cp, j);
1454 if (j > NFSV4_SMALLSTR)
1455 free(cp, M_NFSSTRING);
1460 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1462 *retcmpp = NFSERR_NOTSAME;
1464 } else if (nap != NULL) {
1465 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1466 nap->na_gid = nfsrv_defaultgid;
1470 if (j > NFSV4_SMALLSTR)
1471 free(cp, M_NFSSTRING);
1473 case NFSATTRBIT_QUOTAHARD:
1474 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1476 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1477 freenum = sbp->f_bfree;
1479 freenum = sbp->f_bavail;
1482 * ufs_quotactl() insists that the uid argument
1483 * equal p_ruid for non-root quota access, so
1484 * we'll just make sure that's the case.
1486 savuid = p->p_cred->p_ruid;
1487 p->p_cred->p_ruid = cred->cr_uid;
1488 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1489 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1490 freenum = min(dqb.dqb_bhardlimit, freenum);
1491 p->p_cred->p_ruid = savuid;
1493 uquad = (u_int64_t)freenum;
1494 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1496 if (compare && !(*retcmpp)) {
1497 if (uquad != fxdr_hyper(tl))
1498 *retcmpp = NFSERR_NOTSAME;
1500 attrsum += NFSX_HYPER;
1502 case NFSATTRBIT_QUOTASOFT:
1503 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1505 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1506 freenum = sbp->f_bfree;
1508 freenum = sbp->f_bavail;
1511 * ufs_quotactl() insists that the uid argument
1512 * equal p_ruid for non-root quota access, so
1513 * we'll just make sure that's the case.
1515 savuid = p->p_cred->p_ruid;
1516 p->p_cred->p_ruid = cred->cr_uid;
1517 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1518 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1519 freenum = min(dqb.dqb_bsoftlimit, freenum);
1520 p->p_cred->p_ruid = savuid;
1522 uquad = (u_int64_t)freenum;
1523 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1525 if (compare && !(*retcmpp)) {
1526 if (uquad != fxdr_hyper(tl))
1527 *retcmpp = NFSERR_NOTSAME;
1529 attrsum += NFSX_HYPER;
1531 case NFSATTRBIT_QUOTAUSED:
1532 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1537 * ufs_quotactl() insists that the uid argument
1538 * equal p_ruid for non-root quota access, so
1539 * we'll just make sure that's the case.
1541 savuid = p->p_cred->p_ruid;
1542 p->p_cred->p_ruid = cred->cr_uid;
1543 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1544 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1545 freenum = dqb.dqb_curblocks;
1546 p->p_cred->p_ruid = savuid;
1548 uquad = (u_int64_t)freenum;
1549 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1551 if (compare && !(*retcmpp)) {
1552 if (uquad != fxdr_hyper(tl))
1553 *retcmpp = NFSERR_NOTSAME;
1555 attrsum += NFSX_HYPER;
1557 case NFSATTRBIT_RAWDEV:
1558 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1559 j = fxdr_unsigned(int, *tl++);
1560 k = fxdr_unsigned(int, *tl);
1563 if (nap->na_rdev != NFSMAKEDEV(j, k))
1564 *retcmpp = NFSERR_NOTSAME;
1566 } else if (nap != NULL) {
1567 nap->na_rdev = NFSMAKEDEV(j, k);
1569 attrsum += NFSX_V4SPECDATA;
1571 case NFSATTRBIT_SPACEAVAIL:
1572 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1575 sfp->sf_abytes != fxdr_hyper(tl))
1576 *retcmpp = NFSERR_NOTSAME;
1577 } else if (sfp != NULL) {
1578 sfp->sf_abytes = fxdr_hyper(tl);
1580 attrsum += NFSX_HYPER;
1582 case NFSATTRBIT_SPACEFREE:
1583 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1586 sfp->sf_fbytes != fxdr_hyper(tl))
1587 *retcmpp = NFSERR_NOTSAME;
1588 } else if (sfp != NULL) {
1589 sfp->sf_fbytes = fxdr_hyper(tl);
1591 attrsum += NFSX_HYPER;
1593 case NFSATTRBIT_SPACETOTAL:
1594 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1597 sfp->sf_tbytes != fxdr_hyper(tl))
1598 *retcmpp = NFSERR_NOTSAME;
1599 } else if (sfp != NULL) {
1600 sfp->sf_tbytes = fxdr_hyper(tl);
1602 attrsum += NFSX_HYPER;
1604 case NFSATTRBIT_SPACEUSED:
1605 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1606 thyp = fxdr_hyper(tl);
1609 if ((u_int64_t)nap->na_bytes != thyp)
1610 *retcmpp = NFSERR_NOTSAME;
1612 } else if (nap != NULL) {
1613 nap->na_bytes = thyp;
1615 attrsum += NFSX_HYPER;
1617 case NFSATTRBIT_SYSTEM:
1618 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1619 if (compare && !(*retcmpp))
1620 *retcmpp = NFSERR_ATTRNOTSUPP;
1621 attrsum += NFSX_UNSIGNED;
1623 case NFSATTRBIT_TIMEACCESS:
1624 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1625 fxdr_nfsv4time(tl, &temptime);
1628 if (!NFS_CMPTIME(temptime, nap->na_atime))
1629 *retcmpp = NFSERR_NOTSAME;
1631 } else if (nap != NULL) {
1632 nap->na_atime = temptime;
1634 attrsum += NFSX_V4TIME;
1636 case NFSATTRBIT_TIMEACCESSSET:
1637 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1638 attrsum += NFSX_UNSIGNED;
1639 i = fxdr_unsigned(int, *tl);
1640 if (i == NFSV4SATTRTIME_TOCLIENT) {
1641 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1642 attrsum += NFSX_V4TIME;
1644 if (compare && !(*retcmpp))
1645 *retcmpp = NFSERR_INVAL;
1647 case NFSATTRBIT_TIMEBACKUP:
1648 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1649 if (compare && !(*retcmpp))
1650 *retcmpp = NFSERR_ATTRNOTSUPP;
1651 attrsum += NFSX_V4TIME;
1653 case NFSATTRBIT_TIMECREATE:
1654 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1655 if (compare && !(*retcmpp))
1656 *retcmpp = NFSERR_ATTRNOTSUPP;
1657 attrsum += NFSX_V4TIME;
1659 case NFSATTRBIT_TIMEDELTA:
1660 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1664 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1665 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1666 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1667 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1670 *retcmpp = NFSERR_NOTSAME;
1673 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1676 attrsum += NFSX_V4TIME;
1678 case NFSATTRBIT_TIMEMETADATA:
1679 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1680 fxdr_nfsv4time(tl, &temptime);
1683 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1684 *retcmpp = NFSERR_NOTSAME;
1686 } else if (nap != NULL) {
1687 nap->na_ctime = temptime;
1689 attrsum += NFSX_V4TIME;
1691 case NFSATTRBIT_TIMEMODIFY:
1692 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1693 fxdr_nfsv4time(tl, &temptime);
1696 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1697 *retcmpp = NFSERR_NOTSAME;
1699 } else if (nap != NULL) {
1700 nap->na_mtime = temptime;
1702 attrsum += NFSX_V4TIME;
1704 case NFSATTRBIT_TIMEMODIFYSET:
1705 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1706 attrsum += NFSX_UNSIGNED;
1707 i = fxdr_unsigned(int, *tl);
1708 if (i == NFSV4SATTRTIME_TOCLIENT) {
1709 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1710 attrsum += NFSX_V4TIME;
1712 if (compare && !(*retcmpp))
1713 *retcmpp = NFSERR_INVAL;
1715 case NFSATTRBIT_MOUNTEDONFILEID:
1716 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1717 thyp = fxdr_hyper(tl);
1721 *retcmpp = NFSERR_NOTSAME;
1723 if (!vp || !nfsrv_atroot(vp, &fid))
1724 fid = nap->na_fileid;
1725 if ((u_int64_t)fid != thyp)
1726 *retcmpp = NFSERR_NOTSAME;
1729 } else if (nap != NULL) {
1731 printf("NFSv4 mounted on fileid > 32bits\n");
1732 nap->na_mntonfileno = thyp;
1734 attrsum += NFSX_HYPER;
1737 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1739 if (compare && !(*retcmpp))
1740 *retcmpp = NFSERR_ATTRNOTSUPP;
1742 * and get out of the loop, since we can't parse
1743 * the unknown attrbute data.
1745 bitpos = NFSATTRBIT_MAX;
1751 * some clients pad the attrlist, so we need to skip over the
1754 if (attrsum > attrsize) {
1755 error = NFSERR_BADXDR;
1757 attrsize = NFSM_RNDUP(attrsize);
1758 if (attrsum < attrsize)
1759 error = nfsm_advance(nd, attrsize - attrsum, -1);
1762 NFSEXITCODE2(error, nd);
1767 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1768 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1769 * The first argument is a pointer to an nfsv4lock structure.
1770 * The second argument is 1 iff a blocking lock is wanted.
1771 * If this argument is 0, the call waits until no thread either wants nor
1772 * holds an exclusive lock.
1773 * It returns 1 if the lock was acquired, 0 otherwise.
1774 * If several processes call this function concurrently wanting the exclusive
1775 * lock, one will get the lock and the rest will return without getting the
1776 * lock. (If the caller must have the lock, it simply calls this function in a
1777 * loop until the function returns 1 to indicate the lock was acquired.)
1778 * Any usecnt must be decremented by calling nfsv4_relref() before
1779 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1780 * be called in a loop.
1781 * The isleptp argument is set to indicate if the call slept, iff not NULL
1782 * and the mp argument indicates to check for a forced dismount, iff not
1786 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1787 void *mutex, struct mount *mp)
1793 * If a lock is wanted, loop around until the lock is acquired by
1794 * someone and then released. If I want the lock, try to acquire it.
1795 * For a lock to be issued, no lock must be in force and the usecnt
1799 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1800 lp->nfslock_usecnt == 0) {
1801 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1802 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1805 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1807 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1808 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1809 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1812 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1815 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1816 PZERO - 1, "nfsv4lck", NULL);
1817 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1818 lp->nfslock_usecnt == 0) {
1819 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1820 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1828 * Release the lock acquired by nfsv4_lock().
1829 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1830 * incremented, as well.
1833 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1836 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1838 lp->nfslock_usecnt++;
1843 * Release a reference cnt.
1846 nfsv4_relref(struct nfsv4lock *lp)
1849 if (lp->nfslock_usecnt <= 0)
1850 panic("nfsv4root ref cnt");
1851 lp->nfslock_usecnt--;
1852 if (lp->nfslock_usecnt == 0)
1857 * Get a reference cnt.
1858 * This function will wait for any exclusive lock to be released, but will
1859 * not wait for threads that want the exclusive lock. If priority needs
1860 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1861 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1862 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1863 * return without getting a refcnt for that case.
1866 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1874 * Wait for a lock held.
1876 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1877 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1879 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1882 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1883 PZERO - 1, "nfsv4gr", NULL);
1885 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1888 lp->nfslock_usecnt++;
1892 * Get a reference as above, but return failure instead of sleeping if
1893 * an exclusive lock is held.
1896 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1899 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1902 lp->nfslock_usecnt++;
1907 * Test for a lock. Return 1 if locked, 0 otherwise.
1910 nfsv4_testlock(struct nfsv4lock *lp)
1913 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1914 lp->nfslock_usecnt == 0)
1920 * Wake up anyone sleeping, waiting for this lock.
1923 nfsv4_wanted(struct nfsv4lock *lp)
1926 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1927 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1928 wakeup((caddr_t)&lp->nfslock_lock);
1933 * Copy a string from an mbuf list into a character array.
1934 * Return EBADRPC if there is an mbuf error,
1938 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1947 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1948 rem = NFSM_RNDUP(siz) - siz;
1954 NFSBCOPY(cp, str, xfer);
1963 cp = NFSMTOD(mp, caddr_t);
1975 error = nfsm_advance(nd, rem, len);
1981 NFSEXITCODE2(error, nd);
1986 * Fill in the attributes as marked by the bitmap (V4).
1989 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
1990 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
1991 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
1992 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1994 int bitpos, retnum = 0;
1996 int siz, prefixnum, error;
1997 u_char *cp, namestr[NFSV4_SMALLSTR];
1998 nfsattrbit_t attrbits, retbits;
1999 nfsattrbit_t *retbitp = &retbits;
2000 u_int32_t freenum, *retnump;
2003 struct nfsfsinfo fsinf;
2004 struct timespec temptime;
2005 NFSACL_T *aclp, *naclp = NULL;
2012 * First, set the bits that can be filled and get fsinfo.
2014 NFSSET_ATTRBIT(retbitp, attrbitp);
2016 * If both p and cred are NULL, it is a client side setattr call.
2017 * If both p and cred are not NULL, it is a server side reply call.
2018 * If p is not NULL and cred is NULL, it is a client side callback
2021 if (p == NULL && cred == NULL) {
2022 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2025 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2026 naclp = acl_alloc(M_WAITOK);
2029 nfsvno_getfs(&fsinf, isdgram);
2032 * Get the VFS_STATFS(), since some attributes need them.
2034 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2035 error = VFS_STATFS(mp, &fs);
2038 nd->nd_repstat = NFSERR_ACCES;
2041 NFSCLRSTATFS_ATTRBIT(retbitp);
2047 * And the NFSv4 ACL...
2049 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2050 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2051 supports_nfsv4acls == 0))) {
2052 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2054 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2055 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2056 supports_nfsv4acls == 0)) {
2057 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2058 } else if (naclp != NULL) {
2059 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2060 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2062 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2064 NFSVOPUNLOCK(vp, 0);
2066 error = NFSERR_PERM;
2069 nd->nd_repstat = NFSERR_ACCES;
2072 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2077 * Put out the attribute bitmap for the ones being filled in
2078 * and get the field for the number of attributes returned.
2080 prefixnum = nfsrv_putattrbit(nd, retbitp);
2081 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2082 prefixnum += NFSX_UNSIGNED;
2085 * Now, loop around filling in the attributes for each bit set.
2087 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2088 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2090 case NFSATTRBIT_SUPPORTEDATTRS:
2091 NFSSETSUPP_ATTRBIT(&attrbits);
2092 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2093 && supports_nfsv4acls == 0)) {
2094 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2095 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2097 retnum += nfsrv_putattrbit(nd, &attrbits);
2099 case NFSATTRBIT_TYPE:
2100 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2101 *tl = vtonfsv34_type(vap->va_type);
2102 retnum += NFSX_UNSIGNED;
2104 case NFSATTRBIT_FHEXPIRETYPE:
2105 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2106 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2107 retnum += NFSX_UNSIGNED;
2109 case NFSATTRBIT_CHANGE:
2110 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2111 txdr_hyper(vap->va_filerev, tl);
2112 retnum += NFSX_HYPER;
2114 case NFSATTRBIT_SIZE:
2115 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2116 txdr_hyper(vap->va_size, tl);
2117 retnum += NFSX_HYPER;
2119 case NFSATTRBIT_LINKSUPPORT:
2120 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2121 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2125 retnum += NFSX_UNSIGNED;
2127 case NFSATTRBIT_SYMLINKSUPPORT:
2128 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2129 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2133 retnum += NFSX_UNSIGNED;
2135 case NFSATTRBIT_NAMEDATTR:
2136 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2138 retnum += NFSX_UNSIGNED;
2140 case NFSATTRBIT_FSID:
2141 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2143 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2145 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2146 retnum += NFSX_V4FSID;
2148 case NFSATTRBIT_UNIQUEHANDLES:
2149 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2151 retnum += NFSX_UNSIGNED;
2153 case NFSATTRBIT_LEASETIME:
2154 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2155 *tl = txdr_unsigned(nfsrv_lease);
2156 retnum += NFSX_UNSIGNED;
2158 case NFSATTRBIT_RDATTRERROR:
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2160 *tl = txdr_unsigned(rderror);
2161 retnum += NFSX_UNSIGNED;
2164 * Recommended Attributes. (Only the supported ones.)
2166 case NFSATTRBIT_ACL:
2167 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2169 case NFSATTRBIT_ACLSUPPORT:
2170 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2171 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2172 retnum += NFSX_UNSIGNED;
2174 case NFSATTRBIT_CANSETTIME:
2175 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2176 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2180 retnum += NFSX_UNSIGNED;
2182 case NFSATTRBIT_CASEINSENSITIVE:
2183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2185 retnum += NFSX_UNSIGNED;
2187 case NFSATTRBIT_CASEPRESERVING:
2188 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2190 retnum += NFSX_UNSIGNED;
2192 case NFSATTRBIT_CHOWNRESTRICTED:
2193 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2195 retnum += NFSX_UNSIGNED;
2197 case NFSATTRBIT_FILEHANDLE:
2198 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2200 case NFSATTRBIT_FILEID:
2201 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2203 *tl = txdr_unsigned(vap->va_fileid);
2204 retnum += NFSX_HYPER;
2206 case NFSATTRBIT_FILESAVAIL:
2208 * Check quota and use min(quota, f_ffree).
2210 freenum = fs.f_ffree;
2213 * ufs_quotactl() insists that the uid argument
2214 * equal p_ruid for non-root quota access, so
2215 * we'll just make sure that's the case.
2217 savuid = p->p_cred->p_ruid;
2218 p->p_cred->p_ruid = cred->cr_uid;
2219 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2220 cred->cr_uid, (caddr_t)&dqb))
2221 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2223 p->p_cred->p_ruid = savuid;
2225 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2227 *tl = txdr_unsigned(freenum);
2228 retnum += NFSX_HYPER;
2230 case NFSATTRBIT_FILESFREE:
2231 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2233 *tl = txdr_unsigned(fs.f_ffree);
2234 retnum += NFSX_HYPER;
2236 case NFSATTRBIT_FILESTOTAL:
2237 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2239 *tl = txdr_unsigned(fs.f_files);
2240 retnum += NFSX_HYPER;
2242 case NFSATTRBIT_FSLOCATIONS:
2243 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2246 retnum += 2 * NFSX_UNSIGNED;
2248 case NFSATTRBIT_HOMOGENEOUS:
2249 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2250 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2254 retnum += NFSX_UNSIGNED;
2256 case NFSATTRBIT_MAXFILESIZE:
2257 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2258 uquad = NFSRV_MAXFILESIZE;
2259 txdr_hyper(uquad, tl);
2260 retnum += NFSX_HYPER;
2262 case NFSATTRBIT_MAXLINK:
2263 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2264 *tl = txdr_unsigned(LINK_MAX);
2265 retnum += NFSX_UNSIGNED;
2267 case NFSATTRBIT_MAXNAME:
2268 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2269 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2270 retnum += NFSX_UNSIGNED;
2272 case NFSATTRBIT_MAXREAD:
2273 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2275 *tl = txdr_unsigned(fsinf.fs_rtmax);
2276 retnum += NFSX_HYPER;
2278 case NFSATTRBIT_MAXWRITE:
2279 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2281 *tl = txdr_unsigned(fsinf.fs_wtmax);
2282 retnum += NFSX_HYPER;
2284 case NFSATTRBIT_MODE:
2285 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2286 *tl = vtonfsv34_mode(vap->va_mode);
2287 retnum += NFSX_UNSIGNED;
2289 case NFSATTRBIT_NOTRUNC:
2290 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2292 retnum += NFSX_UNSIGNED;
2294 case NFSATTRBIT_NUMLINKS:
2295 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2296 *tl = txdr_unsigned(vap->va_nlink);
2297 retnum += NFSX_UNSIGNED;
2299 case NFSATTRBIT_OWNER:
2301 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2302 retnum += nfsm_strtom(nd, cp, siz);
2304 free(cp, M_NFSSTRING);
2306 case NFSATTRBIT_OWNERGROUP:
2308 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2309 retnum += nfsm_strtom(nd, cp, siz);
2311 free(cp, M_NFSSTRING);
2313 case NFSATTRBIT_QUOTAHARD:
2314 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2315 freenum = fs.f_bfree;
2317 freenum = fs.f_bavail;
2320 * ufs_quotactl() insists that the uid argument
2321 * equal p_ruid for non-root quota access, so
2322 * we'll just make sure that's the case.
2324 savuid = p->p_cred->p_ruid;
2325 p->p_cred->p_ruid = cred->cr_uid;
2326 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2327 cred->cr_uid, (caddr_t)&dqb))
2328 freenum = min(dqb.dqb_bhardlimit, freenum);
2329 p->p_cred->p_ruid = savuid;
2331 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2332 uquad = (u_int64_t)freenum;
2333 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2334 txdr_hyper(uquad, tl);
2335 retnum += NFSX_HYPER;
2337 case NFSATTRBIT_QUOTASOFT:
2338 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2339 freenum = fs.f_bfree;
2341 freenum = fs.f_bavail;
2344 * ufs_quotactl() insists that the uid argument
2345 * equal p_ruid for non-root quota access, so
2346 * we'll just make sure that's the case.
2348 savuid = p->p_cred->p_ruid;
2349 p->p_cred->p_ruid = cred->cr_uid;
2350 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2351 cred->cr_uid, (caddr_t)&dqb))
2352 freenum = min(dqb.dqb_bsoftlimit, freenum);
2353 p->p_cred->p_ruid = savuid;
2355 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2356 uquad = (u_int64_t)freenum;
2357 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2358 txdr_hyper(uquad, tl);
2359 retnum += NFSX_HYPER;
2361 case NFSATTRBIT_QUOTAUSED:
2365 * ufs_quotactl() insists that the uid argument
2366 * equal p_ruid for non-root quota access, so
2367 * we'll just make sure that's the case.
2369 savuid = p->p_cred->p_ruid;
2370 p->p_cred->p_ruid = cred->cr_uid;
2371 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2372 cred->cr_uid, (caddr_t)&dqb))
2373 freenum = dqb.dqb_curblocks;
2374 p->p_cred->p_ruid = savuid;
2376 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2377 uquad = (u_int64_t)freenum;
2378 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2379 txdr_hyper(uquad, tl);
2380 retnum += NFSX_HYPER;
2382 case NFSATTRBIT_RAWDEV:
2383 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2384 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2385 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2386 retnum += NFSX_V4SPECDATA;
2388 case NFSATTRBIT_SPACEAVAIL:
2389 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2390 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2391 uquad = (u_int64_t)fs.f_bfree;
2393 uquad = (u_int64_t)fs.f_bavail;
2394 uquad *= fs.f_bsize;
2395 txdr_hyper(uquad, tl);
2396 retnum += NFSX_HYPER;
2398 case NFSATTRBIT_SPACEFREE:
2399 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2400 uquad = (u_int64_t)fs.f_bfree;
2401 uquad *= fs.f_bsize;
2402 txdr_hyper(uquad, tl);
2403 retnum += NFSX_HYPER;
2405 case NFSATTRBIT_SPACETOTAL:
2406 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2407 uquad = (u_int64_t)fs.f_blocks;
2408 uquad *= fs.f_bsize;
2409 txdr_hyper(uquad, tl);
2410 retnum += NFSX_HYPER;
2412 case NFSATTRBIT_SPACEUSED:
2413 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2414 txdr_hyper(vap->va_bytes, tl);
2415 retnum += NFSX_HYPER;
2417 case NFSATTRBIT_TIMEACCESS:
2418 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2419 txdr_nfsv4time(&vap->va_atime, tl);
2420 retnum += NFSX_V4TIME;
2422 case NFSATTRBIT_TIMEACCESSSET:
2423 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2424 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2425 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2426 txdr_nfsv4time(&vap->va_atime, tl);
2427 retnum += NFSX_V4SETTIME;
2429 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2430 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2431 retnum += NFSX_UNSIGNED;
2434 case NFSATTRBIT_TIMEDELTA:
2435 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2436 temptime.tv_sec = 0;
2437 temptime.tv_nsec = 1000000000 / hz;
2438 txdr_nfsv4time(&temptime, tl);
2439 retnum += NFSX_V4TIME;
2441 case NFSATTRBIT_TIMEMETADATA:
2442 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2443 txdr_nfsv4time(&vap->va_ctime, tl);
2444 retnum += NFSX_V4TIME;
2446 case NFSATTRBIT_TIMEMODIFY:
2447 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2448 txdr_nfsv4time(&vap->va_mtime, tl);
2449 retnum += NFSX_V4TIME;
2451 case NFSATTRBIT_TIMEMODIFYSET:
2452 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2453 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2454 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2455 txdr_nfsv4time(&vap->va_mtime, tl);
2456 retnum += NFSX_V4SETTIME;
2458 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2459 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2460 retnum += NFSX_UNSIGNED;
2463 case NFSATTRBIT_MOUNTEDONFILEID:
2464 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2466 uquad = mounted_on_fileno;
2468 uquad = (u_int64_t)vap->va_fileid;
2469 txdr_hyper(uquad, tl);
2470 retnum += NFSX_HYPER;
2473 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2479 *retnump = txdr_unsigned(retnum);
2480 return (retnum + prefixnum);
2484 * Put the attribute bits onto an mbuf list.
2485 * Return the number of bytes of output generated.
2488 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2491 int cnt, i, bytesize;
2493 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2494 if (attrbitp->bits[cnt - 1])
2496 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2497 NFSM_BUILD(tl, u_int32_t *, bytesize);
2498 *tl++ = txdr_unsigned(cnt);
2499 for (i = 0; i < cnt; i++)
2500 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2505 * Convert a uid to a string.
2506 * If the lookup fails, just output the digits.
2508 * cpp - points to a buffer of size NFSV4_SMALLSTR
2509 * (malloc a larger one, as required)
2510 * retlenp - pointer to length to be returned
2513 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2516 struct nfsusrgrp *usrp;
2519 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2524 if (nfsrv_dnsname) {
2526 * Always map nfsrv_defaultuid to "nobody".
2528 if (uid == nfsrv_defaultuid) {
2529 i = nfsrv_dnsnamelen + 7;
2532 if (len > NFSV4_SMALLSTR)
2533 free(cp, M_NFSSTRING);
2534 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2540 NFSBCOPY("nobody@", cp, 7);
2542 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2547 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2548 if (usrp->lug_uid == uid) {
2549 if (usrp->lug_expiry < NFSD_MONOSEC)
2552 * If the name doesn't already have an '@'
2553 * in it, append @domainname to it.
2555 for (i = 0; i < usrp->lug_namelen; i++) {
2556 if (usrp->lug_name[i] == '@') {
2562 i = usrp->lug_namelen;
2564 i = usrp->lug_namelen +
2565 nfsrv_dnsnamelen + 1;
2568 if (len > NFSV4_SMALLSTR)
2569 free(cp, M_NFSSTRING);
2570 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2576 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2577 if (!hasampersand) {
2578 cp += usrp->lug_namelen;
2580 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2582 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2583 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2590 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2592 if (ret == 0 && cnt < 2)
2599 * No match, just return a string of digits.
2603 while (tmp || i == 0) {
2607 len = (i > len) ? len : i;
2611 for (i = 0; i < len; i++) {
2612 *cp-- = '0' + (tmp % 10);
2619 * Convert a string to a uid.
2620 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2622 * If this is called from a client side mount using AUTH_SYS and the
2623 * string is made up entirely of digits, just convert the string to
2627 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2631 char *cp, *endstr, *str0;
2632 struct nfsusrgrp *usrp;
2638 error = NFSERR_BADOWNER;
2641 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2643 tuid = (uid_t)strtoul(str0, &endstr, 10);
2644 if ((endstr - str0) == len) {
2645 /* A numeric string. */
2646 if ((nd->nd_flag & ND_KERBV) == 0 &&
2647 ((nd->nd_flag & ND_NFSCL) != 0 ||
2648 nfsd_enable_stringtouid != 0))
2651 error = NFSERR_BADOWNER;
2657 cp = strchr(str0, '@');
2659 i = (int)(cp++ - str0);
2667 * If an '@' is found and the domain name matches, search for the name
2668 * with dns stripped off.
2669 * Mixed case alpahbetics will match for the domain name, but all
2670 * upper case will not.
2672 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2673 (len - 1 - i) == nfsrv_dnsnamelen &&
2674 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2675 len -= (nfsrv_dnsnamelen + 1);
2680 * Check for the special case of "nobody".
2682 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2683 *uidp = nfsrv_defaultuid;
2689 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2690 if (usrp->lug_namelen == len &&
2691 !NFSBCMP(usrp->lug_name, str, len)) {
2692 if (usrp->lug_expiry < NFSD_MONOSEC)
2694 *uidp = usrp->lug_uid;
2695 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2696 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2704 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2706 if (ret == 0 && cnt < 2)
2708 error = NFSERR_BADOWNER;
2716 * Convert a gid to a string.
2717 * gid - the group id
2718 * cpp - points to a buffer of size NFSV4_SMALLSTR
2719 * (malloc a larger one, as required)
2720 * retlenp - pointer to length to be returned
2723 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2726 struct nfsusrgrp *usrp;
2729 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2734 if (nfsrv_dnsname) {
2736 * Always map nfsrv_defaultgid to "nogroup".
2738 if (gid == nfsrv_defaultgid) {
2739 i = nfsrv_dnsnamelen + 8;
2742 if (len > NFSV4_SMALLSTR)
2743 free(cp, M_NFSSTRING);
2744 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2750 NFSBCOPY("nogroup@", cp, 8);
2752 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2757 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2758 if (usrp->lug_gid == gid) {
2759 if (usrp->lug_expiry < NFSD_MONOSEC)
2762 * If the name doesn't already have an '@'
2763 * in it, append @domainname to it.
2765 for (i = 0; i < usrp->lug_namelen; i++) {
2766 if (usrp->lug_name[i] == '@') {
2772 i = usrp->lug_namelen;
2774 i = usrp->lug_namelen +
2775 nfsrv_dnsnamelen + 1;
2778 if (len > NFSV4_SMALLSTR)
2779 free(cp, M_NFSSTRING);
2780 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2786 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2787 if (!hasampersand) {
2788 cp += usrp->lug_namelen;
2790 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2792 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2793 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2800 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2802 if (ret == 0 && cnt < 2)
2809 * No match, just return a string of digits.
2813 while (tmp || i == 0) {
2817 len = (i > len) ? len : i;
2821 for (i = 0; i < len; i++) {
2822 *cp-- = '0' + (tmp % 10);
2829 * Convert a string to a gid.
2830 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2832 * If this is called from a client side mount using AUTH_SYS and the
2833 * string is made up entirely of digits, just convert the string to
2837 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2841 char *cp, *endstr, *str0;
2842 struct nfsusrgrp *usrp;
2848 error = NFSERR_BADOWNER;
2851 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2853 tgid = (gid_t)strtoul(str0, &endstr, 10);
2854 if ((endstr - str0) == len) {
2855 /* A numeric string. */
2856 if ((nd->nd_flag & ND_KERBV) == 0 &&
2857 ((nd->nd_flag & ND_NFSCL) != 0 ||
2858 nfsd_enable_stringtouid != 0))
2861 error = NFSERR_BADOWNER;
2867 cp = strchr(str0, '@');
2869 i = (int)(cp++ - str0);
2877 * If an '@' is found and the dns name matches, search for the name
2878 * with the dns stripped off.
2880 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2881 (len - 1 - i) == nfsrv_dnsnamelen &&
2882 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2883 len -= (nfsrv_dnsnamelen + 1);
2888 * Check for the special case of "nogroup".
2890 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2891 *gidp = nfsrv_defaultgid;
2897 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2898 if (usrp->lug_namelen == len &&
2899 !NFSBCMP(usrp->lug_name, str, len)) {
2900 if (usrp->lug_expiry < NFSD_MONOSEC)
2902 *gidp = usrp->lug_gid;
2903 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2904 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2912 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2914 if (ret == 0 && cnt < 2)
2916 error = NFSERR_BADOWNER;
2924 * Cmp len chars, allowing mixed case in the first argument to match lower
2925 * case in the second, but not if the first argument is all upper case.
2926 * Return 0 for a match, 1 otherwise.
2929 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2935 for (i = 0; i < len; i++) {
2936 if (*cp >= 'A' && *cp <= 'Z') {
2937 tmp = *cp++ + ('a' - 'A');
2940 if (tmp >= 'a' && tmp <= 'z')
2953 * Set the port for the nfsuserd.
2956 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2958 struct nfssockreq *rp;
2959 struct sockaddr_in *ad;
2963 if (nfsrv_nfsuserd) {
2971 * Set up the socket record and connect.
2973 rp = &nfsrv_nfsuserdsock;
2974 rp->nr_client = NULL;
2975 rp->nr_sotype = SOCK_DGRAM;
2976 rp->nr_soproto = IPPROTO_UDP;
2977 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2979 NFSSOCKADDRALLOC(rp->nr_nam);
2980 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2981 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2982 ad->sin_family = AF_INET;
2983 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2984 ad->sin_port = port;
2985 rp->nr_prog = RPCPROG_NFSUSERD;
2986 rp->nr_vers = RPCNFSUSERD_VERS;
2987 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2989 NFSSOCKADDRFREE(rp->nr_nam);
2998 * Delete the nfsuserd port.
3001 nfsrv_nfsuserddelport(void)
3005 if (nfsrv_nfsuserd == 0) {
3011 newnfs_disconnect(&nfsrv_nfsuserdsock);
3012 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3016 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3018 * Returns 0 upon success, non-zero otherwise.
3021 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3024 struct nfsrv_descript *nd;
3026 struct nfsrv_descript nfsd;
3031 if (nfsrv_nfsuserd == 0) {
3038 cred = newnfs_getcred();
3039 nd->nd_flag = ND_GSSINITREPLY;
3042 nd->nd_procnum = procnum;
3043 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3044 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3045 if (procnum == RPCNFSUSERD_GETUID)
3046 *tl = txdr_unsigned(uid);
3048 *tl = txdr_unsigned(gid);
3051 (void) nfsm_strtom(nd, name, len);
3053 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3054 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3057 mbuf_freem(nd->nd_mrep);
3058 error = nd->nd_repstat;
3066 * This function is called from the nfssvc(2) system call, to update the
3067 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3070 nfssvc_idname(struct nfsd_idargs *nidp)
3072 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3073 struct nfsuserhashhead *hp;
3078 if (nidp->nid_flag & NFSID_INITIALIZE) {
3079 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3080 M_NFSSTRING, M_WAITOK);
3081 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3084 if (nfsrv_dnsname) {
3086 * Free up all the old stuff and reinitialize hash lists.
3088 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3089 nfsrv_removeuser(usrp);
3091 free(nfsrv_dnsname, M_NFSSTRING);
3092 nfsrv_dnsname = NULL;
3094 TAILQ_INIT(&nfsuserlruhead);
3095 for (i = 0; i < NFSUSERHASHSIZE; i++)
3096 LIST_INIT(&nfsuserhash[i]);
3097 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3098 LIST_INIT(&nfsgrouphash[i]);
3099 for (i = 0; i < NFSUSERHASHSIZE; i++)
3100 LIST_INIT(&nfsusernamehash[i]);
3101 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3102 LIST_INIT(&nfsgroupnamehash[i]);
3105 * Put name in "DNS" string.
3109 nfsrv_dnsnamelen = nidp->nid_namelen;
3110 nfsrv_defaultuid = nidp->nid_uid;
3111 nfsrv_defaultgid = nidp->nid_gid;
3113 nfsrv_usermax = nidp->nid_usermax;
3117 free(cp, M_NFSSTRING);
3122 * malloc the new one now, so any potential sleep occurs before
3123 * manipulation of the lists.
3125 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3126 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3127 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3130 free((caddr_t)newusrp, M_NFSUSERGROUP);
3133 newusrp->lug_namelen = nidp->nid_namelen;
3137 * Delete old entries, as required.
3139 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3140 hp = NFSUSERHASH(nidp->nid_uid);
3141 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3142 if (usrp->lug_uid == nidp->nid_uid)
3143 nfsrv_removeuser(usrp);
3146 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3147 hp = NFSUSERNAMEHASH(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 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3156 hp = NFSGROUPHASH(nidp->nid_gid);
3157 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3158 if (usrp->lug_gid == nidp->nid_gid)
3159 nfsrv_removeuser(usrp);
3162 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3163 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3164 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3165 if (usrp->lug_namelen == newusrp->lug_namelen &&
3166 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3168 nfsrv_removeuser(usrp);
3171 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3172 if (usrp->lug_expiry < NFSD_MONOSEC)
3173 nfsrv_removeuser(usrp);
3175 while (nfsrv_usercnt >= nfsrv_usermax) {
3176 usrp = TAILQ_FIRST(&nfsuserlruhead);
3177 nfsrv_removeuser(usrp);
3181 * Now, we can add the new one.
3183 if (nidp->nid_usertimeout)
3184 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3186 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3187 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3188 newusrp->lug_uid = nidp->nid_uid;
3189 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3191 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3192 newusrp->lug_namelen), newusrp, lug_namehash);
3193 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3195 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3196 newusrp->lug_gid = nidp->nid_gid;
3197 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3199 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3200 newusrp->lug_namelen), newusrp, lug_namehash);
3201 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3204 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3212 * Remove a user/group name element.
3215 nfsrv_removeuser(struct nfsusrgrp *usrp)
3218 NFSNAMEIDREQUIRED();
3219 LIST_REMOVE(usrp, lug_numhash);
3220 LIST_REMOVE(usrp, lug_namehash);
3221 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3223 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3227 * This function scans a byte string and checks for UTF-8 compliance.
3228 * It returns 0 if it conforms and NFSERR_INVAL if not.
3231 nfsrv_checkutf8(u_int8_t *cp, int len)
3233 u_int32_t val = 0x0;
3234 int cnt = 0, gotd = 0, shift = 0;
3236 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3240 * Here are what the variables are used for:
3241 * val - the calculated value of a multibyte char, used to check
3242 * that it was coded with the correct range
3243 * cnt - the number of 10xxxxxx bytes to follow
3244 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3245 * shift - lower order bits of range (ie. "val >> shift" should
3246 * not be 0, in other words, dividing by the lower bound
3247 * of the range should get a non-zero value)
3248 * byte - used to calculate cnt
3252 /* This handles the 10xxxxxx bytes */
3253 if ((*cp & 0xc0) != 0x80 ||
3254 (gotd && (*cp & 0x20))) {
3255 error = NFSERR_INVAL;
3260 val |= (*cp & 0x3f);
3262 if (cnt == 0 && (val >> shift) == 0x0) {
3263 error = NFSERR_INVAL;
3266 } else if (*cp & 0x80) {
3267 /* first byte of multi byte char */
3269 while ((byte & 0x40) && cnt < 6) {
3273 if (cnt == 0 || cnt == 6) {
3274 error = NFSERR_INVAL;
3277 val = (*cp & (0x3f >> cnt));
3278 shift = utf8_shift[cnt - 1];
3279 if (cnt == 2 && val == 0xd)
3280 /* Check for the 0xd800-0xdfff case */
3287 error = NFSERR_INVAL;
3295 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3296 * strings, one with the root path in it and the other with the list of
3297 * locations. The list is in the same format as is found in nfr_refs.
3298 * It is a "," separated list of entries, where each of them is of the
3299 * form <server>:<rootpath>. For example
3300 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3301 * The nilp argument is set to 1 for the special case of a null fs_root
3302 * and an empty server list.
3303 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3304 * number of xdr bytes parsed in sump.
3307 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3308 int *sump, int *nilp)
3311 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3312 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3314 SLIST_ENTRY(list) next;
3318 SLIST_HEAD(, list) head;
3325 * Get the fs_root path and check for the special case of null path
3326 * and 0 length server list.
3328 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3329 len = fxdr_unsigned(int, *tl);
3330 if (len < 0 || len > 10240) {
3331 error = NFSERR_BADXDR;
3335 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3337 error = NFSERR_BADXDR;
3341 *sump = 2 * NFSX_UNSIGNED;
3345 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3346 error = nfsrv_mtostr(nd, cp, len);
3348 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3349 cnt = fxdr_unsigned(int, *tl);
3351 error = NFSERR_BADXDR;
3357 * Now, loop through the location list and make up the srvlist.
3359 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3360 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3363 for (i = 0; i < cnt; i++) {
3365 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3366 nsrv = fxdr_unsigned(int, *tl);
3368 error = NFSERR_BADXDR;
3373 * Handle the first server by putting it in the srvstr.
3375 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3376 len = fxdr_unsigned(int, *tl);
3377 if (len <= 0 || len > 1024) {
3378 error = NFSERR_BADXDR;
3381 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3386 error = nfsrv_mtostr(nd, cp3, len);
3392 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3393 for (j = 1; j < nsrv; j++) {
3395 * Yuck, put them in an slist and process them later.
3397 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3398 len = fxdr_unsigned(int, *tl);
3399 if (len <= 0 || len > 1024) {
3400 error = NFSERR_BADXDR;
3403 lsp = (struct list *)malloc(sizeof (struct list)
3404 + len, M_TEMP, M_WAITOK);
3405 error = nfsrv_mtostr(nd, lsp->host, len);
3408 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3410 SLIST_INSERT_HEAD(&head, lsp, next);
3414 * Finally, we can get the path.
3416 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3417 len = fxdr_unsigned(int, *tl);
3418 if (len <= 0 || len > 1024) {
3419 error = NFSERR_BADXDR;
3422 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3423 error = nfsrv_mtostr(nd, cp3, len);
3426 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3431 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3432 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3435 NFSBCOPY(lsp->host, cp3, lsp->len);
3438 NFSBCOPY(str, cp3, stringlen);
3441 siz += (lsp->len + stringlen + 2);
3442 free((caddr_t)lsp, M_TEMP);
3448 NFSEXITCODE2(0, nd);
3452 free(cp, M_NFSSTRING);
3454 free(cp2, M_NFSSTRING);
3455 NFSEXITCODE2(error, nd);
3460 * Make the malloc'd space large enough. This is a pain, but the xdr
3461 * doesn't set an upper bound on the side, so...
3464 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3471 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3472 NFSBCOPY(*cpp, cp, *slenp);
3473 free(*cpp, M_NFSSTRING);
3477 *slenp = siz + 1024;
3481 * Initialize the reply header data structures.
3484 nfsrvd_rephead(struct nfsrv_descript *nd)
3489 * If this is a big reply, use a cluster.
3491 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3492 nfs_bigreply[nd->nd_procnum]) {
3493 NFSMCLGET(mreq, M_WAITOK);
3501 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3502 mbuf_setlen(mreq, 0);
3504 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3505 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3509 * Lock a socket against others.
3510 * Currently used to serialize connect/disconnect attempts.
3513 newnfs_sndlock(int *flagp)
3518 while (*flagp & NFSR_SNDLOCK) {
3519 *flagp |= NFSR_WANTSND;
3522 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3523 PZERO - 1, "nfsndlck", &ts);
3525 *flagp |= NFSR_SNDLOCK;
3531 * Unlock the stream socket for others.
3534 newnfs_sndunlock(int *flagp)
3538 if ((*flagp & NFSR_SNDLOCK) == 0)
3539 panic("nfs sndunlock");
3540 *flagp &= ~NFSR_SNDLOCK;
3541 if (*flagp & NFSR_WANTSND) {
3542 *flagp &= ~NFSR_WANTSND;
3543 wakeup((caddr_t)flagp);
3549 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3552 struct sockaddr_in *sad;
3553 struct sockaddr_in6 *sad6;
3554 struct in_addr saddr;
3555 uint32_t portnum, *tl;
3556 int af = 0, i, j, k;
3557 char addr[64], protocol[5], *cp;
3558 int cantparse = 0, error = 0;
3561 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3562 i = fxdr_unsigned(int, *tl);
3563 if (i >= 3 && i <= 4) {
3564 error = nfsrv_mtostr(nd, protocol, i);
3567 if (strcmp(protocol, "tcp") == 0) {
3570 } else if (strcmp(protocol, "udp") == 0) {
3573 } else if (strcmp(protocol, "tcp6") == 0) {
3576 } else if (strcmp(protocol, "udp6") == 0) {
3584 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3589 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3590 i = fxdr_unsigned(int, *tl);
3592 error = NFSERR_BADXDR;
3594 } else if (cantparse == 0 && i >= 11 && i < 64) {
3596 * The shortest address is 11chars and the longest is < 64.
3598 error = nfsrv_mtostr(nd, addr, i);
3602 /* Find the port# at the end and extract that. */
3606 /* Count back two '.'s from end to get port# field. */
3607 for (j = 0; j < i; j++) {
3617 * The NFSv4 port# is appended as .N.N, where N is
3618 * a decimal # in the range 0-255, just like an inet4
3619 * address. Cheat and use inet_aton(), which will
3620 * return a Class A address and then shift the high
3621 * order 8bits over to convert it to the port#.
3624 if (inet_aton(cp, &saddr) == 1) {
3625 portnum = ntohl(saddr.s_addr);
3626 portv = (uint16_t)((portnum >> 16) |
3632 if (cantparse == 0) {
3633 if (af == AF_INET) {
3634 sad = (struct sockaddr_in *)sa;
3635 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
3636 sad->sin_len = sizeof(*sad);
3637 sad->sin_family = AF_INET;
3638 sad->sin_port = htons(portv);
3642 sad6 = (struct sockaddr_in6 *)sa;
3643 if (inet_pton(af, addr, &sad6->sin6_addr)
3645 sad6->sin6_len = sizeof(*sad6);
3646 sad6->sin6_family = AF_INET6;
3647 sad6->sin6_port = htons(portv);
3654 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3665 * Handle an NFSv4.1 Sequence request for the session.
3668 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
3669 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
3675 if (slotid > maxslot)
3676 return (NFSERR_BADSLOT);
3677 if (seqid == slots[slotid].nfssl_seq) {
3679 if (slots[slotid].nfssl_inprog != 0)
3680 error = NFSERR_DELAY;
3681 else if (slots[slotid].nfssl_reply != NULL) {
3682 *reply = slots[slotid].nfssl_reply;
3683 slots[slotid].nfssl_reply = NULL;
3684 slots[slotid].nfssl_inprog = 1;
3686 error = NFSERR_SEQMISORDERED;
3687 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
3688 m_freem(slots[slotid].nfssl_reply);
3689 slots[slotid].nfssl_reply = NULL;
3690 slots[slotid].nfssl_inprog = 1;
3691 slots[slotid].nfssl_seq++;
3693 error = NFSERR_SEQMISORDERED;
3698 * Cache this reply for the slot.
3701 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep)
3704 slots[slotid].nfssl_reply = rep;
3705 slots[slotid].nfssl_inprog = 0;
3709 * Generate the xdr for an NFSv4.1 Sequence Operation.
3712 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
3713 struct nfsclsession *sep, int dont_replycache)
3715 uint32_t *tl, slotseq = 0;
3716 int i, maxslot, slotpos;
3718 uint8_t sessionid[NFSX_V4SESSIONID];
3720 /* Find an unused slot. */
3723 mtx_lock(&sep->nfsess_mtx);
3726 for (i = 0; i < sep->nfsess_foreslots; i++) {
3727 if ((bitval & sep->nfsess_slots) == 0) {
3729 sep->nfsess_slots |= bitval;
3730 sep->nfsess_slotseq[i]++;
3731 slotseq = sep->nfsess_slotseq[i];
3736 if (slotpos == -1) {
3738 * If a forced dismount is in progress, just return.
3739 * This RPC attempt will fail when it calls
3742 if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
3744 mtx_unlock(&sep->nfsess_mtx);
3747 /* Wake up once/sec, to check for a forced dismount. */
3748 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
3749 PZERO, "nfsclseq", hz);
3751 } while (slotpos == -1);
3752 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
3754 for (i = 0; i < 64; i++) {
3755 if ((bitval & sep->nfsess_slots) != 0)
3759 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
3760 mtx_unlock(&sep->nfsess_mtx);
3761 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
3763 /* Build the Sequence arguments. */
3764 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
3765 bcopy(sessionid, tl, NFSX_V4SESSIONID);
3766 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
3767 nd->nd_slotseq = tl;
3768 *tl++ = txdr_unsigned(slotseq);
3769 *tl++ = txdr_unsigned(slotpos);
3770 *tl++ = txdr_unsigned(maxslot);
3771 if (dont_replycache == 0)
3775 nd->nd_flag |= ND_HASSEQUENCE;
3779 * Free a session slot.
3782 nfsv4_freeslot(struct nfsclsession *sep, int slot)
3789 mtx_lock(&sep->nfsess_mtx);
3790 if ((bitval & sep->nfsess_slots) == 0)
3791 printf("freeing free slot!!\n");
3792 sep->nfsess_slots &= ~bitval;
3793 wakeup(&sep->nfsess_slots);
3794 mtx_unlock(&sep->nfsess_mtx);