xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision 52c81be11a107cdedb865a274b5567b0c95c0308)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 /*
40  * These functions support the macros and help fiddle mbuf chains for
41  * the nfs op functions. They do things like create the rpc header and
42  * copy data between mbuf chains and uio lists.
43  */
44 #include "opt_inet.h"
45 #include "opt_inet6.h"
46 
47 #include <fs/nfs/nfsport.h>
48 
49 #include <sys/extattr.h>
50 
51 #include <security/mac/mac_framework.h>
52 
53 /*
54  * Data items converted to xdr at startup, since they are constant
55  * This is kinda hokey, but may save a little time doing byte swaps
56  */
57 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
58 
59 /* And other global data */
60 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
61 		      NFFIFO, NFNON };
62 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
63 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
64 struct timeval nfsboottime;	/* Copy boottime once, so it never changes */
65 int nfscl_ticks;
66 int nfsrv_useacl = 1;
67 struct nfssockreq nfsrv_nfsuserdsock;
68 nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
69 static int nfsrv_userdupcalls = 0;
70 struct nfsreqhead nfsd_reqq;
71 uid_t nfsrv_defaultuid = UID_NOBODY;
72 gid_t nfsrv_defaultgid = GID_NOGROUP;
73 int nfsrv_lease = NFSRV_LEASE;
74 int ncl_mbuf_mlen = MLEN;
75 int nfsd_enable_stringtouid = 0;
76 int nfsrv_doflexfile = 0;
77 static int nfs_enable_uidtostring = 0;
78 NFSNAMEIDMUTEX;
79 NFSSOCKMUTEX;
80 extern int nfsrv_lughashsize;
81 extern struct mtx nfsrv_dslock_mtx;
82 extern volatile int nfsrv_devidcnt;
83 extern int nfscl_debuglevel;
84 extern struct nfsdevicehead nfsrv_devidhead;
85 extern struct nfsstatsv1 nfsstatsv1;
86 
87 SYSCTL_DECL(_vfs_nfs);
88 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
89     &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
90 
91 int nfsrv_maxpnfsmirror = 1;
92 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
93     &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
94 
95 int nfs_maxcopyrange = 10 * 1024 * 1024;
96 SYSCTL_INT(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
97     &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
98 
99 /*
100  * This array of structures indicates, for V4:
101  * retfh - which of 3 types of calling args are used
102  *	0 - doesn't change cfh or use a sfh
103  *	1 - replaces cfh with a new one (unless it returns an error status)
104  *	2 - uses cfh and sfh
105  * needscfh - if the op wants a cfh and premtime
106  *	0 - doesn't use a cfh
107  *	1 - uses a cfh, but doesn't want pre-op attributes
108  *	2 - uses a cfh and wants pre-op attributes
109  * savereply - indicates a non-idempotent Op
110  *	0 - not non-idempotent
111  *	1 - non-idempotent
112  * Ops that are ordered via seqid# are handled separately from these
113  * non-idempotent Ops.
114  * Define it here, since it is used by both the client and server.
115  */
116 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
117 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
118 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
119 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
120 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Access */
121 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Close */
122 	{ 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 },		/* Commit */
123 	{ 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Create */
124 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Delegpurge */
125 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Delegreturn */
126 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Getattr */
127 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* GetFH */
128 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Link */
129 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Lock */
130 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* LockT */
131 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* LockU */
132 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Lookup */
133 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Lookupp */
134 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* NVerify */
135 	{ 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },		/* Open */
136 	{ 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenAttr */
137 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenConfirm */
138 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenDowngrade */
139 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutFH */
140 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutPubFH */
141 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutRootFH */
142 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* Read */
143 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Readdir */
144 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* ReadLink */
145 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Remove */
146 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Rename */
147 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Renew */
148 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* RestoreFH */
149 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SaveFH */
150 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SecInfo */
151 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Setattr */
152 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SetClientID */
153 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SetClientIDConfirm */
154 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Verify */
155 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Write */
156 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* ReleaseLockOwner */
157 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Backchannel Ctrl */
158 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Bind Conn to Sess */
159 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Exchange ID */
160 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Create Session */
161 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Destroy Session */
162 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Free StateID */
163 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Dir Deleg */
164 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Device Info */
165 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Device List */
166 	{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 },		/* Layout Commit */
167 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Layout Get */
168 	{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },		/* Layout Return */
169 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Secinfo No name */
170 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Sequence */
171 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Set SSV */
172 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Test StateID */
173 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Want Delegation */
174 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Destroy ClientID */
175 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Reclaim Complete */
176 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Allocate */
177 	{ 2, 1, 1, 0, LK_SHARED, 1, 0 },		/* Copy */
178 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Copy Notify */
179 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Deallocate */
180 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* IO Advise */
181 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Layout Error */
182 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Layout Stats */
183 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Offload Cancel */
184 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Offload Status */
185 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Read Plus */
186 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* Seek */
187 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Write Same */
188 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Clone */
189 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Getxattr */
190 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Setxattr */
191 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Listxattrs */
192 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Removexattr */
193 };
194 
195 static int ncl_mbuf_mhlen = MHLEN;
196 static int nfsrv_usercnt = 0;
197 static int nfsrv_dnsnamelen;
198 static u_char *nfsrv_dnsname = NULL;
199 static int nfsrv_usermax = 999999999;
200 struct nfsrv_lughash {
201 	struct mtx		mtx;
202 	struct nfsuserhashhead	lughead;
203 };
204 static struct nfsrv_lughash	*nfsuserhash;
205 static struct nfsrv_lughash	*nfsusernamehash;
206 static struct nfsrv_lughash	*nfsgrouphash;
207 static struct nfsrv_lughash	*nfsgroupnamehash;
208 
209 /*
210  * This static array indicates whether or not the RPC generates a large
211  * reply. This is used by nfs_reply() to decide whether or not an mbuf
212  * cluster should be allocated. (If a cluster is required by an RPC
213  * marked 0 in this array, the code will still work, just not quite as
214  * efficiently.)
215  */
216 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
217     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,
218     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
219     1, 0, 0, 1 };
220 
221 /* local functions */
222 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
223 static void nfsv4_wanted(struct nfsv4lock *lp);
224 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
225 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
226 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
227 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
228     int *, int *);
229 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
230 
231 static struct {
232 	int	op;
233 	int	opcnt;
234 	const u_char *tag;
235 	int	taglen;
236 } nfsv4_opmap[NFSV42_NPROCS] = {
237 	{ 0, 1, "Null", 4 },
238 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
239 	{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
240 	{ NFSV4OP_LOOKUP, 3, "Lookup", 6, },
241 	{ NFSV4OP_ACCESS, 2, "Access", 6, },
242 	{ NFSV4OP_READLINK, 2, "Readlink", 8, },
243 	{ NFSV4OP_READ, 1, "Read", 4, },
244 	{ NFSV4OP_WRITE, 2, "Write", 5, },
245 	{ NFSV4OP_OPEN, 5, "Open", 4, },
246 	{ NFSV4OP_CREATE, 5, "Create", 6, },
247 	{ NFSV4OP_CREATE, 1, "Create", 6, },
248 	{ NFSV4OP_CREATE, 3, "Create", 6, },
249 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
250 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
251 	{ NFSV4OP_SAVEFH, 5, "Rename", 6, },
252 	{ NFSV4OP_SAVEFH, 4, "Link", 4, },
253 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
254 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
255 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
256 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
257 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
258 	{ NFSV4OP_COMMIT, 2, "Commit", 6, },
259 	{ NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
260 	{ NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
261 	{ NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
262 	{ NFSV4OP_LOCK, 1, "Lock", 4, },
263 	{ NFSV4OP_LOCKU, 1, "LockU", 5, },
264 	{ NFSV4OP_OPEN, 2, "Open", 4, },
265 	{ NFSV4OP_CLOSE, 1, "Close", 5, },
266 	{ NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
267 	{ NFSV4OP_LOCKT, 1, "LockT", 5, },
268 	{ NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
269 	{ NFSV4OP_RENEW, 1, "Renew", 5, },
270 	{ NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
271 	{ NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
272 	{ NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
273 	{ NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
274 	{ NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
275 	{ NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
276 	{ NFSV4OP_GETATTR, 1, "Getacl", 6, },
277 	{ NFSV4OP_SETATTR, 1, "Setacl", 6, },
278 	{ NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
279 	{ NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
280 	{ NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
281 	{ NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
282 	{ NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
283 	{ NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
284 	{ NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
285 	{ NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
286 	{ NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
287 	{ NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
288 	{ NFSV4OP_WRITE, 1, "WriteDS", 7, },
289 	{ NFSV4OP_READ, 1, "ReadDS", 6, },
290 	{ NFSV4OP_COMMIT, 1, "CommitDS", 8, },
291 	{ NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
292 	{ NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
293 	{ NFSV4OP_IOADVISE, 1, "Advise", 6, },
294 	{ NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
295 	{ NFSV4OP_SAVEFH, 5, "Copy", 4, },
296 	{ NFSV4OP_SEEK, 2, "Seek", 4, },
297 	{ NFSV4OP_SEEK, 1, "SeekDS", 6, },
298 	{ NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
299 	{ NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
300 	{ NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
301 	{ NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
302 };
303 
304 /*
305  * NFS RPCS that have large request message size.
306  */
307 static int nfs_bigrequest[NFSV42_NPROCS] = {
308 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
309 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
310 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
311 };
312 
313 /*
314  * Start building a request. Mostly just put the first file handle in
315  * place.
316  */
317 void
318 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
319     u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
320     int vers, int minorvers)
321 {
322 	struct mbuf *mb;
323 	u_int32_t *tl;
324 	int opcnt;
325 	nfsattrbit_t attrbits;
326 
327 	/*
328 	 * First, fill in some of the fields of nd.
329 	 */
330 	nd->nd_slotseq = NULL;
331 	if (vers == NFS_VER4) {
332 		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
333 		if (minorvers == NFSV41_MINORVERSION)
334 			nd->nd_flag |= ND_NFSV41;
335 		else if (minorvers == NFSV42_MINORVERSION)
336 			nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
337 	} else if (vers == NFS_VER3)
338 		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
339 	else {
340 		if (NFSHASNFSV4(nmp)) {
341 			nd->nd_flag = ND_NFSV4 | ND_NFSCL;
342 			if (nmp->nm_minorvers == 1)
343 				nd->nd_flag |= ND_NFSV41;
344 			else if (nmp->nm_minorvers == 2)
345 				nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
346 		} else if (NFSHASNFSV3(nmp))
347 			nd->nd_flag = ND_NFSV3 | ND_NFSCL;
348 		else
349 			nd->nd_flag = ND_NFSV2 | ND_NFSCL;
350 	}
351 	nd->nd_procnum = procnum;
352 	nd->nd_repstat = 0;
353 
354 	/*
355 	 * Get the first mbuf for the request.
356 	 */
357 	if (nfs_bigrequest[procnum])
358 		NFSMCLGET(mb, M_WAITOK);
359 	else
360 		NFSMGET(mb);
361 	mb->m_len = 0;
362 	nd->nd_mreq = nd->nd_mb = mb;
363 	nd->nd_bpos = mtod(mb, caddr_t);
364 
365 	/*
366 	 * And fill the first file handle into the request.
367 	 */
368 	if (nd->nd_flag & ND_NFSV4) {
369 		opcnt = nfsv4_opmap[procnum].opcnt +
370 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
371 		if ((nd->nd_flag & ND_NFSV41) != 0) {
372 			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
373 			if (procnum == NFSPROC_RENEW)
374 				/*
375 				 * For the special case of Renew, just do a
376 				 * Sequence Op.
377 				 */
378 				opcnt = 1;
379 			else if (procnum == NFSPROC_WRITEDS ||
380 			    procnum == NFSPROC_COMMITDS)
381 				/*
382 				 * For the special case of a Writeor Commit to
383 				 * a DS, the opcnt == 3, for Sequence, PutFH,
384 				 * Write/Commit.
385 				 */
386 				opcnt = 3;
387 		}
388 		/*
389 		 * What should the tag really be?
390 		 */
391 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
392 			nfsv4_opmap[procnum].taglen);
393 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
394 		if ((nd->nd_flag & ND_NFSV42) != 0)
395 			*tl++ = txdr_unsigned(NFSV42_MINORVERSION);
396 		else if ((nd->nd_flag & ND_NFSV41) != 0)
397 			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
398 		else
399 			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
400 		if (opcntpp != NULL)
401 			*opcntpp = tl;
402 		*tl = txdr_unsigned(opcnt);
403 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
404 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
405 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
406 			    0)
407 				nd->nd_flag |= ND_LOOPBADSESS;
408 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
409 			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
410 			if (sep == NULL) {
411 				sep = nfsmnt_mdssession(nmp);
412 				nfsv4_setsequence(nmp, nd, sep,
413 				    nfs_bigreply[procnum]);
414 			} else
415 				nfsv4_setsequence(nmp, nd, sep,
416 				    nfs_bigreply[procnum]);
417 		}
418 		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
419 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
420 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
421 			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
422 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
423 			    == 2 && procnum != NFSPROC_WRITEDS &&
424 			    procnum != NFSPROC_COMMITDS) {
425 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
426 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
427 				/*
428 				 * For Lookup Ops, we want all the directory
429 				 * attributes, so we can load the name cache.
430 				 */
431 				if (procnum == NFSPROC_LOOKUP ||
432 				    procnum == NFSPROC_LOOKUPP)
433 					NFSGETATTR_ATTRBIT(&attrbits);
434 				else {
435 					NFSWCCATTR_ATTRBIT(&attrbits);
436 					nd->nd_flag |= ND_V4WCCATTR;
437 				}
438 				(void) nfsrv_putattrbit(nd, &attrbits);
439 			}
440 		}
441 		if (procnum != NFSPROC_RENEW ||
442 		    (nd->nd_flag & ND_NFSV41) == 0) {
443 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
444 			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
445 		}
446 	} else {
447 		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
448 	}
449 	if (procnum < NFSV42_NPROCS)
450 		NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
451 }
452 
453 /*
454  * Put a state Id in the mbuf list.
455  */
456 void
457 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
458 {
459 	nfsv4stateid_t *st;
460 
461 	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
462 	if (flag == NFSSTATEID_PUTALLZERO) {
463 		st->seqid = 0;
464 		st->other[0] = 0;
465 		st->other[1] = 0;
466 		st->other[2] = 0;
467 	} else if (flag == NFSSTATEID_PUTALLONE) {
468 		st->seqid = 0xffffffff;
469 		st->other[0] = 0xffffffff;
470 		st->other[1] = 0xffffffff;
471 		st->other[2] = 0xffffffff;
472 	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
473 		st->seqid = 0;
474 		st->other[0] = stateidp->other[0];
475 		st->other[1] = stateidp->other[1];
476 		st->other[2] = stateidp->other[2];
477 	} else {
478 		st->seqid = stateidp->seqid;
479 		st->other[0] = stateidp->other[0];
480 		st->other[1] = stateidp->other[1];
481 		st->other[2] = stateidp->other[2];
482 	}
483 }
484 
485 /*
486  * Fill in the setable attributes. The full argument indicates whether
487  * to fill in them all or just mode and time.
488  */
489 void
490 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
491     struct vnode *vp, int flags, u_int32_t rdev)
492 {
493 	u_int32_t *tl;
494 	struct nfsv2_sattr *sp;
495 	nfsattrbit_t attrbits;
496 
497 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
498 	case ND_NFSV2:
499 		NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
500 		if (vap->va_mode == (mode_t)VNOVAL)
501 			sp->sa_mode = newnfs_xdrneg1;
502 		else
503 			sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
504 		if (vap->va_uid == (uid_t)VNOVAL)
505 			sp->sa_uid = newnfs_xdrneg1;
506 		else
507 			sp->sa_uid = txdr_unsigned(vap->va_uid);
508 		if (vap->va_gid == (gid_t)VNOVAL)
509 			sp->sa_gid = newnfs_xdrneg1;
510 		else
511 			sp->sa_gid = txdr_unsigned(vap->va_gid);
512 		if (flags & NFSSATTR_SIZE0)
513 			sp->sa_size = 0;
514 		else if (flags & NFSSATTR_SIZENEG1)
515 			sp->sa_size = newnfs_xdrneg1;
516 		else if (flags & NFSSATTR_SIZERDEV)
517 			sp->sa_size = txdr_unsigned(rdev);
518 		else
519 			sp->sa_size = txdr_unsigned(vap->va_size);
520 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
521 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
522 		break;
523 	case ND_NFSV3:
524 		if (vap->va_mode != (mode_t)VNOVAL) {
525 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
526 			*tl++ = newnfs_true;
527 			*tl = txdr_unsigned(vap->va_mode);
528 		} else {
529 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
530 			*tl = newnfs_false;
531 		}
532 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
533 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
534 			*tl++ = newnfs_true;
535 			*tl = txdr_unsigned(vap->va_uid);
536 		} else {
537 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
538 			*tl = newnfs_false;
539 		}
540 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
541 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
542 			*tl++ = newnfs_true;
543 			*tl = txdr_unsigned(vap->va_gid);
544 		} else {
545 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
546 			*tl = newnfs_false;
547 		}
548 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
549 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
550 			*tl++ = newnfs_true;
551 			txdr_hyper(vap->va_size, tl);
552 		} else {
553 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
554 			*tl = newnfs_false;
555 		}
556 		if (vap->va_atime.tv_sec != VNOVAL) {
557 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
558 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
559 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
560 				txdr_nfsv3time(&vap->va_atime, tl);
561 			} else {
562 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
563 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
564 			}
565 		} else {
566 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
567 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
568 		}
569 		if (vap->va_mtime.tv_sec != VNOVAL) {
570 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
571 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
572 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
573 				txdr_nfsv3time(&vap->va_mtime, tl);
574 			} else {
575 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
576 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
577 			}
578 		} else {
579 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
580 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
581 		}
582 		break;
583 	case ND_NFSV4:
584 		NFSZERO_ATTRBIT(&attrbits);
585 		if (vap->va_mode != (mode_t)VNOVAL)
586 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
587 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
588 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
589 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
590 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
591 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
592 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
593 		if (vap->va_atime.tv_sec != VNOVAL)
594 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
595 		if (vap->va_mtime.tv_sec != VNOVAL)
596 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
597 		(void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
598 		    &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
599 		break;
600 	}
601 }
602 
603 #ifndef APPLE
604 /*
605  * copies mbuf chain to the uio scatter/gather list
606  */
607 int
608 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
609 {
610 	char *mbufcp, *uiocp;
611 	int xfer, left, len;
612 	struct mbuf *mp;
613 	long uiosiz, rem;
614 	int error = 0;
615 
616 	mp = nd->nd_md;
617 	mbufcp = nd->nd_dpos;
618 	len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
619 	rem = NFSM_RNDUP(siz) - siz;
620 	while (siz > 0) {
621 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
622 			error = EBADRPC;
623 			goto out;
624 		}
625 		left = uiop->uio_iov->iov_len;
626 		uiocp = uiop->uio_iov->iov_base;
627 		if (left > siz)
628 			left = siz;
629 		uiosiz = left;
630 		while (left > 0) {
631 			while (len == 0) {
632 				mp = mp->m_next;
633 				if (mp == NULL) {
634 					error = EBADRPC;
635 					goto out;
636 				}
637 				mbufcp = mtod(mp, caddr_t);
638 				len = mp->m_len;
639 				KASSERT(len >= 0,
640 				    ("len %d, corrupted mbuf?", len));
641 			}
642 			xfer = (left > len) ? len : left;
643 #ifdef notdef
644 			/* Not Yet.. */
645 			if (uiop->uio_iov->iov_op != NULL)
646 				(*(uiop->uio_iov->iov_op))
647 				(mbufcp, uiocp, xfer);
648 			else
649 #endif
650 			if (uiop->uio_segflg == UIO_SYSSPACE)
651 				NFSBCOPY(mbufcp, uiocp, xfer);
652 			else
653 				copyout(mbufcp, uiocp, xfer);
654 			left -= xfer;
655 			len -= xfer;
656 			mbufcp += xfer;
657 			uiocp += xfer;
658 			uiop->uio_offset += xfer;
659 			uiop->uio_resid -= xfer;
660 		}
661 		if (uiop->uio_iov->iov_len <= siz) {
662 			uiop->uio_iovcnt--;
663 			uiop->uio_iov++;
664 		} else {
665 			uiop->uio_iov->iov_base = (void *)
666 				((char *)uiop->uio_iov->iov_base + uiosiz);
667 			uiop->uio_iov->iov_len -= uiosiz;
668 		}
669 		siz -= uiosiz;
670 	}
671 	nd->nd_dpos = mbufcp;
672 	nd->nd_md = mp;
673 	if (rem > 0) {
674 		if (len < rem)
675 			error = nfsm_advance(nd, rem, len);
676 		else
677 			nd->nd_dpos += rem;
678 	}
679 
680 out:
681 	NFSEXITCODE2(error, nd);
682 	return (error);
683 }
684 #endif	/* !APPLE */
685 
686 /*
687  * Help break down an mbuf chain by setting the first siz bytes contiguous
688  * pointed to by returned val.
689  * This is used by the macro NFSM_DISSECT for tough
690  * cases.
691  */
692 void *
693 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
694 {
695 	struct mbuf *mp2;
696 	int siz2, xfer;
697 	caddr_t p;
698 	int left;
699 	caddr_t retp;
700 
701 	retp = NULL;
702 	left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
703 	while (left == 0) {
704 		nd->nd_md = nd->nd_md->m_next;
705 		if (nd->nd_md == NULL)
706 			return (retp);
707 		left = nd->nd_md->m_len;
708 		nd->nd_dpos = mtod(nd->nd_md, caddr_t);
709 	}
710 	if (left >= siz) {
711 		retp = nd->nd_dpos;
712 		nd->nd_dpos += siz;
713 	} else if (nd->nd_md->m_next == NULL) {
714 		return (retp);
715 	} else if (siz > ncl_mbuf_mhlen) {
716 		panic("nfs S too big");
717 	} else {
718 		MGET(mp2, MT_DATA, how);
719 		if (mp2 == NULL)
720 			return (NULL);
721 		mp2->m_next = nd->nd_md->m_next;
722 		nd->nd_md->m_next = mp2;
723 		nd->nd_md->m_len -= left;
724 		nd->nd_md = mp2;
725 		retp = p = mtod(mp2, caddr_t);
726 		NFSBCOPY(nd->nd_dpos, p, left);	/* Copy what was left */
727 		siz2 = siz - left;
728 		p += left;
729 		mp2 = mp2->m_next;
730 		/* Loop around copying up the siz2 bytes */
731 		while (siz2 > 0) {
732 			if (mp2 == NULL)
733 				return (NULL);
734 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
735 			if (xfer > 0) {
736 				NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
737 				mp2->m_data += xfer;
738 				mp2->m_len -= xfer;
739 				p += xfer;
740 				siz2 -= xfer;
741 			}
742 			if (siz2 > 0)
743 				mp2 = mp2->m_next;
744 		}
745 		nd->nd_md->m_len = siz;
746 		nd->nd_md = mp2;
747 		nd->nd_dpos = mtod(mp2, caddr_t);
748 	}
749 	return (retp);
750 }
751 
752 /*
753  * Advance the position in the mbuf chain.
754  * If offs == 0, this is a no-op, but it is simpler to just return from
755  * here than check for offs > 0 for all calls to nfsm_advance.
756  * If left == -1, it should be calculated here.
757  */
758 int
759 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
760 {
761 	int error = 0;
762 
763 	if (offs == 0)
764 		goto out;
765 	/*
766 	 * A negative offs might indicate a corrupted mbuf chain and,
767 	 * as such, a printf is logged.
768 	 */
769 	if (offs < 0) {
770 		printf("nfsrv_advance: negative offs\n");
771 		error = EBADRPC;
772 		goto out;
773 	}
774 
775 	/*
776 	 * If left == -1, calculate it here.
777 	 */
778 	if (left == -1)
779 		left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
780 		    nd->nd_dpos;
781 
782 	/*
783 	 * Loop around, advancing over the mbuf data.
784 	 */
785 	while (offs > left) {
786 		offs -= left;
787 		nd->nd_md = nd->nd_md->m_next;
788 		if (nd->nd_md == NULL) {
789 			error = EBADRPC;
790 			goto out;
791 		}
792 		left = nd->nd_md->m_len;
793 		nd->nd_dpos = mtod(nd->nd_md, caddr_t);
794 	}
795 	nd->nd_dpos += offs;
796 
797 out:
798 	NFSEXITCODE(error);
799 	return (error);
800 }
801 
802 /*
803  * Copy a string into mbuf(s).
804  * Return the number of bytes output, including XDR overheads.
805  */
806 int
807 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
808 {
809 	struct mbuf *m2;
810 	int xfer, left;
811 	struct mbuf *m1;
812 	int rem, bytesize;
813 	u_int32_t *tl;
814 	char *cp2;
815 
816 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
817 	*tl = txdr_unsigned(siz);
818 	rem = NFSM_RNDUP(siz) - siz;
819 	bytesize = NFSX_UNSIGNED + siz + rem;
820 	m2 = nd->nd_mb;
821 	cp2 = nd->nd_bpos;
822 	left = M_TRAILINGSPACE(m2);
823 
824 	/*
825 	 * Loop around copying the string to mbuf(s).
826 	 */
827 	while (siz > 0) {
828 		if (left == 0) {
829 			if (siz > ncl_mbuf_mlen)
830 				NFSMCLGET(m1, M_WAITOK);
831 			else
832 				NFSMGET(m1);
833 			m1->m_len = 0;
834 			m2->m_next = m1;
835 			m2 = m1;
836 			cp2 = mtod(m2, caddr_t);
837 			left = M_TRAILINGSPACE(m2);
838 		}
839 		if (left >= siz)
840 			xfer = siz;
841 		else
842 			xfer = left;
843 		NFSBCOPY(cp, cp2, xfer);
844 		cp += xfer;
845 		m2->m_len += xfer;
846 		siz -= xfer;
847 		left -= xfer;
848 		if (siz == 0 && rem) {
849 			if (left < rem)
850 				panic("nfsm_strtom");
851 			NFSBZERO(cp2 + xfer, rem);
852 			m2->m_len += rem;
853 		}
854 	}
855 	nd->nd_mb = m2;
856 	nd->nd_bpos = mtod(m2, caddr_t) + m2->m_len;
857 	return (bytesize);
858 }
859 
860 /*
861  * Called once to initialize data structures...
862  */
863 void
864 newnfs_init(void)
865 {
866 	static int nfs_inited = 0;
867 
868 	if (nfs_inited)
869 		return;
870 	nfs_inited = 1;
871 
872 	newnfs_true = txdr_unsigned(TRUE);
873 	newnfs_false = txdr_unsigned(FALSE);
874 	newnfs_xdrneg1 = txdr_unsigned(-1);
875 	nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
876 	if (nfscl_ticks < 1)
877 		nfscl_ticks = 1;
878 	NFSSETBOOTTIME(nfsboottime);
879 
880 	/*
881 	 * Initialize reply list and start timer
882 	 */
883 	TAILQ_INIT(&nfsd_reqq);
884 	NFS_TIMERINIT;
885 }
886 
887 /*
888  * Put a file handle in an mbuf list.
889  * If the size argument == 0, just use the default size.
890  * set_true == 1 if there should be an newnfs_true prepended on the file handle.
891  * Return the number of bytes output, including XDR overhead.
892  */
893 int
894 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
895 {
896 	u_int32_t *tl;
897 	u_int8_t *cp;
898 	int fullsiz, rem, bytesize = 0;
899 
900 	if (size == 0)
901 		size = NFSX_MYFH;
902 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
903 	case ND_NFSV2:
904 		if (size > NFSX_V2FH)
905 			panic("fh size > NFSX_V2FH for NFSv2");
906 		NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
907 		NFSBCOPY(fhp, cp, size);
908 		if (size < NFSX_V2FH)
909 			NFSBZERO(cp + size, NFSX_V2FH - size);
910 		bytesize = NFSX_V2FH;
911 		break;
912 	case ND_NFSV3:
913 	case ND_NFSV4:
914 		fullsiz = NFSM_RNDUP(size);
915 		rem = fullsiz - size;
916 		if (set_true) {
917 		    bytesize = 2 * NFSX_UNSIGNED + fullsiz;
918 		    NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
919 		    *tl = newnfs_true;
920 		} else {
921 		    bytesize = NFSX_UNSIGNED + fullsiz;
922 		}
923 		(void) nfsm_strtom(nd, fhp, size);
924 		break;
925 	}
926 	return (bytesize);
927 }
928 
929 /*
930  * This function compares two net addresses by family and returns TRUE
931  * if they are the same host.
932  * If there is any doubt, return FALSE.
933  * The AF_INET family is handled as a special case so that address mbufs
934  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
935  */
936 int
937 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
938 {
939 #ifdef INET
940 	struct sockaddr_in *inetaddr;
941 #endif
942 
943 	switch (family) {
944 #ifdef INET
945 	case AF_INET:
946 		inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
947 		if (inetaddr->sin_family == AF_INET &&
948 		    inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
949 			return (1);
950 		break;
951 #endif
952 #ifdef INET6
953 	case AF_INET6:
954 		{
955 		struct sockaddr_in6 *inetaddr6;
956 
957 		inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
958 		/* XXX - should test sin6_scope_id ? */
959 		if (inetaddr6->sin6_family == AF_INET6 &&
960 		    IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
961 			  &haddr->had_inet6))
962 			return (1);
963 		}
964 		break;
965 #endif
966 	}
967 	return (0);
968 }
969 
970 /*
971  * Similar to the above, but takes to NFSSOCKADDR_T args.
972  */
973 int
974 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
975 {
976 	struct sockaddr_in *addr1, *addr2;
977 	struct sockaddr *inaddr;
978 
979 	inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
980 	switch (inaddr->sa_family) {
981 	case AF_INET:
982 		addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
983 		addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
984 		if (addr2->sin_family == AF_INET &&
985 		    addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
986 			return (1);
987 		break;
988 #ifdef INET6
989 	case AF_INET6:
990 		{
991 		struct sockaddr_in6 *inet6addr1, *inet6addr2;
992 
993 		inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
994 		inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
995 		/* XXX - should test sin6_scope_id ? */
996 		if (inet6addr2->sin6_family == AF_INET6 &&
997 		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
998 			  &inet6addr2->sin6_addr))
999 			return (1);
1000 		}
1001 		break;
1002 #endif
1003 	}
1004 	return (0);
1005 }
1006 
1007 /*
1008  * Trim trailing data off the mbuf list being built.
1009  */
1010 void
1011 newnfs_trimtrailing(nd, mb, bpos)
1012 	struct nfsrv_descript *nd;
1013 	struct mbuf *mb;
1014 	caddr_t bpos;
1015 {
1016 
1017 	if (mb->m_next) {
1018 		m_freem(mb->m_next);
1019 		mb->m_next = NULL;
1020 	}
1021 	mb->m_len = bpos - mtod(mb, caddr_t);
1022 	nd->nd_mb = mb;
1023 	nd->nd_bpos = bpos;
1024 }
1025 
1026 /*
1027  * Dissect a file handle on the client.
1028  */
1029 int
1030 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1031 {
1032 	u_int32_t *tl;
1033 	struct nfsfh *nfhp;
1034 	int error, len;
1035 
1036 	*nfhpp = NULL;
1037 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1038 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1039 		if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1040 			len > NFSX_FHMAX) {
1041 			error = EBADRPC;
1042 			goto nfsmout;
1043 		}
1044 	} else
1045 		len = NFSX_V2FH;
1046 	nfhp = malloc(sizeof (struct nfsfh) + len,
1047 	    M_NFSFH, M_WAITOK);
1048 	error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1049 	if (error) {
1050 		free(nfhp, M_NFSFH);
1051 		goto nfsmout;
1052 	}
1053 	nfhp->nfh_len = len;
1054 	*nfhpp = nfhp;
1055 nfsmout:
1056 	NFSEXITCODE2(error, nd);
1057 	return (error);
1058 }
1059 
1060 /*
1061  * Break down the nfsv4 acl.
1062  * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1063  */
1064 int
1065 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1066     int *aclsizep, __unused NFSPROC_T *p)
1067 {
1068 	u_int32_t *tl;
1069 	int i, aclsize;
1070 	int acecnt, error = 0, aceerr = 0, acesize;
1071 
1072 	*aclerrp = 0;
1073 	if (aclp)
1074 		aclp->acl_cnt = 0;
1075 	/*
1076 	 * Parse out the ace entries and expect them to conform to
1077 	 * what can be supported by R/W/X bits.
1078 	 */
1079 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1080 	aclsize = NFSX_UNSIGNED;
1081 	acecnt = fxdr_unsigned(int, *tl);
1082 	if (acecnt > ACL_MAX_ENTRIES)
1083 		aceerr = NFSERR_ATTRNOTSUPP;
1084 	if (nfsrv_useacl == 0)
1085 		aceerr = NFSERR_ATTRNOTSUPP;
1086 	for (i = 0; i < acecnt; i++) {
1087 		if (aclp && !aceerr)
1088 			error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1089 			    &aceerr, &acesize, p);
1090 		else
1091 			error = nfsrv_skipace(nd, &acesize);
1092 		if (error)
1093 			goto nfsmout;
1094 		aclsize += acesize;
1095 	}
1096 	if (aclp && !aceerr)
1097 		aclp->acl_cnt = acecnt;
1098 	if (aceerr)
1099 		*aclerrp = aceerr;
1100 	if (aclsizep)
1101 		*aclsizep = aclsize;
1102 nfsmout:
1103 	NFSEXITCODE2(error, nd);
1104 	return (error);
1105 }
1106 
1107 /*
1108  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1109  */
1110 static int
1111 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1112 {
1113 	u_int32_t *tl;
1114 	int error, len = 0;
1115 
1116 	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1117 	len = fxdr_unsigned(int, *(tl + 3));
1118 	error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1119 nfsmout:
1120 	*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1121 	NFSEXITCODE2(error, nd);
1122 	return (error);
1123 }
1124 
1125 /*
1126  * Get attribute bits from an mbuf list.
1127  * Returns EBADRPC for a parsing error, 0 otherwise.
1128  * If the clearinvalid flag is set, clear the bits not supported.
1129  */
1130 int
1131 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1132     int *retnotsupp)
1133 {
1134 	u_int32_t *tl;
1135 	int cnt, i, outcnt;
1136 	int error = 0;
1137 
1138 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1139 	cnt = fxdr_unsigned(int, *tl);
1140 	if (cnt < 0) {
1141 		error = NFSERR_BADXDR;
1142 		goto nfsmout;
1143 	}
1144 	if (cnt > NFSATTRBIT_MAXWORDS)
1145 		outcnt = NFSATTRBIT_MAXWORDS;
1146 	else
1147 		outcnt = cnt;
1148 	NFSZERO_ATTRBIT(attrbitp);
1149 	if (outcnt > 0) {
1150 		NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1151 		for (i = 0; i < outcnt; i++)
1152 			attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1153 	}
1154 	for (i = 0; i < (cnt - outcnt); i++) {
1155 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1156 		if (retnotsupp != NULL && *tl != 0)
1157 			*retnotsupp = NFSERR_ATTRNOTSUPP;
1158 	}
1159 	if (cntp)
1160 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1161 nfsmout:
1162 	NFSEXITCODE2(error, nd);
1163 	return (error);
1164 }
1165 
1166 /*
1167  * Get the attributes for V4.
1168  * If the compare flag is true, test for any attribute changes,
1169  * otherwise return the attribute values.
1170  * These attributes cover fields in "struct vattr", "struct statfs",
1171  * "struct nfsfsinfo", the file handle and the lease duration.
1172  * The value of retcmpp is set to 1 if all attributes are the same,
1173  * and 0 otherwise.
1174  * Returns EBADRPC if it can't be parsed, 0 otherwise.
1175  */
1176 int
1177 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1178     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1179     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1180     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1181     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1182 {
1183 	u_int32_t *tl;
1184 	int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1185 	int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1186 	u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1187 	nfsattrbit_t attrbits, retattrbits, checkattrbits;
1188 	struct nfsfh *tnfhp;
1189 	struct nfsreferral *refp;
1190 	u_quad_t tquad;
1191 	nfsquad_t tnfsquad;
1192 	struct timespec temptime;
1193 	uid_t uid;
1194 	gid_t gid;
1195 	u_int32_t freenum = 0, tuint;
1196 	u_int64_t uquad = 0, thyp, thyp2;
1197 #ifdef QUOTA
1198 	struct dqblk dqb;
1199 	uid_t savuid;
1200 #endif
1201 
1202 	CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1203 	if (compare) {
1204 		retnotsup = 0;
1205 		error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1206 	} else {
1207 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1208 	}
1209 	if (error)
1210 		goto nfsmout;
1211 
1212 	if (compare) {
1213 		*retcmpp = retnotsup;
1214 	} else {
1215 		/*
1216 		 * Just set default values to some of the important ones.
1217 		 */
1218 		if (nap != NULL) {
1219 			nap->na_type = VREG;
1220 			nap->na_mode = 0;
1221 			nap->na_rdev = (NFSDEV_T)0;
1222 			nap->na_mtime.tv_sec = 0;
1223 			nap->na_mtime.tv_nsec = 0;
1224 			nap->na_gen = 0;
1225 			nap->na_flags = 0;
1226 			nap->na_blocksize = NFS_FABLKSIZE;
1227 		}
1228 		if (sbp != NULL) {
1229 			sbp->f_bsize = NFS_FABLKSIZE;
1230 			sbp->f_blocks = 0;
1231 			sbp->f_bfree = 0;
1232 			sbp->f_bavail = 0;
1233 			sbp->f_files = 0;
1234 			sbp->f_ffree = 0;
1235 		}
1236 		if (fsp != NULL) {
1237 			fsp->fs_rtmax = 8192;
1238 			fsp->fs_rtpref = 8192;
1239 			fsp->fs_maxname = NFS_MAXNAMLEN;
1240 			fsp->fs_wtmax = 8192;
1241 			fsp->fs_wtpref = 8192;
1242 			fsp->fs_wtmult = NFS_FABLKSIZE;
1243 			fsp->fs_dtpref = 8192;
1244 			fsp->fs_maxfilesize = 0xffffffffffffffffull;
1245 			fsp->fs_timedelta.tv_sec = 0;
1246 			fsp->fs_timedelta.tv_nsec = 1;
1247 			fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1248 				NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1249 		}
1250 		if (pc != NULL) {
1251 			pc->pc_linkmax = NFS_LINK_MAX;
1252 			pc->pc_namemax = NAME_MAX;
1253 			pc->pc_notrunc = 0;
1254 			pc->pc_chownrestricted = 0;
1255 			pc->pc_caseinsensitive = 0;
1256 			pc->pc_casepreserving = 1;
1257 		}
1258 		if (sfp != NULL) {
1259 			sfp->sf_ffiles = UINT64_MAX;
1260 			sfp->sf_tfiles = UINT64_MAX;
1261 			sfp->sf_afiles = UINT64_MAX;
1262 			sfp->sf_fbytes = UINT64_MAX;
1263 			sfp->sf_tbytes = UINT64_MAX;
1264 			sfp->sf_abytes = UINT64_MAX;
1265 		}
1266 	}
1267 
1268 	/*
1269 	 * Loop around getting the attributes.
1270 	 */
1271 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1272 	attrsize = fxdr_unsigned(int, *tl);
1273 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1274 	    if (attrsum > attrsize) {
1275 		error = NFSERR_BADXDR;
1276 		goto nfsmout;
1277 	    }
1278 	    if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1279 		switch (bitpos) {
1280 		case NFSATTRBIT_SUPPORTEDATTRS:
1281 			retnotsup = 0;
1282 			if (compare || nap == NULL)
1283 			    error = nfsrv_getattrbits(nd, &retattrbits,
1284 				&cnt, &retnotsup);
1285 			else
1286 			    error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1287 				&cnt, &retnotsup);
1288 			if (error)
1289 			    goto nfsmout;
1290 			if (compare && !(*retcmpp)) {
1291 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1292 
1293 			   /* Some filesystem do not support NFSv4ACL   */
1294 			   if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1295 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1296 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1297 		   	   }
1298 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1299 			       || retnotsup)
1300 				*retcmpp = NFSERR_NOTSAME;
1301 			}
1302 			attrsum += cnt;
1303 			break;
1304 		case NFSATTRBIT_TYPE:
1305 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1306 			if (compare) {
1307 				if (!(*retcmpp)) {
1308 				    if (nap->na_type != nfsv34tov_type(*tl))
1309 					*retcmpp = NFSERR_NOTSAME;
1310 				}
1311 			} else if (nap != NULL) {
1312 				nap->na_type = nfsv34tov_type(*tl);
1313 			}
1314 			attrsum += NFSX_UNSIGNED;
1315 			break;
1316 		case NFSATTRBIT_FHEXPIRETYPE:
1317 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1318 			if (compare && !(*retcmpp)) {
1319 				if (fxdr_unsigned(int, *tl) !=
1320 					NFSV4FHTYPE_PERSISTENT)
1321 					*retcmpp = NFSERR_NOTSAME;
1322 			}
1323 			attrsum += NFSX_UNSIGNED;
1324 			break;
1325 		case NFSATTRBIT_CHANGE:
1326 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1327 			if (compare) {
1328 				if (!(*retcmpp)) {
1329 				    if (nap->na_filerev != fxdr_hyper(tl))
1330 					*retcmpp = NFSERR_NOTSAME;
1331 				}
1332 			} else if (nap != NULL) {
1333 				nap->na_filerev = fxdr_hyper(tl);
1334 			}
1335 			attrsum += NFSX_HYPER;
1336 			break;
1337 		case NFSATTRBIT_SIZE:
1338 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1339 			if (compare) {
1340 				if (!(*retcmpp)) {
1341 				    if (nap->na_size != fxdr_hyper(tl))
1342 					*retcmpp = NFSERR_NOTSAME;
1343 				}
1344 			} else if (nap != NULL) {
1345 				nap->na_size = fxdr_hyper(tl);
1346 			}
1347 			attrsum += NFSX_HYPER;
1348 			break;
1349 		case NFSATTRBIT_LINKSUPPORT:
1350 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1351 			if (compare) {
1352 				if (!(*retcmpp)) {
1353 				    if (fsp->fs_properties & NFSV3_FSFLINK) {
1354 					if (*tl == newnfs_false)
1355 						*retcmpp = NFSERR_NOTSAME;
1356 				    } else {
1357 					if (*tl == newnfs_true)
1358 						*retcmpp = NFSERR_NOTSAME;
1359 				    }
1360 				}
1361 			} else if (fsp != NULL) {
1362 				if (*tl == newnfs_true)
1363 					fsp->fs_properties |= NFSV3_FSFLINK;
1364 				else
1365 					fsp->fs_properties &= ~NFSV3_FSFLINK;
1366 			}
1367 			attrsum += NFSX_UNSIGNED;
1368 			break;
1369 		case NFSATTRBIT_SYMLINKSUPPORT:
1370 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1371 			if (compare) {
1372 				if (!(*retcmpp)) {
1373 				    if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1374 					if (*tl == newnfs_false)
1375 						*retcmpp = NFSERR_NOTSAME;
1376 				    } else {
1377 					if (*tl == newnfs_true)
1378 						*retcmpp = NFSERR_NOTSAME;
1379 				    }
1380 				}
1381 			} else if (fsp != NULL) {
1382 				if (*tl == newnfs_true)
1383 					fsp->fs_properties |= NFSV3_FSFSYMLINK;
1384 				else
1385 					fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1386 			}
1387 			attrsum += NFSX_UNSIGNED;
1388 			break;
1389 		case NFSATTRBIT_NAMEDATTR:
1390 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1391 			if (compare && !(*retcmpp)) {
1392 				if (*tl != newnfs_false)
1393 					*retcmpp = NFSERR_NOTSAME;
1394 			}
1395 			attrsum += NFSX_UNSIGNED;
1396 			break;
1397 		case NFSATTRBIT_FSID:
1398 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1399 			thyp = fxdr_hyper(tl);
1400 			tl += 2;
1401 			thyp2 = fxdr_hyper(tl);
1402 			if (compare) {
1403 			    if (*retcmpp == 0) {
1404 				if (thyp != (u_int64_t)
1405 				    vp->v_mount->mnt_stat.f_fsid.val[0] ||
1406 				    thyp2 != (u_int64_t)
1407 				    vp->v_mount->mnt_stat.f_fsid.val[1])
1408 					*retcmpp = NFSERR_NOTSAME;
1409 			    }
1410 			} else if (nap != NULL) {
1411 				nap->na_filesid[0] = thyp;
1412 				nap->na_filesid[1] = thyp2;
1413 			}
1414 			attrsum += (4 * NFSX_UNSIGNED);
1415 			break;
1416 		case NFSATTRBIT_UNIQUEHANDLES:
1417 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1418 			if (compare && !(*retcmpp)) {
1419 				if (*tl != newnfs_true)
1420 					*retcmpp = NFSERR_NOTSAME;
1421 			}
1422 			attrsum += NFSX_UNSIGNED;
1423 			break;
1424 		case NFSATTRBIT_LEASETIME:
1425 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1426 			if (compare) {
1427 				if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1428 				    !(*retcmpp))
1429 					*retcmpp = NFSERR_NOTSAME;
1430 			} else if (leasep != NULL) {
1431 				*leasep = fxdr_unsigned(u_int32_t, *tl);
1432 			}
1433 			attrsum += NFSX_UNSIGNED;
1434 			break;
1435 		case NFSATTRBIT_RDATTRERROR:
1436 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1437 			if (compare) {
1438 				 if (!(*retcmpp))
1439 					*retcmpp = NFSERR_INVAL;
1440 			} else if (rderrp != NULL) {
1441 				*rderrp = fxdr_unsigned(u_int32_t, *tl);
1442 			}
1443 			attrsum += NFSX_UNSIGNED;
1444 			break;
1445 		case NFSATTRBIT_ACL:
1446 			if (compare) {
1447 			  if (!(*retcmpp)) {
1448 			    if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1449 				NFSACL_T *naclp;
1450 
1451 				naclp = acl_alloc(M_WAITOK);
1452 				error = nfsrv_dissectacl(nd, naclp, &aceerr,
1453 				    &cnt, p);
1454 				if (error) {
1455 				    acl_free(naclp);
1456 				    goto nfsmout;
1457 				}
1458 				if (aceerr || aclp == NULL ||
1459 				    nfsrv_compareacl(aclp, naclp))
1460 				    *retcmpp = NFSERR_NOTSAME;
1461 				acl_free(naclp);
1462 			    } else {
1463 				error = nfsrv_dissectacl(nd, NULL, &aceerr,
1464 				    &cnt, p);
1465 				*retcmpp = NFSERR_ATTRNOTSUPP;
1466 			    }
1467 			  }
1468 			} else {
1469 				if (vp != NULL && aclp != NULL)
1470 				    error = nfsrv_dissectacl(nd, aclp, &aceerr,
1471 					&cnt, p);
1472 				else
1473 				    error = nfsrv_dissectacl(nd, NULL, &aceerr,
1474 					&cnt, p);
1475 				if (error)
1476 				    goto nfsmout;
1477 			}
1478 
1479 			attrsum += cnt;
1480 			break;
1481 		case NFSATTRBIT_ACLSUPPORT:
1482 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1483 			if (compare && !(*retcmpp)) {
1484 				if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1485 					if (fxdr_unsigned(u_int32_t, *tl) !=
1486 					    NFSV4ACE_SUPTYPES)
1487 						*retcmpp = NFSERR_NOTSAME;
1488 				} else {
1489 					*retcmpp = NFSERR_ATTRNOTSUPP;
1490 				}
1491 			}
1492 			attrsum += NFSX_UNSIGNED;
1493 			break;
1494 		case NFSATTRBIT_ARCHIVE:
1495 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1496 			if (compare && !(*retcmpp))
1497 				*retcmpp = NFSERR_ATTRNOTSUPP;
1498 			attrsum += NFSX_UNSIGNED;
1499 			break;
1500 		case NFSATTRBIT_CANSETTIME:
1501 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1502 			if (compare) {
1503 				if (!(*retcmpp)) {
1504 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1505 					if (*tl == newnfs_false)
1506 						*retcmpp = NFSERR_NOTSAME;
1507 				    } else {
1508 					if (*tl == newnfs_true)
1509 						*retcmpp = NFSERR_NOTSAME;
1510 				    }
1511 				}
1512 			} else if (fsp != NULL) {
1513 				if (*tl == newnfs_true)
1514 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1515 				else
1516 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1517 			}
1518 			attrsum += NFSX_UNSIGNED;
1519 			break;
1520 		case NFSATTRBIT_CASEINSENSITIVE:
1521 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1522 			if (compare) {
1523 				if (!(*retcmpp)) {
1524 				    if (*tl != newnfs_false)
1525 					*retcmpp = NFSERR_NOTSAME;
1526 				}
1527 			} else if (pc != NULL) {
1528 				pc->pc_caseinsensitive =
1529 				    fxdr_unsigned(u_int32_t, *tl);
1530 			}
1531 			attrsum += NFSX_UNSIGNED;
1532 			break;
1533 		case NFSATTRBIT_CASEPRESERVING:
1534 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1535 			if (compare) {
1536 				if (!(*retcmpp)) {
1537 				    if (*tl != newnfs_true)
1538 					*retcmpp = NFSERR_NOTSAME;
1539 				}
1540 			} else if (pc != NULL) {
1541 				pc->pc_casepreserving =
1542 				    fxdr_unsigned(u_int32_t, *tl);
1543 			}
1544 			attrsum += NFSX_UNSIGNED;
1545 			break;
1546 		case NFSATTRBIT_CHOWNRESTRICTED:
1547 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1548 			if (compare) {
1549 				if (!(*retcmpp)) {
1550 				    if (*tl != newnfs_true)
1551 					*retcmpp = NFSERR_NOTSAME;
1552 				}
1553 			} else if (pc != NULL) {
1554 				pc->pc_chownrestricted =
1555 				    fxdr_unsigned(u_int32_t, *tl);
1556 			}
1557 			attrsum += NFSX_UNSIGNED;
1558 			break;
1559 		case NFSATTRBIT_FILEHANDLE:
1560 			error = nfsm_getfh(nd, &tnfhp);
1561 			if (error)
1562 				goto nfsmout;
1563 			tfhsize = tnfhp->nfh_len;
1564 			if (compare) {
1565 				if (!(*retcmpp) &&
1566 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1567 				     fhp, fhsize))
1568 					*retcmpp = NFSERR_NOTSAME;
1569 				free(tnfhp, M_NFSFH);
1570 			} else if (nfhpp != NULL) {
1571 				*nfhpp = tnfhp;
1572 			} else {
1573 				free(tnfhp, M_NFSFH);
1574 			}
1575 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1576 			break;
1577 		case NFSATTRBIT_FILEID:
1578 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1579 			thyp = fxdr_hyper(tl);
1580 			if (compare) {
1581 				if (!(*retcmpp)) {
1582 					if (nap->na_fileid != thyp)
1583 						*retcmpp = NFSERR_NOTSAME;
1584 				}
1585 			} else if (nap != NULL)
1586 				nap->na_fileid = thyp;
1587 			attrsum += NFSX_HYPER;
1588 			break;
1589 		case NFSATTRBIT_FILESAVAIL:
1590 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1591 			if (compare) {
1592 				if (!(*retcmpp) &&
1593 				    sfp->sf_afiles != fxdr_hyper(tl))
1594 					*retcmpp = NFSERR_NOTSAME;
1595 			} else if (sfp != NULL) {
1596 				sfp->sf_afiles = fxdr_hyper(tl);
1597 			}
1598 			attrsum += NFSX_HYPER;
1599 			break;
1600 		case NFSATTRBIT_FILESFREE:
1601 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1602 			if (compare) {
1603 				if (!(*retcmpp) &&
1604 				    sfp->sf_ffiles != fxdr_hyper(tl))
1605 					*retcmpp = NFSERR_NOTSAME;
1606 			} else if (sfp != NULL) {
1607 				sfp->sf_ffiles = fxdr_hyper(tl);
1608 			}
1609 			attrsum += NFSX_HYPER;
1610 			break;
1611 		case NFSATTRBIT_FILESTOTAL:
1612 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1613 			if (compare) {
1614 				if (!(*retcmpp) &&
1615 				    sfp->sf_tfiles != fxdr_hyper(tl))
1616 					*retcmpp = NFSERR_NOTSAME;
1617 			} else if (sfp != NULL) {
1618 				sfp->sf_tfiles = fxdr_hyper(tl);
1619 			}
1620 			attrsum += NFSX_HYPER;
1621 			break;
1622 		case NFSATTRBIT_FSLOCATIONS:
1623 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1624 			if (error)
1625 				goto nfsmout;
1626 			attrsum += l;
1627 			if (compare && !(*retcmpp)) {
1628 				refp = nfsv4root_getreferral(vp, NULL, 0);
1629 				if (refp != NULL) {
1630 					if (cp == NULL || cp2 == NULL ||
1631 					    strcmp(cp, "/") ||
1632 					    strcmp(cp2, refp->nfr_srvlist))
1633 						*retcmpp = NFSERR_NOTSAME;
1634 				} else if (m == 0) {
1635 					*retcmpp = NFSERR_NOTSAME;
1636 				}
1637 			}
1638 			if (cp != NULL)
1639 				free(cp, M_NFSSTRING);
1640 			if (cp2 != NULL)
1641 				free(cp2, M_NFSSTRING);
1642 			break;
1643 		case NFSATTRBIT_HIDDEN:
1644 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1645 			if (compare && !(*retcmpp))
1646 				*retcmpp = NFSERR_ATTRNOTSUPP;
1647 			attrsum += NFSX_UNSIGNED;
1648 			break;
1649 		case NFSATTRBIT_HOMOGENEOUS:
1650 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1651 			if (compare) {
1652 				if (!(*retcmpp)) {
1653 				    if (fsp->fs_properties &
1654 					NFSV3_FSFHOMOGENEOUS) {
1655 					if (*tl == newnfs_false)
1656 						*retcmpp = NFSERR_NOTSAME;
1657 				    } else {
1658 					if (*tl == newnfs_true)
1659 						*retcmpp = NFSERR_NOTSAME;
1660 				    }
1661 				}
1662 			} else if (fsp != NULL) {
1663 				if (*tl == newnfs_true)
1664 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1665 				else
1666 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1667 			}
1668 			attrsum += NFSX_UNSIGNED;
1669 			break;
1670 		case NFSATTRBIT_MAXFILESIZE:
1671 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1672 			tnfsquad.qval = fxdr_hyper(tl);
1673 			if (compare) {
1674 				if (!(*retcmpp)) {
1675 					tquad = NFSRV_MAXFILESIZE;
1676 					if (tquad != tnfsquad.qval)
1677 						*retcmpp = NFSERR_NOTSAME;
1678 				}
1679 			} else if (fsp != NULL) {
1680 				fsp->fs_maxfilesize = tnfsquad.qval;
1681 			}
1682 			attrsum += NFSX_HYPER;
1683 			break;
1684 		case NFSATTRBIT_MAXLINK:
1685 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1686 			if (compare) {
1687 				if (!(*retcmpp)) {
1688 				    if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1689 					*retcmpp = NFSERR_NOTSAME;
1690 				}
1691 			} else if (pc != NULL) {
1692 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1693 			}
1694 			attrsum += NFSX_UNSIGNED;
1695 			break;
1696 		case NFSATTRBIT_MAXNAME:
1697 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1698 			if (compare) {
1699 				if (!(*retcmpp)) {
1700 				    if (fsp->fs_maxname !=
1701 					fxdr_unsigned(u_int32_t, *tl))
1702 						*retcmpp = NFSERR_NOTSAME;
1703 				}
1704 			} else {
1705 				tuint = fxdr_unsigned(u_int32_t, *tl);
1706 				/*
1707 				 * Some Linux NFSv4 servers report this
1708 				 * as 0 or 4billion, so I'll set it to
1709 				 * NFS_MAXNAMLEN. If a server actually creates
1710 				 * a name longer than NFS_MAXNAMLEN, it will
1711 				 * get an error back.
1712 				 */
1713 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1714 					tuint = NFS_MAXNAMLEN;
1715 				if (fsp != NULL)
1716 					fsp->fs_maxname = tuint;
1717 				if (pc != NULL)
1718 					pc->pc_namemax = tuint;
1719 			}
1720 			attrsum += NFSX_UNSIGNED;
1721 			break;
1722 		case NFSATTRBIT_MAXREAD:
1723 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1724 			if (compare) {
1725 				if (!(*retcmpp)) {
1726 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1727 					*(tl + 1)) || *tl != 0)
1728 					*retcmpp = NFSERR_NOTSAME;
1729 				}
1730 			} else if (fsp != NULL) {
1731 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1732 				fsp->fs_rtpref = fsp->fs_rtmax;
1733 				fsp->fs_dtpref = fsp->fs_rtpref;
1734 			}
1735 			attrsum += NFSX_HYPER;
1736 			break;
1737 		case NFSATTRBIT_MAXWRITE:
1738 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1739 			if (compare) {
1740 				if (!(*retcmpp)) {
1741 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1742 					*(tl + 1)) || *tl != 0)
1743 					*retcmpp = NFSERR_NOTSAME;
1744 				}
1745 			} else if (fsp != NULL) {
1746 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1747 				fsp->fs_wtpref = fsp->fs_wtmax;
1748 			}
1749 			attrsum += NFSX_HYPER;
1750 			break;
1751 		case NFSATTRBIT_MIMETYPE:
1752 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1753 			i = fxdr_unsigned(int, *tl);
1754 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1755 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1756 			if (error)
1757 				goto nfsmout;
1758 			if (compare && !(*retcmpp))
1759 				*retcmpp = NFSERR_ATTRNOTSUPP;
1760 			break;
1761 		case NFSATTRBIT_MODE:
1762 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1763 			if (compare) {
1764 				if (!(*retcmpp)) {
1765 				    if (nap->na_mode != nfstov_mode(*tl))
1766 					*retcmpp = NFSERR_NOTSAME;
1767 				}
1768 			} else if (nap != NULL) {
1769 				nap->na_mode = nfstov_mode(*tl);
1770 			}
1771 			attrsum += NFSX_UNSIGNED;
1772 			break;
1773 		case NFSATTRBIT_NOTRUNC:
1774 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1775 			if (compare) {
1776 				if (!(*retcmpp)) {
1777 				    if (*tl != newnfs_true)
1778 					*retcmpp = NFSERR_NOTSAME;
1779 				}
1780 			} else if (pc != NULL) {
1781 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1782 			}
1783 			attrsum += NFSX_UNSIGNED;
1784 			break;
1785 		case NFSATTRBIT_NUMLINKS:
1786 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1787 			tuint = fxdr_unsigned(u_int32_t, *tl);
1788 			if (compare) {
1789 			    if (!(*retcmpp)) {
1790 				if ((u_int32_t)nap->na_nlink != tuint)
1791 					*retcmpp = NFSERR_NOTSAME;
1792 			    }
1793 			} else if (nap != NULL) {
1794 				nap->na_nlink = tuint;
1795 			}
1796 			attrsum += NFSX_UNSIGNED;
1797 			break;
1798 		case NFSATTRBIT_OWNER:
1799 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1800 			j = fxdr_unsigned(int, *tl);
1801 			if (j < 0) {
1802 				error = NFSERR_BADXDR;
1803 				goto nfsmout;
1804 			}
1805 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1806 			if (j > NFSV4_SMALLSTR)
1807 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1808 			else
1809 				cp = namestr;
1810 			error = nfsrv_mtostr(nd, cp, j);
1811 			if (error) {
1812 				if (j > NFSV4_SMALLSTR)
1813 					free(cp, M_NFSSTRING);
1814 				goto nfsmout;
1815 			}
1816 			if (compare) {
1817 			    if (!(*retcmpp)) {
1818 				if (nfsv4_strtouid(nd, cp, j, &uid) ||
1819 				    nap->na_uid != uid)
1820 				    *retcmpp = NFSERR_NOTSAME;
1821 			    }
1822 			} else if (nap != NULL) {
1823 				if (nfsv4_strtouid(nd, cp, j, &uid))
1824 					nap->na_uid = nfsrv_defaultuid;
1825 				else
1826 					nap->na_uid = uid;
1827 			}
1828 			if (j > NFSV4_SMALLSTR)
1829 				free(cp, M_NFSSTRING);
1830 			break;
1831 		case NFSATTRBIT_OWNERGROUP:
1832 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1833 			j = fxdr_unsigned(int, *tl);
1834 			if (j < 0) {
1835 				error =  NFSERR_BADXDR;
1836 				goto nfsmout;
1837 			}
1838 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1839 			if (j > NFSV4_SMALLSTR)
1840 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1841 			else
1842 				cp = namestr;
1843 			error = nfsrv_mtostr(nd, cp, j);
1844 			if (error) {
1845 				if (j > NFSV4_SMALLSTR)
1846 					free(cp, M_NFSSTRING);
1847 				goto nfsmout;
1848 			}
1849 			if (compare) {
1850 			    if (!(*retcmpp)) {
1851 				if (nfsv4_strtogid(nd, cp, j, &gid) ||
1852 				    nap->na_gid != gid)
1853 				    *retcmpp = NFSERR_NOTSAME;
1854 			    }
1855 			} else if (nap != NULL) {
1856 				if (nfsv4_strtogid(nd, cp, j, &gid))
1857 					nap->na_gid = nfsrv_defaultgid;
1858 				else
1859 					nap->na_gid = gid;
1860 			}
1861 			if (j > NFSV4_SMALLSTR)
1862 				free(cp, M_NFSSTRING);
1863 			break;
1864 		case NFSATTRBIT_QUOTAHARD:
1865 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1866 			if (sbp != NULL) {
1867 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1868 				freenum = sbp->f_bfree;
1869 			    else
1870 				freenum = sbp->f_bavail;
1871 #ifdef QUOTA
1872 			    /*
1873 			     * ufs_quotactl() insists that the uid argument
1874 			     * equal p_ruid for non-root quota access, so
1875 			     * we'll just make sure that's the case.
1876 			     */
1877 			    savuid = p->p_cred->p_ruid;
1878 			    p->p_cred->p_ruid = cred->cr_uid;
1879 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1880 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1881 				freenum = min(dqb.dqb_bhardlimit, freenum);
1882 			    p->p_cred->p_ruid = savuid;
1883 #endif	/* QUOTA */
1884 			    uquad = (u_int64_t)freenum;
1885 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1886 			}
1887 			if (compare && !(*retcmpp)) {
1888 				if (uquad != fxdr_hyper(tl))
1889 					*retcmpp = NFSERR_NOTSAME;
1890 			}
1891 			attrsum += NFSX_HYPER;
1892 			break;
1893 		case NFSATTRBIT_QUOTASOFT:
1894 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1895 			if (sbp != NULL) {
1896 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1897 				freenum = sbp->f_bfree;
1898 			    else
1899 				freenum = sbp->f_bavail;
1900 #ifdef QUOTA
1901 			    /*
1902 			     * ufs_quotactl() insists that the uid argument
1903 			     * equal p_ruid for non-root quota access, so
1904 			     * we'll just make sure that's the case.
1905 			     */
1906 			    savuid = p->p_cred->p_ruid;
1907 			    p->p_cred->p_ruid = cred->cr_uid;
1908 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1909 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1910 				freenum = min(dqb.dqb_bsoftlimit, freenum);
1911 			    p->p_cred->p_ruid = savuid;
1912 #endif	/* QUOTA */
1913 			    uquad = (u_int64_t)freenum;
1914 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1915 			}
1916 			if (compare && !(*retcmpp)) {
1917 				if (uquad != fxdr_hyper(tl))
1918 					*retcmpp = NFSERR_NOTSAME;
1919 			}
1920 			attrsum += NFSX_HYPER;
1921 			break;
1922 		case NFSATTRBIT_QUOTAUSED:
1923 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1924 			if (sbp != NULL) {
1925 			    freenum = 0;
1926 #ifdef QUOTA
1927 			    /*
1928 			     * ufs_quotactl() insists that the uid argument
1929 			     * equal p_ruid for non-root quota access, so
1930 			     * we'll just make sure that's the case.
1931 			     */
1932 			    savuid = p->p_cred->p_ruid;
1933 			    p->p_cred->p_ruid = cred->cr_uid;
1934 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1935 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1936 				freenum = dqb.dqb_curblocks;
1937 			    p->p_cred->p_ruid = savuid;
1938 #endif	/* QUOTA */
1939 			    uquad = (u_int64_t)freenum;
1940 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1941 			}
1942 			if (compare && !(*retcmpp)) {
1943 				if (uquad != fxdr_hyper(tl))
1944 					*retcmpp = NFSERR_NOTSAME;
1945 			}
1946 			attrsum += NFSX_HYPER;
1947 			break;
1948 		case NFSATTRBIT_RAWDEV:
1949 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1950 			j = fxdr_unsigned(int, *tl++);
1951 			k = fxdr_unsigned(int, *tl);
1952 			if (compare) {
1953 			    if (!(*retcmpp)) {
1954 				if (nap->na_rdev != NFSMAKEDEV(j, k))
1955 					*retcmpp = NFSERR_NOTSAME;
1956 			    }
1957 			} else if (nap != NULL) {
1958 				nap->na_rdev = NFSMAKEDEV(j, k);
1959 			}
1960 			attrsum += NFSX_V4SPECDATA;
1961 			break;
1962 		case NFSATTRBIT_SPACEAVAIL:
1963 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1964 			if (compare) {
1965 				if (!(*retcmpp) &&
1966 				    sfp->sf_abytes != fxdr_hyper(tl))
1967 					*retcmpp = NFSERR_NOTSAME;
1968 			} else if (sfp != NULL) {
1969 				sfp->sf_abytes = fxdr_hyper(tl);
1970 			}
1971 			attrsum += NFSX_HYPER;
1972 			break;
1973 		case NFSATTRBIT_SPACEFREE:
1974 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1975 			if (compare) {
1976 				if (!(*retcmpp) &&
1977 				    sfp->sf_fbytes != fxdr_hyper(tl))
1978 					*retcmpp = NFSERR_NOTSAME;
1979 			} else if (sfp != NULL) {
1980 				sfp->sf_fbytes = fxdr_hyper(tl);
1981 			}
1982 			attrsum += NFSX_HYPER;
1983 			break;
1984 		case NFSATTRBIT_SPACETOTAL:
1985 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1986 			if (compare) {
1987 				if (!(*retcmpp) &&
1988 				    sfp->sf_tbytes != fxdr_hyper(tl))
1989 					*retcmpp = NFSERR_NOTSAME;
1990 			} else if (sfp != NULL) {
1991 				sfp->sf_tbytes = fxdr_hyper(tl);
1992 			}
1993 			attrsum += NFSX_HYPER;
1994 			break;
1995 		case NFSATTRBIT_SPACEUSED:
1996 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1997 			thyp = fxdr_hyper(tl);
1998 			if (compare) {
1999 			    if (!(*retcmpp)) {
2000 				if ((u_int64_t)nap->na_bytes != thyp)
2001 					*retcmpp = NFSERR_NOTSAME;
2002 			    }
2003 			} else if (nap != NULL) {
2004 				nap->na_bytes = thyp;
2005 			}
2006 			attrsum += NFSX_HYPER;
2007 			break;
2008 		case NFSATTRBIT_SYSTEM:
2009 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2010 			if (compare && !(*retcmpp))
2011 				*retcmpp = NFSERR_ATTRNOTSUPP;
2012 			attrsum += NFSX_UNSIGNED;
2013 			break;
2014 		case NFSATTRBIT_TIMEACCESS:
2015 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2016 			fxdr_nfsv4time(tl, &temptime);
2017 			if (compare) {
2018 			    if (!(*retcmpp)) {
2019 				if (!NFS_CMPTIME(temptime, nap->na_atime))
2020 					*retcmpp = NFSERR_NOTSAME;
2021 			    }
2022 			} else if (nap != NULL) {
2023 				nap->na_atime = temptime;
2024 			}
2025 			attrsum += NFSX_V4TIME;
2026 			break;
2027 		case NFSATTRBIT_TIMEACCESSSET:
2028 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2029 			attrsum += NFSX_UNSIGNED;
2030 			i = fxdr_unsigned(int, *tl);
2031 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2032 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2033 				attrsum += NFSX_V4TIME;
2034 			}
2035 			if (compare && !(*retcmpp))
2036 				*retcmpp = NFSERR_INVAL;
2037 			break;
2038 		case NFSATTRBIT_TIMEBACKUP:
2039 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2040 			if (compare && !(*retcmpp))
2041 				*retcmpp = NFSERR_ATTRNOTSUPP;
2042 			attrsum += NFSX_V4TIME;
2043 			break;
2044 		case NFSATTRBIT_TIMECREATE:
2045 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2046 			if (compare && !(*retcmpp))
2047 				*retcmpp = NFSERR_ATTRNOTSUPP;
2048 			attrsum += NFSX_V4TIME;
2049 			break;
2050 		case NFSATTRBIT_TIMEDELTA:
2051 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2052 			if (fsp != NULL) {
2053 			    if (compare) {
2054 				if (!(*retcmpp)) {
2055 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2056 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2057 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2058 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
2059 					 1000000000) ||
2060 					*tl != 0)
2061 					    *retcmpp = NFSERR_NOTSAME;
2062 				}
2063 			    } else {
2064 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2065 			    }
2066 			}
2067 			attrsum += NFSX_V4TIME;
2068 			break;
2069 		case NFSATTRBIT_TIMEMETADATA:
2070 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2071 			fxdr_nfsv4time(tl, &temptime);
2072 			if (compare) {
2073 			    if (!(*retcmpp)) {
2074 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
2075 					*retcmpp = NFSERR_NOTSAME;
2076 			    }
2077 			} else if (nap != NULL) {
2078 				nap->na_ctime = temptime;
2079 			}
2080 			attrsum += NFSX_V4TIME;
2081 			break;
2082 		case NFSATTRBIT_TIMEMODIFY:
2083 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2084 			fxdr_nfsv4time(tl, &temptime);
2085 			if (compare) {
2086 			    if (!(*retcmpp)) {
2087 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
2088 					*retcmpp = NFSERR_NOTSAME;
2089 			    }
2090 			} else if (nap != NULL) {
2091 				nap->na_mtime = temptime;
2092 			}
2093 			attrsum += NFSX_V4TIME;
2094 			break;
2095 		case NFSATTRBIT_TIMEMODIFYSET:
2096 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2097 			attrsum += NFSX_UNSIGNED;
2098 			i = fxdr_unsigned(int, *tl);
2099 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2100 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2101 				attrsum += NFSX_V4TIME;
2102 			}
2103 			if (compare && !(*retcmpp))
2104 				*retcmpp = NFSERR_INVAL;
2105 			break;
2106 		case NFSATTRBIT_MOUNTEDONFILEID:
2107 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2108 			thyp = fxdr_hyper(tl);
2109 			if (compare) {
2110 				if (!(*retcmpp)) {
2111 					if (!vp || !nfsrv_atroot(vp, &thyp2))
2112 						thyp2 = nap->na_fileid;
2113 					if (thyp2 != thyp)
2114 						*retcmpp = NFSERR_NOTSAME;
2115 				}
2116 			} else if (nap != NULL)
2117 				nap->na_mntonfileno = thyp;
2118 			attrsum += NFSX_HYPER;
2119 			break;
2120 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2121 			retnotsup = 0;
2122 			error = nfsrv_getattrbits(nd, &retattrbits,
2123 			    &cnt, &retnotsup);
2124 			if (error)
2125 			    goto nfsmout;
2126 			if (compare && !(*retcmpp)) {
2127 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2128 			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2129 			   NFSCLRBIT_ATTRBIT(&checkattrbits,
2130 				NFSATTRBIT_TIMEACCESSSET);
2131 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2132 			       || retnotsup)
2133 				*retcmpp = NFSERR_NOTSAME;
2134 			}
2135 			attrsum += cnt;
2136 			break;
2137 		case NFSATTRBIT_FSLAYOUTTYPE:
2138 		case NFSATTRBIT_LAYOUTTYPE:
2139 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2140 			attrsum += NFSX_UNSIGNED;
2141 			i = fxdr_unsigned(int, *tl);
2142 			if (i > 0) {
2143 				NFSM_DISSECT(tl, u_int32_t *, i *
2144 				    NFSX_UNSIGNED);
2145 				attrsum += i * NFSX_UNSIGNED;
2146 				j = fxdr_unsigned(int, *tl);
2147 				if (i == 1 && compare && !(*retcmpp) &&
2148 				    (((nfsrv_doflexfile != 0 ||
2149 				       nfsrv_maxpnfsmirror > 1) &&
2150 				      j != NFSLAYOUT_FLEXFILE) ||
2151 				    (nfsrv_doflexfile == 0 &&
2152 				     j != NFSLAYOUT_NFSV4_1_FILES)))
2153 					*retcmpp = NFSERR_NOTSAME;
2154 			}
2155 			if (nfsrv_devidcnt == 0) {
2156 				if (compare && !(*retcmpp) && i > 0)
2157 					*retcmpp = NFSERR_NOTSAME;
2158 			} else {
2159 				if (compare && !(*retcmpp) && i != 1)
2160 					*retcmpp = NFSERR_NOTSAME;
2161 			}
2162 			break;
2163 		case NFSATTRBIT_LAYOUTALIGNMENT:
2164 		case NFSATTRBIT_LAYOUTBLKSIZE:
2165 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2166 			attrsum += NFSX_UNSIGNED;
2167 			i = fxdr_unsigned(int, *tl);
2168 			if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2169 				*retcmpp = NFSERR_NOTSAME;
2170 			break;
2171 		default:
2172 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2173 				bitpos);
2174 			if (compare && !(*retcmpp))
2175 				*retcmpp = NFSERR_ATTRNOTSUPP;
2176 			/*
2177 			 * and get out of the loop, since we can't parse
2178 			 * the unknown attrbute data.
2179 			 */
2180 			bitpos = NFSATTRBIT_MAX;
2181 			break;
2182 		}
2183 	}
2184 
2185 	/*
2186 	 * some clients pad the attrlist, so we need to skip over the
2187 	 * padding.
2188 	 */
2189 	if (attrsum > attrsize) {
2190 		error = NFSERR_BADXDR;
2191 	} else {
2192 		attrsize = NFSM_RNDUP(attrsize);
2193 		if (attrsum < attrsize)
2194 			error = nfsm_advance(nd, attrsize - attrsum, -1);
2195 	}
2196 nfsmout:
2197 	NFSEXITCODE2(error, nd);
2198 	return (error);
2199 }
2200 
2201 /*
2202  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2203  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2204  * The first argument is a pointer to an nfsv4lock structure.
2205  * The second argument is 1 iff a blocking lock is wanted.
2206  * If this argument is 0, the call waits until no thread either wants nor
2207  * holds an exclusive lock.
2208  * It returns 1 if the lock was acquired, 0 otherwise.
2209  * If several processes call this function concurrently wanting the exclusive
2210  * lock, one will get the lock and the rest will return without getting the
2211  * lock. (If the caller must have the lock, it simply calls this function in a
2212  *  loop until the function returns 1 to indicate the lock was acquired.)
2213  * Any usecnt must be decremented by calling nfsv4_relref() before
2214  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2215  * be called in a loop.
2216  * The isleptp argument is set to indicate if the call slept, iff not NULL
2217  * and the mp argument indicates to check for a forced dismount, iff not
2218  * NULL.
2219  */
2220 int
2221 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2222     void *mutex, struct mount *mp)
2223 {
2224 
2225 	if (isleptp)
2226 		*isleptp = 0;
2227 	/*
2228 	 * If a lock is wanted, loop around until the lock is acquired by
2229 	 * someone and then released. If I want the lock, try to acquire it.
2230 	 * For a lock to be issued, no lock must be in force and the usecnt
2231 	 * must be zero.
2232 	 */
2233 	if (iwantlock) {
2234 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2235 		lp->nfslock_usecnt == 0) {
2236 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2237 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
2238 		return (1);
2239 	    }
2240 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2241 	}
2242 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2243 		if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2244 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2245 			return (0);
2246 		}
2247 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2248 		if (isleptp)
2249 			*isleptp = 1;
2250 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
2251 		    PZERO - 1, "nfsv4lck", NULL);
2252 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2253 		    lp->nfslock_usecnt == 0) {
2254 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2255 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
2256 			return (1);
2257 		}
2258 	}
2259 	return (0);
2260 }
2261 
2262 /*
2263  * Release the lock acquired by nfsv4_lock().
2264  * The second argument is set to 1 to indicate the nfslock_usecnt should be
2265  * incremented, as well.
2266  */
2267 void
2268 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2269 {
2270 
2271 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2272 	if (incref)
2273 		lp->nfslock_usecnt++;
2274 	nfsv4_wanted(lp);
2275 }
2276 
2277 /*
2278  * Release a reference cnt.
2279  */
2280 void
2281 nfsv4_relref(struct nfsv4lock *lp)
2282 {
2283 
2284 	if (lp->nfslock_usecnt <= 0)
2285 		panic("nfsv4root ref cnt");
2286 	lp->nfslock_usecnt--;
2287 	if (lp->nfslock_usecnt == 0)
2288 		nfsv4_wanted(lp);
2289 }
2290 
2291 /*
2292  * Get a reference cnt.
2293  * This function will wait for any exclusive lock to be released, but will
2294  * not wait for threads that want the exclusive lock. If priority needs
2295  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2296  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2297  * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2298  * return without getting a refcnt for that case.
2299  */
2300 void
2301 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2302     struct mount *mp)
2303 {
2304 
2305 	if (isleptp)
2306 		*isleptp = 0;
2307 
2308 	/*
2309 	 * Wait for a lock held.
2310 	 */
2311 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2312 		if (mp != NULL && NFSCL_FORCEDISM(mp))
2313 			return;
2314 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2315 		if (isleptp)
2316 			*isleptp = 1;
2317 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
2318 		    PZERO - 1, "nfsv4gr", NULL);
2319 	}
2320 	if (mp != NULL && NFSCL_FORCEDISM(mp))
2321 		return;
2322 
2323 	lp->nfslock_usecnt++;
2324 }
2325 
2326 /*
2327  * Get a reference as above, but return failure instead of sleeping if
2328  * an exclusive lock is held.
2329  */
2330 int
2331 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2332 {
2333 
2334 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2335 		return (0);
2336 
2337 	lp->nfslock_usecnt++;
2338 	return (1);
2339 }
2340 
2341 /*
2342  * Test for a lock. Return 1 if locked, 0 otherwise.
2343  */
2344 int
2345 nfsv4_testlock(struct nfsv4lock *lp)
2346 {
2347 
2348 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2349 	    lp->nfslock_usecnt == 0)
2350 		return (0);
2351 	return (1);
2352 }
2353 
2354 /*
2355  * Wake up anyone sleeping, waiting for this lock.
2356  */
2357 static void
2358 nfsv4_wanted(struct nfsv4lock *lp)
2359 {
2360 
2361 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2362 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2363 		wakeup((caddr_t)&lp->nfslock_lock);
2364 	}
2365 }
2366 
2367 /*
2368  * Copy a string from an mbuf list into a character array.
2369  * Return EBADRPC if there is an mbuf error,
2370  * 0 otherwise.
2371  */
2372 int
2373 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2374 {
2375 	char *cp;
2376 	int xfer, len;
2377 	struct mbuf *mp;
2378 	int rem, error = 0;
2379 
2380 	mp = nd->nd_md;
2381 	cp = nd->nd_dpos;
2382 	len = mtod(mp, caddr_t) + mp->m_len - cp;
2383 	rem = NFSM_RNDUP(siz) - siz;
2384 	while (siz > 0) {
2385 		if (len > siz)
2386 			xfer = siz;
2387 		else
2388 			xfer = len;
2389 		NFSBCOPY(cp, str, xfer);
2390 		str += xfer;
2391 		siz -= xfer;
2392 		if (siz > 0) {
2393 			mp = mp->m_next;
2394 			if (mp == NULL) {
2395 				error = EBADRPC;
2396 				goto out;
2397 			}
2398 			cp = mtod(mp, caddr_t);
2399 			len = mp->m_len;
2400 		} else {
2401 			cp += xfer;
2402 			len -= xfer;
2403 		}
2404 	}
2405 	*str = '\0';
2406 	nd->nd_dpos = cp;
2407 	nd->nd_md = mp;
2408 	if (rem > 0) {
2409 		if (len < rem)
2410 			error = nfsm_advance(nd, rem, len);
2411 		else
2412 			nd->nd_dpos += rem;
2413 	}
2414 
2415 out:
2416 	NFSEXITCODE2(error, nd);
2417 	return (error);
2418 }
2419 
2420 /*
2421  * Fill in the attributes as marked by the bitmap (V4).
2422  */
2423 int
2424 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2425     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2426     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2427     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2428     struct statfs *pnfssf)
2429 {
2430 	int bitpos, retnum = 0;
2431 	u_int32_t *tl;
2432 	int siz, prefixnum, error;
2433 	u_char *cp, namestr[NFSV4_SMALLSTR];
2434 	nfsattrbit_t attrbits, retbits;
2435 	nfsattrbit_t *retbitp = &retbits;
2436 	u_int32_t freenum, *retnump;
2437 	u_int64_t uquad;
2438 	struct statfs *fs;
2439 	struct nfsfsinfo fsinf;
2440 	struct timespec temptime;
2441 	NFSACL_T *aclp, *naclp = NULL;
2442 	size_t atsiz;
2443 	bool xattrsupp;
2444 #ifdef QUOTA
2445 	struct dqblk dqb;
2446 	uid_t savuid;
2447 #endif
2448 
2449 	/*
2450 	 * First, set the bits that can be filled and get fsinfo.
2451 	 */
2452 	NFSSET_ATTRBIT(retbitp, attrbitp);
2453 	/*
2454 	 * If both p and cred are NULL, it is a client side setattr call.
2455 	 * If both p and cred are not NULL, it is a server side reply call.
2456 	 * If p is not NULL and cred is NULL, it is a client side callback
2457 	 * reply call.
2458 	 */
2459 	if (p == NULL && cred == NULL) {
2460 		NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2461 		aclp = saclp;
2462 	} else {
2463 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2464 		naclp = acl_alloc(M_WAITOK);
2465 		aclp = naclp;
2466 	}
2467 	nfsvno_getfs(&fsinf, isdgram);
2468 #ifndef APPLE
2469 	/*
2470 	 * Get the VFS_STATFS(), since some attributes need them.
2471 	 */
2472 	fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2473 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2474 		error = VFS_STATFS(mp, fs);
2475 		if (error != 0) {
2476 			if (reterr) {
2477 				nd->nd_repstat = NFSERR_ACCES;
2478 				free(fs, M_STATFS);
2479 				return (0);
2480 			}
2481 			NFSCLRSTATFS_ATTRBIT(retbitp);
2482 		}
2483 	}
2484 #endif
2485 
2486 	/*
2487 	 * And the NFSv4 ACL...
2488 	 */
2489 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2490 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2491 		supports_nfsv4acls == 0))) {
2492 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2493 	}
2494 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2495 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2496 		    supports_nfsv4acls == 0)) {
2497 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2498 		} else if (naclp != NULL) {
2499 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2500 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2501 				if (error == 0)
2502 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2503 					    naclp, cred, p);
2504 				NFSVOPUNLOCK(vp);
2505 			} else
2506 				error = NFSERR_PERM;
2507 			if (error != 0) {
2508 				if (reterr) {
2509 					nd->nd_repstat = NFSERR_ACCES;
2510 					free(fs, M_STATFS);
2511 					return (0);
2512 				}
2513 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2514 			}
2515 		}
2516 	}
2517 
2518 	/* Check to see if Extended Attributes are supported. */
2519 	xattrsupp = false;
2520 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2521 		if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2522 			error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2523 			    "xxx", NULL, &atsiz, cred, p);
2524 			NFSVOPUNLOCK(vp);
2525 			if (error != EOPNOTSUPP)
2526 				xattrsupp = true;
2527 		}
2528 	}
2529 
2530 	/*
2531 	 * Put out the attribute bitmap for the ones being filled in
2532 	 * and get the field for the number of attributes returned.
2533 	 */
2534 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2535 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2536 	prefixnum += NFSX_UNSIGNED;
2537 
2538 	/*
2539 	 * Now, loop around filling in the attributes for each bit set.
2540 	 */
2541 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2542 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2543 		switch (bitpos) {
2544 		case NFSATTRBIT_SUPPORTEDATTRS:
2545 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2546 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2547 			    && supports_nfsv4acls == 0)) {
2548 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2549 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2550 			}
2551 			retnum += nfsrv_putattrbit(nd, &attrbits);
2552 			break;
2553 		case NFSATTRBIT_TYPE:
2554 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2555 			*tl = vtonfsv34_type(vap->va_type);
2556 			retnum += NFSX_UNSIGNED;
2557 			break;
2558 		case NFSATTRBIT_FHEXPIRETYPE:
2559 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2560 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2561 			retnum += NFSX_UNSIGNED;
2562 			break;
2563 		case NFSATTRBIT_CHANGE:
2564 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2565 			txdr_hyper(vap->va_filerev, tl);
2566 			retnum += NFSX_HYPER;
2567 			break;
2568 		case NFSATTRBIT_SIZE:
2569 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2570 			txdr_hyper(vap->va_size, tl);
2571 			retnum += NFSX_HYPER;
2572 			break;
2573 		case NFSATTRBIT_LINKSUPPORT:
2574 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2575 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2576 				*tl = newnfs_true;
2577 			else
2578 				*tl = newnfs_false;
2579 			retnum += NFSX_UNSIGNED;
2580 			break;
2581 		case NFSATTRBIT_SYMLINKSUPPORT:
2582 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2583 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2584 				*tl = newnfs_true;
2585 			else
2586 				*tl = newnfs_false;
2587 			retnum += NFSX_UNSIGNED;
2588 			break;
2589 		case NFSATTRBIT_NAMEDATTR:
2590 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2591 			*tl = newnfs_false;
2592 			retnum += NFSX_UNSIGNED;
2593 			break;
2594 		case NFSATTRBIT_FSID:
2595 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2596 			*tl++ = 0;
2597 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2598 			*tl++ = 0;
2599 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2600 			retnum += NFSX_V4FSID;
2601 			break;
2602 		case NFSATTRBIT_UNIQUEHANDLES:
2603 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2604 			*tl = newnfs_true;
2605 			retnum += NFSX_UNSIGNED;
2606 			break;
2607 		case NFSATTRBIT_LEASETIME:
2608 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2609 			*tl = txdr_unsigned(nfsrv_lease);
2610 			retnum += NFSX_UNSIGNED;
2611 			break;
2612 		case NFSATTRBIT_RDATTRERROR:
2613 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2614 			*tl = txdr_unsigned(rderror);
2615 			retnum += NFSX_UNSIGNED;
2616 			break;
2617 		/*
2618 		 * Recommended Attributes. (Only the supported ones.)
2619 		 */
2620 		case NFSATTRBIT_ACL:
2621 			retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2622 			break;
2623 		case NFSATTRBIT_ACLSUPPORT:
2624 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2625 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2626 			retnum += NFSX_UNSIGNED;
2627 			break;
2628 		case NFSATTRBIT_CANSETTIME:
2629 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2630 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2631 				*tl = newnfs_true;
2632 			else
2633 				*tl = newnfs_false;
2634 			retnum += NFSX_UNSIGNED;
2635 			break;
2636 		case NFSATTRBIT_CASEINSENSITIVE:
2637 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2638 			*tl = newnfs_false;
2639 			retnum += NFSX_UNSIGNED;
2640 			break;
2641 		case NFSATTRBIT_CASEPRESERVING:
2642 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2643 			*tl = newnfs_true;
2644 			retnum += NFSX_UNSIGNED;
2645 			break;
2646 		case NFSATTRBIT_CHOWNRESTRICTED:
2647 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2648 			*tl = newnfs_true;
2649 			retnum += NFSX_UNSIGNED;
2650 			break;
2651 		case NFSATTRBIT_FILEHANDLE:
2652 			retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2653 			break;
2654 		case NFSATTRBIT_FILEID:
2655 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2656 			uquad = vap->va_fileid;
2657 			txdr_hyper(uquad, tl);
2658 			retnum += NFSX_HYPER;
2659 			break;
2660 		case NFSATTRBIT_FILESAVAIL:
2661 			/*
2662 			 * Check quota and use min(quota, f_ffree).
2663 			 */
2664 			freenum = fs->f_ffree;
2665 #ifdef QUOTA
2666 			/*
2667 			 * ufs_quotactl() insists that the uid argument
2668 			 * equal p_ruid for non-root quota access, so
2669 			 * we'll just make sure that's the case.
2670 			 */
2671 			savuid = p->p_cred->p_ruid;
2672 			p->p_cred->p_ruid = cred->cr_uid;
2673 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2674 			    cred->cr_uid, (caddr_t)&dqb))
2675 			    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2676 				freenum);
2677 			p->p_cred->p_ruid = savuid;
2678 #endif	/* QUOTA */
2679 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2680 			*tl++ = 0;
2681 			*tl = txdr_unsigned(freenum);
2682 			retnum += NFSX_HYPER;
2683 			break;
2684 		case NFSATTRBIT_FILESFREE:
2685 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2686 			*tl++ = 0;
2687 			*tl = txdr_unsigned(fs->f_ffree);
2688 			retnum += NFSX_HYPER;
2689 			break;
2690 		case NFSATTRBIT_FILESTOTAL:
2691 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2692 			*tl++ = 0;
2693 			*tl = txdr_unsigned(fs->f_files);
2694 			retnum += NFSX_HYPER;
2695 			break;
2696 		case NFSATTRBIT_FSLOCATIONS:
2697 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2698 			*tl++ = 0;
2699 			*tl = 0;
2700 			retnum += 2 * NFSX_UNSIGNED;
2701 			break;
2702 		case NFSATTRBIT_HOMOGENEOUS:
2703 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2704 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2705 				*tl = newnfs_true;
2706 			else
2707 				*tl = newnfs_false;
2708 			retnum += NFSX_UNSIGNED;
2709 			break;
2710 		case NFSATTRBIT_MAXFILESIZE:
2711 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2712 			uquad = NFSRV_MAXFILESIZE;
2713 			txdr_hyper(uquad, tl);
2714 			retnum += NFSX_HYPER;
2715 			break;
2716 		case NFSATTRBIT_MAXLINK:
2717 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2718 			*tl = txdr_unsigned(NFS_LINK_MAX);
2719 			retnum += NFSX_UNSIGNED;
2720 			break;
2721 		case NFSATTRBIT_MAXNAME:
2722 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2723 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
2724 			retnum += NFSX_UNSIGNED;
2725 			break;
2726 		case NFSATTRBIT_MAXREAD:
2727 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2728 			*tl++ = 0;
2729 			*tl = txdr_unsigned(fsinf.fs_rtmax);
2730 			retnum += NFSX_HYPER;
2731 			break;
2732 		case NFSATTRBIT_MAXWRITE:
2733 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2734 			*tl++ = 0;
2735 			*tl = txdr_unsigned(fsinf.fs_wtmax);
2736 			retnum += NFSX_HYPER;
2737 			break;
2738 		case NFSATTRBIT_MODE:
2739 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2740 			*tl = vtonfsv34_mode(vap->va_mode);
2741 			retnum += NFSX_UNSIGNED;
2742 			break;
2743 		case NFSATTRBIT_NOTRUNC:
2744 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2745 			*tl = newnfs_true;
2746 			retnum += NFSX_UNSIGNED;
2747 			break;
2748 		case NFSATTRBIT_NUMLINKS:
2749 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2750 			*tl = txdr_unsigned(vap->va_nlink);
2751 			retnum += NFSX_UNSIGNED;
2752 			break;
2753 		case NFSATTRBIT_OWNER:
2754 			cp = namestr;
2755 			nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2756 			retnum += nfsm_strtom(nd, cp, siz);
2757 			if (cp != namestr)
2758 				free(cp, M_NFSSTRING);
2759 			break;
2760 		case NFSATTRBIT_OWNERGROUP:
2761 			cp = namestr;
2762 			nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2763 			retnum += nfsm_strtom(nd, cp, siz);
2764 			if (cp != namestr)
2765 				free(cp, M_NFSSTRING);
2766 			break;
2767 		case NFSATTRBIT_QUOTAHARD:
2768 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2769 				freenum = fs->f_bfree;
2770 			else
2771 				freenum = fs->f_bavail;
2772 #ifdef QUOTA
2773 			/*
2774 			 * ufs_quotactl() insists that the uid argument
2775 			 * equal p_ruid for non-root quota access, so
2776 			 * we'll just make sure that's the case.
2777 			 */
2778 			savuid = p->p_cred->p_ruid;
2779 			p->p_cred->p_ruid = cred->cr_uid;
2780 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2781 			    cred->cr_uid, (caddr_t)&dqb))
2782 			    freenum = min(dqb.dqb_bhardlimit, freenum);
2783 			p->p_cred->p_ruid = savuid;
2784 #endif	/* QUOTA */
2785 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2786 			uquad = (u_int64_t)freenum;
2787 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2788 			txdr_hyper(uquad, tl);
2789 			retnum += NFSX_HYPER;
2790 			break;
2791 		case NFSATTRBIT_QUOTASOFT:
2792 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2793 				freenum = fs->f_bfree;
2794 			else
2795 				freenum = fs->f_bavail;
2796 #ifdef QUOTA
2797 			/*
2798 			 * ufs_quotactl() insists that the uid argument
2799 			 * equal p_ruid for non-root quota access, so
2800 			 * we'll just make sure that's the case.
2801 			 */
2802 			savuid = p->p_cred->p_ruid;
2803 			p->p_cred->p_ruid = cred->cr_uid;
2804 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2805 			    cred->cr_uid, (caddr_t)&dqb))
2806 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
2807 			p->p_cred->p_ruid = savuid;
2808 #endif	/* QUOTA */
2809 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2810 			uquad = (u_int64_t)freenum;
2811 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2812 			txdr_hyper(uquad, tl);
2813 			retnum += NFSX_HYPER;
2814 			break;
2815 		case NFSATTRBIT_QUOTAUSED:
2816 			freenum = 0;
2817 #ifdef QUOTA
2818 			/*
2819 			 * ufs_quotactl() insists that the uid argument
2820 			 * equal p_ruid for non-root quota access, so
2821 			 * we'll just make sure that's the case.
2822 			 */
2823 			savuid = p->p_cred->p_ruid;
2824 			p->p_cred->p_ruid = cred->cr_uid;
2825 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2826 			    cred->cr_uid, (caddr_t)&dqb))
2827 			    freenum = dqb.dqb_curblocks;
2828 			p->p_cred->p_ruid = savuid;
2829 #endif	/* QUOTA */
2830 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2831 			uquad = (u_int64_t)freenum;
2832 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2833 			txdr_hyper(uquad, tl);
2834 			retnum += NFSX_HYPER;
2835 			break;
2836 		case NFSATTRBIT_RAWDEV:
2837 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2838 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2839 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2840 			retnum += NFSX_V4SPECDATA;
2841 			break;
2842 		case NFSATTRBIT_SPACEAVAIL:
2843 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2844 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2845 				if (pnfssf != NULL)
2846 					uquad = (u_int64_t)pnfssf->f_bfree;
2847 				else
2848 					uquad = (u_int64_t)fs->f_bfree;
2849 			} else {
2850 				if (pnfssf != NULL)
2851 					uquad = (u_int64_t)pnfssf->f_bavail;
2852 				else
2853 					uquad = (u_int64_t)fs->f_bavail;
2854 			}
2855 			if (pnfssf != NULL)
2856 				uquad *= pnfssf->f_bsize;
2857 			else
2858 				uquad *= fs->f_bsize;
2859 			txdr_hyper(uquad, tl);
2860 			retnum += NFSX_HYPER;
2861 			break;
2862 		case NFSATTRBIT_SPACEFREE:
2863 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2864 			if (pnfssf != NULL) {
2865 				uquad = (u_int64_t)pnfssf->f_bfree;
2866 				uquad *= pnfssf->f_bsize;
2867 			} else {
2868 				uquad = (u_int64_t)fs->f_bfree;
2869 				uquad *= fs->f_bsize;
2870 			}
2871 			txdr_hyper(uquad, tl);
2872 			retnum += NFSX_HYPER;
2873 			break;
2874 		case NFSATTRBIT_SPACETOTAL:
2875 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2876 			if (pnfssf != NULL) {
2877 				uquad = (u_int64_t)pnfssf->f_blocks;
2878 				uquad *= pnfssf->f_bsize;
2879 			} else {
2880 				uquad = (u_int64_t)fs->f_blocks;
2881 				uquad *= fs->f_bsize;
2882 			}
2883 			txdr_hyper(uquad, tl);
2884 			retnum += NFSX_HYPER;
2885 			break;
2886 		case NFSATTRBIT_SPACEUSED:
2887 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2888 			txdr_hyper(vap->va_bytes, tl);
2889 			retnum += NFSX_HYPER;
2890 			break;
2891 		case NFSATTRBIT_TIMEACCESS:
2892 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2893 			txdr_nfsv4time(&vap->va_atime, tl);
2894 			retnum += NFSX_V4TIME;
2895 			break;
2896 		case NFSATTRBIT_TIMEACCESSSET:
2897 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2898 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2899 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2900 				txdr_nfsv4time(&vap->va_atime, tl);
2901 				retnum += NFSX_V4SETTIME;
2902 			} else {
2903 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2904 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2905 				retnum += NFSX_UNSIGNED;
2906 			}
2907 			break;
2908 		case NFSATTRBIT_TIMEDELTA:
2909 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2910 			temptime.tv_sec = 0;
2911 			temptime.tv_nsec = 1000000000 / hz;
2912 			txdr_nfsv4time(&temptime, tl);
2913 			retnum += NFSX_V4TIME;
2914 			break;
2915 		case NFSATTRBIT_TIMEMETADATA:
2916 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2917 			txdr_nfsv4time(&vap->va_ctime, tl);
2918 			retnum += NFSX_V4TIME;
2919 			break;
2920 		case NFSATTRBIT_TIMEMODIFY:
2921 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2922 			txdr_nfsv4time(&vap->va_mtime, tl);
2923 			retnum += NFSX_V4TIME;
2924 			break;
2925 		case NFSATTRBIT_TIMECREATE:
2926 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2927 			txdr_nfsv4time(&vap->va_birthtime, tl);
2928 			retnum += NFSX_V4TIME;
2929 			break;
2930 		case NFSATTRBIT_TIMEMODIFYSET:
2931 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2932 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2933 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2934 				txdr_nfsv4time(&vap->va_mtime, tl);
2935 				retnum += NFSX_V4SETTIME;
2936 			} else {
2937 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2938 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2939 				retnum += NFSX_UNSIGNED;
2940 			}
2941 			break;
2942 		case NFSATTRBIT_MOUNTEDONFILEID:
2943 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2944 			if (at_root != 0)
2945 				uquad = mounted_on_fileno;
2946 			else
2947 				uquad = vap->va_fileid;
2948 			txdr_hyper(uquad, tl);
2949 			retnum += NFSX_HYPER;
2950 			break;
2951 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2952 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2953 			NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2954 			NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2955 			retnum += nfsrv_putattrbit(nd, &attrbits);
2956 			break;
2957 		case NFSATTRBIT_FSLAYOUTTYPE:
2958 		case NFSATTRBIT_LAYOUTTYPE:
2959 			if (nfsrv_devidcnt == 0)
2960 				siz = 1;
2961 			else
2962 				siz = 2;
2963 			if (siz == 2) {
2964 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2965 				*tl++ = txdr_unsigned(1);	/* One entry. */
2966 				if (nfsrv_doflexfile != 0 ||
2967 				    nfsrv_maxpnfsmirror > 1)
2968 					*tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
2969 				else
2970 					*tl = txdr_unsigned(
2971 					    NFSLAYOUT_NFSV4_1_FILES);
2972 			} else {
2973 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2974 				*tl = 0;
2975 			}
2976 			retnum += siz * NFSX_UNSIGNED;
2977 			break;
2978 		case NFSATTRBIT_LAYOUTALIGNMENT:
2979 		case NFSATTRBIT_LAYOUTBLKSIZE:
2980 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2981 			*tl = txdr_unsigned(NFS_SRVMAXIO);
2982 			retnum += NFSX_UNSIGNED;
2983 			break;
2984 		case NFSATTRBIT_XATTRSUPPORT:
2985 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2986 			if (xattrsupp)
2987 				*tl = newnfs_true;
2988 			else
2989 				*tl = newnfs_false;
2990 			retnum += NFSX_UNSIGNED;
2991 			break;
2992 		default:
2993 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2994 		}
2995 	    }
2996 	}
2997 	if (naclp != NULL)
2998 		acl_free(naclp);
2999 	free(fs, M_STATFS);
3000 	*retnump = txdr_unsigned(retnum);
3001 	return (retnum + prefixnum);
3002 }
3003 
3004 /*
3005  * Put the attribute bits onto an mbuf list.
3006  * Return the number of bytes of output generated.
3007  */
3008 int
3009 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3010 {
3011 	u_int32_t *tl;
3012 	int cnt, i, bytesize;
3013 
3014 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3015 		if (attrbitp->bits[cnt - 1])
3016 			break;
3017 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3018 	NFSM_BUILD(tl, u_int32_t *, bytesize);
3019 	*tl++ = txdr_unsigned(cnt);
3020 	for (i = 0; i < cnt; i++)
3021 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
3022 	return (bytesize);
3023 }
3024 
3025 /*
3026  * Convert a uid to a string.
3027  * If the lookup fails, just output the digits.
3028  * uid - the user id
3029  * cpp - points to a buffer of size NFSV4_SMALLSTR
3030  *       (malloc a larger one, as required)
3031  * retlenp - pointer to length to be returned
3032  */
3033 void
3034 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3035 {
3036 	int i;
3037 	struct nfsusrgrp *usrp;
3038 	u_char *cp = *cpp;
3039 	uid_t tmp;
3040 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3041 	struct nfsrv_lughash *hp;
3042 
3043 	cnt = 0;
3044 tryagain:
3045 	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3046 		/*
3047 		 * Always map nfsrv_defaultuid to "nobody".
3048 		 */
3049 		if (uid == nfsrv_defaultuid) {
3050 			i = nfsrv_dnsnamelen + 7;
3051 			if (i > len) {
3052 				if (len > NFSV4_SMALLSTR)
3053 					free(cp, M_NFSSTRING);
3054 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3055 				*cpp = cp;
3056 				len = i;
3057 				goto tryagain;
3058 			}
3059 			*retlenp = i;
3060 			NFSBCOPY("nobody@", cp, 7);
3061 			cp += 7;
3062 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3063 			return;
3064 		}
3065 		hasampersand = 0;
3066 		hp = NFSUSERHASH(uid);
3067 		mtx_lock(&hp->mtx);
3068 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3069 			if (usrp->lug_uid == uid) {
3070 				if (usrp->lug_expiry < NFSD_MONOSEC)
3071 					break;
3072 				/*
3073 				 * If the name doesn't already have an '@'
3074 				 * in it, append @domainname to it.
3075 				 */
3076 				for (i = 0; i < usrp->lug_namelen; i++) {
3077 					if (usrp->lug_name[i] == '@') {
3078 						hasampersand = 1;
3079 						break;
3080 					}
3081 				}
3082 				if (hasampersand)
3083 					i = usrp->lug_namelen;
3084 				else
3085 					i = usrp->lug_namelen +
3086 					    nfsrv_dnsnamelen + 1;
3087 				if (i > len) {
3088 					mtx_unlock(&hp->mtx);
3089 					if (len > NFSV4_SMALLSTR)
3090 						free(cp, M_NFSSTRING);
3091 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3092 					*cpp = cp;
3093 					len = i;
3094 					goto tryagain;
3095 				}
3096 				*retlenp = i;
3097 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3098 				if (!hasampersand) {
3099 					cp += usrp->lug_namelen;
3100 					*cp++ = '@';
3101 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3102 				}
3103 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3104 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3105 				    lug_numhash);
3106 				mtx_unlock(&hp->mtx);
3107 				return;
3108 			}
3109 		}
3110 		mtx_unlock(&hp->mtx);
3111 		cnt++;
3112 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3113 		if (ret == 0 && cnt < 2)
3114 			goto tryagain;
3115 	}
3116 
3117 	/*
3118 	 * No match, just return a string of digits.
3119 	 */
3120 	tmp = uid;
3121 	i = 0;
3122 	while (tmp || i == 0) {
3123 		tmp /= 10;
3124 		i++;
3125 	}
3126 	len = (i > len) ? len : i;
3127 	*retlenp = len;
3128 	cp += (len - 1);
3129 	tmp = uid;
3130 	for (i = 0; i < len; i++) {
3131 		*cp-- = '0' + (tmp % 10);
3132 		tmp /= 10;
3133 	}
3134 	return;
3135 }
3136 
3137 /*
3138  * Get a credential for the uid with the server's group list.
3139  * If none is found, just return the credential passed in after
3140  * logging a warning message.
3141  */
3142 struct ucred *
3143 nfsrv_getgrpscred(struct ucred *oldcred)
3144 {
3145 	struct nfsusrgrp *usrp;
3146 	struct ucred *newcred;
3147 	int cnt, ret;
3148 	uid_t uid;
3149 	struct nfsrv_lughash *hp;
3150 
3151 	cnt = 0;
3152 	uid = oldcred->cr_uid;
3153 tryagain:
3154 	if (nfsrv_dnsnamelen > 0) {
3155 		hp = NFSUSERHASH(uid);
3156 		mtx_lock(&hp->mtx);
3157 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3158 			if (usrp->lug_uid == uid) {
3159 				if (usrp->lug_expiry < NFSD_MONOSEC)
3160 					break;
3161 				if (usrp->lug_cred != NULL) {
3162 					newcred = crhold(usrp->lug_cred);
3163 					crfree(oldcred);
3164 				} else
3165 					newcred = oldcred;
3166 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3167 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3168 				    lug_numhash);
3169 				mtx_unlock(&hp->mtx);
3170 				return (newcred);
3171 			}
3172 		}
3173 		mtx_unlock(&hp->mtx);
3174 		cnt++;
3175 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3176 		if (ret == 0 && cnt < 2)
3177 			goto tryagain;
3178 	}
3179 	return (oldcred);
3180 }
3181 
3182 /*
3183  * Convert a string to a uid.
3184  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3185  * return 0.
3186  * If this is called from a client side mount using AUTH_SYS and the
3187  * string is made up entirely of digits, just convert the string to
3188  * a number.
3189  */
3190 int
3191 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3192 {
3193 	int i;
3194 	char *cp, *endstr, *str0;
3195 	struct nfsusrgrp *usrp;
3196 	int cnt, ret;
3197 	int error = 0;
3198 	uid_t tuid;
3199 	struct nfsrv_lughash *hp, *hp2;
3200 
3201 	if (len == 0) {
3202 		error = NFSERR_BADOWNER;
3203 		goto out;
3204 	}
3205 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3206 	str0 = str;
3207 	tuid = (uid_t)strtoul(str0, &endstr, 10);
3208 	if ((endstr - str0) == len) {
3209 		/* A numeric string. */
3210 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3211 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3212 		      nfsd_enable_stringtouid != 0))
3213 			*uidp = tuid;
3214 		else
3215 			error = NFSERR_BADOWNER;
3216 		goto out;
3217 	}
3218 	/*
3219 	 * Look for an '@'.
3220 	 */
3221 	cp = strchr(str0, '@');
3222 	if (cp != NULL)
3223 		i = (int)(cp++ - str0);
3224 	else
3225 		i = len;
3226 
3227 	cnt = 0;
3228 tryagain:
3229 	if (nfsrv_dnsnamelen > 0) {
3230 		/*
3231 		 * If an '@' is found and the domain name matches, search for
3232 		 * the name with dns stripped off.
3233 		 * Mixed case alpahbetics will match for the domain name, but
3234 		 * all upper case will not.
3235 		 */
3236 		if (cnt == 0 && i < len && i > 0 &&
3237 		    (len - 1 - i) == nfsrv_dnsnamelen &&
3238 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3239 			len -= (nfsrv_dnsnamelen + 1);
3240 			*(cp - 1) = '\0';
3241 		}
3242 
3243 		/*
3244 		 * Check for the special case of "nobody".
3245 		 */
3246 		if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3247 			*uidp = nfsrv_defaultuid;
3248 			error = 0;
3249 			goto out;
3250 		}
3251 
3252 		hp = NFSUSERNAMEHASH(str, len);
3253 		mtx_lock(&hp->mtx);
3254 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3255 			if (usrp->lug_namelen == len &&
3256 			    !NFSBCMP(usrp->lug_name, str, len)) {
3257 				if (usrp->lug_expiry < NFSD_MONOSEC)
3258 					break;
3259 				hp2 = NFSUSERHASH(usrp->lug_uid);
3260 				mtx_lock(&hp2->mtx);
3261 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3262 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3263 				    lug_numhash);
3264 				*uidp = usrp->lug_uid;
3265 				mtx_unlock(&hp2->mtx);
3266 				mtx_unlock(&hp->mtx);
3267 				error = 0;
3268 				goto out;
3269 			}
3270 		}
3271 		mtx_unlock(&hp->mtx);
3272 		cnt++;
3273 		ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3274 		    str);
3275 		if (ret == 0 && cnt < 2)
3276 			goto tryagain;
3277 	}
3278 	error = NFSERR_BADOWNER;
3279 
3280 out:
3281 	NFSEXITCODE(error);
3282 	return (error);
3283 }
3284 
3285 /*
3286  * Convert a gid to a string.
3287  * gid - the group id
3288  * cpp - points to a buffer of size NFSV4_SMALLSTR
3289  *       (malloc a larger one, as required)
3290  * retlenp - pointer to length to be returned
3291  */
3292 void
3293 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3294 {
3295 	int i;
3296 	struct nfsusrgrp *usrp;
3297 	u_char *cp = *cpp;
3298 	gid_t tmp;
3299 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3300 	struct nfsrv_lughash *hp;
3301 
3302 	cnt = 0;
3303 tryagain:
3304 	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3305 		/*
3306 		 * Always map nfsrv_defaultgid to "nogroup".
3307 		 */
3308 		if (gid == nfsrv_defaultgid) {
3309 			i = nfsrv_dnsnamelen + 8;
3310 			if (i > len) {
3311 				if (len > NFSV4_SMALLSTR)
3312 					free(cp, M_NFSSTRING);
3313 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3314 				*cpp = cp;
3315 				len = i;
3316 				goto tryagain;
3317 			}
3318 			*retlenp = i;
3319 			NFSBCOPY("nogroup@", cp, 8);
3320 			cp += 8;
3321 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3322 			return;
3323 		}
3324 		hasampersand = 0;
3325 		hp = NFSGROUPHASH(gid);
3326 		mtx_lock(&hp->mtx);
3327 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3328 			if (usrp->lug_gid == gid) {
3329 				if (usrp->lug_expiry < NFSD_MONOSEC)
3330 					break;
3331 				/*
3332 				 * If the name doesn't already have an '@'
3333 				 * in it, append @domainname to it.
3334 				 */
3335 				for (i = 0; i < usrp->lug_namelen; i++) {
3336 					if (usrp->lug_name[i] == '@') {
3337 						hasampersand = 1;
3338 						break;
3339 					}
3340 				}
3341 				if (hasampersand)
3342 					i = usrp->lug_namelen;
3343 				else
3344 					i = usrp->lug_namelen +
3345 					    nfsrv_dnsnamelen + 1;
3346 				if (i > len) {
3347 					mtx_unlock(&hp->mtx);
3348 					if (len > NFSV4_SMALLSTR)
3349 						free(cp, M_NFSSTRING);
3350 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3351 					*cpp = cp;
3352 					len = i;
3353 					goto tryagain;
3354 				}
3355 				*retlenp = i;
3356 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3357 				if (!hasampersand) {
3358 					cp += usrp->lug_namelen;
3359 					*cp++ = '@';
3360 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3361 				}
3362 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3363 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3364 				    lug_numhash);
3365 				mtx_unlock(&hp->mtx);
3366 				return;
3367 			}
3368 		}
3369 		mtx_unlock(&hp->mtx);
3370 		cnt++;
3371 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3372 		if (ret == 0 && cnt < 2)
3373 			goto tryagain;
3374 	}
3375 
3376 	/*
3377 	 * No match, just return a string of digits.
3378 	 */
3379 	tmp = gid;
3380 	i = 0;
3381 	while (tmp || i == 0) {
3382 		tmp /= 10;
3383 		i++;
3384 	}
3385 	len = (i > len) ? len : i;
3386 	*retlenp = len;
3387 	cp += (len - 1);
3388 	tmp = gid;
3389 	for (i = 0; i < len; i++) {
3390 		*cp-- = '0' + (tmp % 10);
3391 		tmp /= 10;
3392 	}
3393 	return;
3394 }
3395 
3396 /*
3397  * Convert a string to a gid.
3398  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3399  * return 0.
3400  * If this is called from a client side mount using AUTH_SYS and the
3401  * string is made up entirely of digits, just convert the string to
3402  * a number.
3403  */
3404 int
3405 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3406 {
3407 	int i;
3408 	char *cp, *endstr, *str0;
3409 	struct nfsusrgrp *usrp;
3410 	int cnt, ret;
3411 	int error = 0;
3412 	gid_t tgid;
3413 	struct nfsrv_lughash *hp, *hp2;
3414 
3415 	if (len == 0) {
3416 		error =  NFSERR_BADOWNER;
3417 		goto out;
3418 	}
3419 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3420 	str0 = str;
3421 	tgid = (gid_t)strtoul(str0, &endstr, 10);
3422 	if ((endstr - str0) == len) {
3423 		/* A numeric string. */
3424 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3425 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3426 		      nfsd_enable_stringtouid != 0))
3427 			*gidp = tgid;
3428 		else
3429 			error = NFSERR_BADOWNER;
3430 		goto out;
3431 	}
3432 	/*
3433 	 * Look for an '@'.
3434 	 */
3435 	cp = strchr(str0, '@');
3436 	if (cp != NULL)
3437 		i = (int)(cp++ - str0);
3438 	else
3439 		i = len;
3440 
3441 	cnt = 0;
3442 tryagain:
3443 	if (nfsrv_dnsnamelen > 0) {
3444 		/*
3445 		 * If an '@' is found and the dns name matches, search for the
3446 		 * name with the dns stripped off.
3447 		 */
3448 		if (cnt == 0 && i < len && i > 0 &&
3449 		    (len - 1 - i) == nfsrv_dnsnamelen &&
3450 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3451 			len -= (nfsrv_dnsnamelen + 1);
3452 			*(cp - 1) = '\0';
3453 		}
3454 
3455 		/*
3456 		 * Check for the special case of "nogroup".
3457 		 */
3458 		if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3459 			*gidp = nfsrv_defaultgid;
3460 			error = 0;
3461 			goto out;
3462 		}
3463 
3464 		hp = NFSGROUPNAMEHASH(str, len);
3465 		mtx_lock(&hp->mtx);
3466 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3467 			if (usrp->lug_namelen == len &&
3468 			    !NFSBCMP(usrp->lug_name, str, len)) {
3469 				if (usrp->lug_expiry < NFSD_MONOSEC)
3470 					break;
3471 				hp2 = NFSGROUPHASH(usrp->lug_gid);
3472 				mtx_lock(&hp2->mtx);
3473 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3474 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3475 				    lug_numhash);
3476 				*gidp = usrp->lug_gid;
3477 				mtx_unlock(&hp2->mtx);
3478 				mtx_unlock(&hp->mtx);
3479 				error = 0;
3480 				goto out;
3481 			}
3482 		}
3483 		mtx_unlock(&hp->mtx);
3484 		cnt++;
3485 		ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3486 		    str);
3487 		if (ret == 0 && cnt < 2)
3488 			goto tryagain;
3489 	}
3490 	error = NFSERR_BADOWNER;
3491 
3492 out:
3493 	NFSEXITCODE(error);
3494 	return (error);
3495 }
3496 
3497 /*
3498  * Cmp len chars, allowing mixed case in the first argument to match lower
3499  * case in the second, but not if the first argument is all upper case.
3500  * Return 0 for a match, 1 otherwise.
3501  */
3502 static int
3503 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3504 {
3505 	int i;
3506 	u_char tmp;
3507 	int fndlower = 0;
3508 
3509 	for (i = 0; i < len; i++) {
3510 		if (*cp >= 'A' && *cp <= 'Z') {
3511 			tmp = *cp++ + ('a' - 'A');
3512 		} else {
3513 			tmp = *cp++;
3514 			if (tmp >= 'a' && tmp <= 'z')
3515 				fndlower = 1;
3516 		}
3517 		if (tmp != *cp2++)
3518 			return (1);
3519 	}
3520 	if (fndlower)
3521 		return (0);
3522 	else
3523 		return (1);
3524 }
3525 
3526 /*
3527  * Set the port for the nfsuserd.
3528  */
3529 int
3530 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3531 {
3532 	struct nfssockreq *rp;
3533 #ifdef INET
3534 	struct sockaddr_in *ad;
3535 #endif
3536 #ifdef INET6
3537 	struct sockaddr_in6 *ad6;
3538 	const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3539 #endif
3540 	int error;
3541 
3542 	NFSLOCKNAMEID();
3543 	if (nfsrv_nfsuserd != NOTRUNNING) {
3544 		NFSUNLOCKNAMEID();
3545 		error = EPERM;
3546 		goto out;
3547 	}
3548 	nfsrv_nfsuserd = STARTSTOP;
3549 	/*
3550 	 * Set up the socket record and connect.
3551 	 * Set nr_client NULL before unlocking, just to ensure that no other
3552 	 * process/thread/core will use a bogus old value.  This could only
3553 	 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3554 	 * broken.
3555 	 */
3556 	rp = &nfsrv_nfsuserdsock;
3557 	rp->nr_client = NULL;
3558 	NFSUNLOCKNAMEID();
3559 	rp->nr_sotype = SOCK_DGRAM;
3560 	rp->nr_soproto = IPPROTO_UDP;
3561 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3562 	rp->nr_cred = NULL;
3563 	rp->nr_prog = RPCPROG_NFSUSERD;
3564 	error = 0;
3565 	switch (nargs->nuserd_family) {
3566 #ifdef INET
3567 	case AF_INET:
3568 		rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3569 		    M_WAITOK | M_ZERO);
3570  		ad = (struct sockaddr_in *)rp->nr_nam;
3571 		ad->sin_len = sizeof(struct sockaddr_in);
3572  		ad->sin_family = AF_INET;
3573 		ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3574 		ad->sin_port = nargs->nuserd_port;
3575 		break;
3576 #endif
3577 #ifdef INET6
3578 	case AF_INET6:
3579 		rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3580 		    M_WAITOK | M_ZERO);
3581 		ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3582 		ad6->sin6_len = sizeof(struct sockaddr_in6);
3583 		ad6->sin6_family = AF_INET6;
3584 		ad6->sin6_addr = in6loopback;
3585 		ad6->sin6_port = nargs->nuserd_port;
3586 		break;
3587 #endif
3588 	default:
3589 		error = ENXIO;
3590  	}
3591 	rp->nr_vers = RPCNFSUSERD_VERS;
3592 	if (error == 0)
3593 		error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3594 	if (error == 0) {
3595 		NFSLOCKNAMEID();
3596 		nfsrv_nfsuserd = RUNNING;
3597 		NFSUNLOCKNAMEID();
3598 	} else {
3599 		free(rp->nr_nam, M_SONAME);
3600 		NFSLOCKNAMEID();
3601 		nfsrv_nfsuserd = NOTRUNNING;
3602 		NFSUNLOCKNAMEID();
3603 	}
3604 out:
3605 	NFSEXITCODE(error);
3606 	return (error);
3607 }
3608 
3609 /*
3610  * Delete the nfsuserd port.
3611  */
3612 void
3613 nfsrv_nfsuserddelport(void)
3614 {
3615 
3616 	NFSLOCKNAMEID();
3617 	if (nfsrv_nfsuserd != RUNNING) {
3618 		NFSUNLOCKNAMEID();
3619 		return;
3620 	}
3621 	nfsrv_nfsuserd = STARTSTOP;
3622 	/* Wait for all upcalls to complete. */
3623 	while (nfsrv_userdupcalls > 0)
3624 		msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3625 		    "nfsupcalls", 0);
3626 	NFSUNLOCKNAMEID();
3627 	newnfs_disconnect(&nfsrv_nfsuserdsock);
3628 	free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3629 	NFSLOCKNAMEID();
3630 	nfsrv_nfsuserd = NOTRUNNING;
3631 	NFSUNLOCKNAMEID();
3632 }
3633 
3634 /*
3635  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3636  * name<-->id cache.
3637  * Returns 0 upon success, non-zero otherwise.
3638  */
3639 static int
3640 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3641 {
3642 	u_int32_t *tl;
3643 	struct nfsrv_descript *nd;
3644 	int len;
3645 	struct nfsrv_descript nfsd;
3646 	struct ucred *cred;
3647 	int error;
3648 
3649 	NFSLOCKNAMEID();
3650 	if (nfsrv_nfsuserd != RUNNING) {
3651 		NFSUNLOCKNAMEID();
3652 		error = EPERM;
3653 		goto out;
3654 	}
3655 	/*
3656 	 * Maintain a count of upcalls in progress, so that nfsrv_X()
3657 	 * can wait until no upcalls are in progress.
3658 	 */
3659 	nfsrv_userdupcalls++;
3660 	NFSUNLOCKNAMEID();
3661 	KASSERT(nfsrv_userdupcalls > 0,
3662 	    ("nfsrv_getuser: non-positive upcalls"));
3663 	nd = &nfsd;
3664 	cred = newnfs_getcred();
3665 	nd->nd_flag = ND_GSSINITREPLY;
3666 	nfsrvd_rephead(nd);
3667 
3668 	nd->nd_procnum = procnum;
3669 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3670 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3671 		if (procnum == RPCNFSUSERD_GETUID)
3672 			*tl = txdr_unsigned(uid);
3673 		else
3674 			*tl = txdr_unsigned(gid);
3675 	} else {
3676 		len = strlen(name);
3677 		(void) nfsm_strtom(nd, name, len);
3678 	}
3679 	error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3680 		cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3681 	NFSLOCKNAMEID();
3682 	if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3683 		wakeup(&nfsrv_userdupcalls);
3684 	NFSUNLOCKNAMEID();
3685 	NFSFREECRED(cred);
3686 	if (!error) {
3687 		m_freem(nd->nd_mrep);
3688 		error = nd->nd_repstat;
3689 	}
3690 out:
3691 	NFSEXITCODE(error);
3692 	return (error);
3693 }
3694 
3695 /*
3696  * This function is called from the nfssvc(2) system call, to update the
3697  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3698  */
3699 int
3700 nfssvc_idname(struct nfsd_idargs *nidp)
3701 {
3702 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
3703 	struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3704 	int i, group_locked, groupname_locked, user_locked, username_locked;
3705 	int error = 0;
3706 	u_char *cp;
3707 	gid_t *grps;
3708 	struct ucred *cr;
3709 	static int onethread = 0;
3710 	static time_t lasttime = 0;
3711 
3712 	if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3713 		error = EINVAL;
3714 		goto out;
3715 	}
3716 	if (nidp->nid_flag & NFSID_INITIALIZE) {
3717 		cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3718 		error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3719 		if (error != 0) {
3720 			free(cp, M_NFSSTRING);
3721 			goto out;
3722 		}
3723 		if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3724 			/*
3725 			 * Free up all the old stuff and reinitialize hash
3726 			 * lists.  All mutexes for both lists must be locked,
3727 			 * with the user/group name ones before the uid/gid
3728 			 * ones, to avoid a LOR.
3729 			 */
3730 			for (i = 0; i < nfsrv_lughashsize; i++)
3731 				mtx_lock(&nfsusernamehash[i].mtx);
3732 			for (i = 0; i < nfsrv_lughashsize; i++)
3733 				mtx_lock(&nfsuserhash[i].mtx);
3734 			for (i = 0; i < nfsrv_lughashsize; i++)
3735 				TAILQ_FOREACH_SAFE(usrp,
3736 				    &nfsuserhash[i].lughead, lug_numhash, nusrp)
3737 					nfsrv_removeuser(usrp, 1);
3738 			for (i = 0; i < nfsrv_lughashsize; i++)
3739 				mtx_unlock(&nfsuserhash[i].mtx);
3740 			for (i = 0; i < nfsrv_lughashsize; i++)
3741 				mtx_unlock(&nfsusernamehash[i].mtx);
3742 			for (i = 0; i < nfsrv_lughashsize; i++)
3743 				mtx_lock(&nfsgroupnamehash[i].mtx);
3744 			for (i = 0; i < nfsrv_lughashsize; i++)
3745 				mtx_lock(&nfsgrouphash[i].mtx);
3746 			for (i = 0; i < nfsrv_lughashsize; i++)
3747 				TAILQ_FOREACH_SAFE(usrp,
3748 				    &nfsgrouphash[i].lughead, lug_numhash,
3749 				    nusrp)
3750 					nfsrv_removeuser(usrp, 0);
3751 			for (i = 0; i < nfsrv_lughashsize; i++)
3752 				mtx_unlock(&nfsgrouphash[i].mtx);
3753 			for (i = 0; i < nfsrv_lughashsize; i++)
3754 				mtx_unlock(&nfsgroupnamehash[i].mtx);
3755 			free(nfsrv_dnsname, M_NFSSTRING);
3756 			nfsrv_dnsname = NULL;
3757 		}
3758 		if (nfsuserhash == NULL) {
3759 			/* Allocate the hash tables. */
3760 			nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3761 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3762 			    M_ZERO);
3763 			for (i = 0; i < nfsrv_lughashsize; i++)
3764 				mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3765 				    NULL, MTX_DEF | MTX_DUPOK);
3766 			nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3767 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3768 			    M_ZERO);
3769 			for (i = 0; i < nfsrv_lughashsize; i++)
3770 				mtx_init(&nfsusernamehash[i].mtx,
3771 				    "nfsusrhash", NULL, MTX_DEF |
3772 				    MTX_DUPOK);
3773 			nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3774 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3775 			    M_ZERO);
3776 			for (i = 0; i < nfsrv_lughashsize; i++)
3777 				mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3778 				    NULL, MTX_DEF | MTX_DUPOK);
3779 			nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3780 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3781 			    M_ZERO);
3782 			for (i = 0; i < nfsrv_lughashsize; i++)
3783 			    mtx_init(&nfsgroupnamehash[i].mtx,
3784 			    "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3785 		}
3786 		/* (Re)initialize the list heads. */
3787 		for (i = 0; i < nfsrv_lughashsize; i++)
3788 			TAILQ_INIT(&nfsuserhash[i].lughead);
3789 		for (i = 0; i < nfsrv_lughashsize; i++)
3790 			TAILQ_INIT(&nfsusernamehash[i].lughead);
3791 		for (i = 0; i < nfsrv_lughashsize; i++)
3792 			TAILQ_INIT(&nfsgrouphash[i].lughead);
3793 		for (i = 0; i < nfsrv_lughashsize; i++)
3794 			TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3795 
3796 		/*
3797 		 * Put name in "DNS" string.
3798 		 */
3799 		nfsrv_dnsname = cp;
3800 		nfsrv_defaultuid = nidp->nid_uid;
3801 		nfsrv_defaultgid = nidp->nid_gid;
3802 		nfsrv_usercnt = 0;
3803 		nfsrv_usermax = nidp->nid_usermax;
3804 		atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3805 		goto out;
3806 	}
3807 
3808 	/*
3809 	 * malloc the new one now, so any potential sleep occurs before
3810 	 * manipulation of the lists.
3811 	 */
3812 	newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3813 	    M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3814 	error = copyin(nidp->nid_name, newusrp->lug_name,
3815 	    nidp->nid_namelen);
3816 	if (error == 0 && nidp->nid_ngroup > 0 &&
3817 	    (nidp->nid_flag & NFSID_ADDUID) != 0) {
3818 		grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3819 		    M_WAITOK);
3820 		error = copyin(nidp->nid_grps, grps,
3821 		    sizeof(gid_t) * nidp->nid_ngroup);
3822 		if (error == 0) {
3823 			/*
3824 			 * Create a credential just like svc_getcred(),
3825 			 * but using the group list provided.
3826 			 */
3827 			cr = crget();
3828 			cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3829 			crsetgroups(cr, nidp->nid_ngroup, grps);
3830 			cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3831 			cr->cr_prison = &prison0;
3832 			prison_hold(cr->cr_prison);
3833 #ifdef MAC
3834 			mac_cred_associate_nfsd(cr);
3835 #endif
3836 			newusrp->lug_cred = cr;
3837 		}
3838 		free(grps, M_TEMP);
3839 	}
3840 	if (error) {
3841 		free(newusrp, M_NFSUSERGROUP);
3842 		goto out;
3843 	}
3844 	newusrp->lug_namelen = nidp->nid_namelen;
3845 
3846 	/*
3847 	 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3848 	 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3849 	 * The flags user_locked, username_locked, group_locked and
3850 	 * groupname_locked are set to indicate all of those hash lists are
3851 	 * locked. hp_name != NULL  and hp_idnum != NULL indicates that
3852 	 * the respective one mutex is locked.
3853 	 */
3854 	user_locked = username_locked = group_locked = groupname_locked = 0;
3855 	hp_name = hp_idnum = NULL;
3856 
3857 	/*
3858 	 * Delete old entries, as required.
3859 	 */
3860 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3861 		/* Must lock all username hash lists first, to avoid a LOR. */
3862 		for (i = 0; i < nfsrv_lughashsize; i++)
3863 			mtx_lock(&nfsusernamehash[i].mtx);
3864 		username_locked = 1;
3865 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
3866 		mtx_lock(&hp_idnum->mtx);
3867 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3868 		    nusrp) {
3869 			if (usrp->lug_uid == nidp->nid_uid)
3870 				nfsrv_removeuser(usrp, 1);
3871 		}
3872 	} else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3873 		hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3874 		    newusrp->lug_namelen);
3875 		mtx_lock(&hp_name->mtx);
3876 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3877 		    nusrp) {
3878 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3879 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3880 			    usrp->lug_namelen)) {
3881 				thp = NFSUSERHASH(usrp->lug_uid);
3882 				mtx_lock(&thp->mtx);
3883 				nfsrv_removeuser(usrp, 1);
3884 				mtx_unlock(&thp->mtx);
3885 			}
3886 		}
3887 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
3888 		mtx_lock(&hp_idnum->mtx);
3889 	} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3890 		/* Must lock all groupname hash lists first, to avoid a LOR. */
3891 		for (i = 0; i < nfsrv_lughashsize; i++)
3892 			mtx_lock(&nfsgroupnamehash[i].mtx);
3893 		groupname_locked = 1;
3894 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3895 		mtx_lock(&hp_idnum->mtx);
3896 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3897 		    nusrp) {
3898 			if (usrp->lug_gid == nidp->nid_gid)
3899 				nfsrv_removeuser(usrp, 0);
3900 		}
3901 	} else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3902 		hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3903 		    newusrp->lug_namelen);
3904 		mtx_lock(&hp_name->mtx);
3905 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3906 		    nusrp) {
3907 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3908 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3909 			    usrp->lug_namelen)) {
3910 				thp = NFSGROUPHASH(usrp->lug_gid);
3911 				mtx_lock(&thp->mtx);
3912 				nfsrv_removeuser(usrp, 0);
3913 				mtx_unlock(&thp->mtx);
3914 			}
3915 		}
3916 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3917 		mtx_lock(&hp_idnum->mtx);
3918 	}
3919 
3920 	/*
3921 	 * Now, we can add the new one.
3922 	 */
3923 	if (nidp->nid_usertimeout)
3924 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3925 	else
3926 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
3927 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3928 		newusrp->lug_uid = nidp->nid_uid;
3929 		thp = NFSUSERHASH(newusrp->lug_uid);
3930 		mtx_assert(&thp->mtx, MA_OWNED);
3931 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3932 		thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3933 		mtx_assert(&thp->mtx, MA_OWNED);
3934 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3935 		atomic_add_int(&nfsrv_usercnt, 1);
3936 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3937 		newusrp->lug_gid = nidp->nid_gid;
3938 		thp = NFSGROUPHASH(newusrp->lug_gid);
3939 		mtx_assert(&thp->mtx, MA_OWNED);
3940 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3941 		thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3942 		mtx_assert(&thp->mtx, MA_OWNED);
3943 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3944 		atomic_add_int(&nfsrv_usercnt, 1);
3945 	} else {
3946 		if (newusrp->lug_cred != NULL)
3947 			crfree(newusrp->lug_cred);
3948 		free(newusrp, M_NFSUSERGROUP);
3949 	}
3950 
3951 	/*
3952 	 * Once per second, allow one thread to trim the cache.
3953 	 */
3954 	if (lasttime < NFSD_MONOSEC &&
3955 	    atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3956 		/*
3957 		 * First, unlock the single mutexes, so that all entries
3958 		 * can be locked and any LOR is avoided.
3959 		 */
3960 		if (hp_name != NULL) {
3961 			mtx_unlock(&hp_name->mtx);
3962 			hp_name = NULL;
3963 		}
3964 		if (hp_idnum != NULL) {
3965 			mtx_unlock(&hp_idnum->mtx);
3966 			hp_idnum = NULL;
3967 		}
3968 
3969 		if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3970 		    NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3971 			if (username_locked == 0) {
3972 				for (i = 0; i < nfsrv_lughashsize; i++)
3973 					mtx_lock(&nfsusernamehash[i].mtx);
3974 				username_locked = 1;
3975 			}
3976 			KASSERT(user_locked == 0,
3977 			    ("nfssvc_idname: user_locked"));
3978 			for (i = 0; i < nfsrv_lughashsize; i++)
3979 				mtx_lock(&nfsuserhash[i].mtx);
3980 			user_locked = 1;
3981 			for (i = 0; i < nfsrv_lughashsize; i++) {
3982 				TAILQ_FOREACH_SAFE(usrp,
3983 				    &nfsuserhash[i].lughead, lug_numhash,
3984 				    nusrp)
3985 					if (usrp->lug_expiry < NFSD_MONOSEC)
3986 						nfsrv_removeuser(usrp, 1);
3987 			}
3988 			for (i = 0; i < nfsrv_lughashsize; i++) {
3989 				/*
3990 				 * Trim the cache using an approximate LRU
3991 				 * algorithm.  This code deletes the least
3992 				 * recently used entry on each hash list.
3993 				 */
3994 				if (nfsrv_usercnt <= nfsrv_usermax)
3995 					break;
3996 				usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3997 				if (usrp != NULL)
3998 					nfsrv_removeuser(usrp, 1);
3999 			}
4000 		} else {
4001 			if (groupname_locked == 0) {
4002 				for (i = 0; i < nfsrv_lughashsize; i++)
4003 					mtx_lock(&nfsgroupnamehash[i].mtx);
4004 				groupname_locked = 1;
4005 			}
4006 			KASSERT(group_locked == 0,
4007 			    ("nfssvc_idname: group_locked"));
4008 			for (i = 0; i < nfsrv_lughashsize; i++)
4009 				mtx_lock(&nfsgrouphash[i].mtx);
4010 			group_locked = 1;
4011 			for (i = 0; i < nfsrv_lughashsize; i++) {
4012 				TAILQ_FOREACH_SAFE(usrp,
4013 				    &nfsgrouphash[i].lughead, lug_numhash,
4014 				    nusrp)
4015 					if (usrp->lug_expiry < NFSD_MONOSEC)
4016 						nfsrv_removeuser(usrp, 0);
4017 			}
4018 			for (i = 0; i < nfsrv_lughashsize; i++) {
4019 				/*
4020 				 * Trim the cache using an approximate LRU
4021 				 * algorithm.  This code deletes the least
4022 				 * recently user entry on each hash list.
4023 				 */
4024 				if (nfsrv_usercnt <= nfsrv_usermax)
4025 					break;
4026 				usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4027 				if (usrp != NULL)
4028 					nfsrv_removeuser(usrp, 0);
4029 			}
4030 		}
4031 		lasttime = NFSD_MONOSEC;
4032 		atomic_store_rel_int(&onethread, 0);
4033 	}
4034 
4035 	/* Now, unlock all locked mutexes. */
4036 	if (hp_idnum != NULL)
4037 		mtx_unlock(&hp_idnum->mtx);
4038 	if (hp_name != NULL)
4039 		mtx_unlock(&hp_name->mtx);
4040 	if (user_locked != 0)
4041 		for (i = 0; i < nfsrv_lughashsize; i++)
4042 			mtx_unlock(&nfsuserhash[i].mtx);
4043 	if (username_locked != 0)
4044 		for (i = 0; i < nfsrv_lughashsize; i++)
4045 			mtx_unlock(&nfsusernamehash[i].mtx);
4046 	if (group_locked != 0)
4047 		for (i = 0; i < nfsrv_lughashsize; i++)
4048 			mtx_unlock(&nfsgrouphash[i].mtx);
4049 	if (groupname_locked != 0)
4050 		for (i = 0; i < nfsrv_lughashsize; i++)
4051 			mtx_unlock(&nfsgroupnamehash[i].mtx);
4052 out:
4053 	NFSEXITCODE(error);
4054 	return (error);
4055 }
4056 
4057 /*
4058  * Remove a user/group name element.
4059  */
4060 static void
4061 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4062 {
4063 	struct nfsrv_lughash *hp;
4064 
4065 	if (isuser != 0) {
4066 		hp = NFSUSERHASH(usrp->lug_uid);
4067 		mtx_assert(&hp->mtx, MA_OWNED);
4068 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4069 		hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4070 		mtx_assert(&hp->mtx, MA_OWNED);
4071 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4072 	} else {
4073 		hp = NFSGROUPHASH(usrp->lug_gid);
4074 		mtx_assert(&hp->mtx, MA_OWNED);
4075 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4076 		hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4077 		mtx_assert(&hp->mtx, MA_OWNED);
4078 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4079 	}
4080 	atomic_add_int(&nfsrv_usercnt, -1);
4081 	if (usrp->lug_cred != NULL)
4082 		crfree(usrp->lug_cred);
4083 	free(usrp, M_NFSUSERGROUP);
4084 }
4085 
4086 /*
4087  * Free up all the allocations related to the name<-->id cache.
4088  * This function should only be called when the nfsuserd daemon isn't
4089  * running, since it doesn't do any locking.
4090  * This function is meant to be used when the nfscommon module is unloaded.
4091  */
4092 void
4093 nfsrv_cleanusergroup(void)
4094 {
4095 	struct nfsrv_lughash *hp, *hp2;
4096 	struct nfsusrgrp *nusrp, *usrp;
4097 	int i;
4098 
4099 	if (nfsuserhash == NULL)
4100 		return;
4101 
4102 	for (i = 0; i < nfsrv_lughashsize; i++) {
4103 		hp = &nfsuserhash[i];
4104 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4105 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4106 			hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4107 			    usrp->lug_namelen);
4108 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4109 			if (usrp->lug_cred != NULL)
4110 				crfree(usrp->lug_cred);
4111 			free(usrp, M_NFSUSERGROUP);
4112 		}
4113 		hp = &nfsgrouphash[i];
4114 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4115 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4116 			hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4117 			    usrp->lug_namelen);
4118 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4119 			if (usrp->lug_cred != NULL)
4120 				crfree(usrp->lug_cred);
4121 			free(usrp, M_NFSUSERGROUP);
4122 		}
4123 		mtx_destroy(&nfsuserhash[i].mtx);
4124 		mtx_destroy(&nfsusernamehash[i].mtx);
4125 		mtx_destroy(&nfsgroupnamehash[i].mtx);
4126 		mtx_destroy(&nfsgrouphash[i].mtx);
4127 	}
4128 	free(nfsuserhash, M_NFSUSERGROUP);
4129 	free(nfsusernamehash, M_NFSUSERGROUP);
4130 	free(nfsgrouphash, M_NFSUSERGROUP);
4131 	free(nfsgroupnamehash, M_NFSUSERGROUP);
4132 	free(nfsrv_dnsname, M_NFSSTRING);
4133 }
4134 
4135 /*
4136  * This function scans a byte string and checks for UTF-8 compliance.
4137  * It returns 0 if it conforms and NFSERR_INVAL if not.
4138  */
4139 int
4140 nfsrv_checkutf8(u_int8_t *cp, int len)
4141 {
4142 	u_int32_t val = 0x0;
4143 	int cnt = 0, gotd = 0, shift = 0;
4144 	u_int8_t byte;
4145 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4146 	int error = 0;
4147 
4148 	/*
4149 	 * Here are what the variables are used for:
4150 	 * val - the calculated value of a multibyte char, used to check
4151 	 *       that it was coded with the correct range
4152 	 * cnt - the number of 10xxxxxx bytes to follow
4153 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4154 	 * shift - lower order bits of range (ie. "val >> shift" should
4155 	 *       not be 0, in other words, dividing by the lower bound
4156 	 *       of the range should get a non-zero value)
4157 	 * byte - used to calculate cnt
4158 	 */
4159 	while (len > 0) {
4160 		if (cnt > 0) {
4161 			/* This handles the 10xxxxxx bytes */
4162 			if ((*cp & 0xc0) != 0x80 ||
4163 			    (gotd && (*cp & 0x20))) {
4164 				error = NFSERR_INVAL;
4165 				goto out;
4166 			}
4167 			gotd = 0;
4168 			val <<= 6;
4169 			val |= (*cp & 0x3f);
4170 			cnt--;
4171 			if (cnt == 0 && (val >> shift) == 0x0) {
4172 				error = NFSERR_INVAL;
4173 				goto out;
4174 			}
4175 		} else if (*cp & 0x80) {
4176 			/* first byte of multi byte char */
4177 			byte = *cp;
4178 			while ((byte & 0x40) && cnt < 6) {
4179 				cnt++;
4180 				byte <<= 1;
4181 			}
4182 			if (cnt == 0 || cnt == 6) {
4183 				error = NFSERR_INVAL;
4184 				goto out;
4185 			}
4186 			val = (*cp & (0x3f >> cnt));
4187 			shift = utf8_shift[cnt - 1];
4188 			if (cnt == 2 && val == 0xd)
4189 				/* Check for the 0xd800-0xdfff case */
4190 				gotd = 1;
4191 		}
4192 		cp++;
4193 		len--;
4194 	}
4195 	if (cnt > 0)
4196 		error = NFSERR_INVAL;
4197 
4198 out:
4199 	NFSEXITCODE(error);
4200 	return (error);
4201 }
4202 
4203 /*
4204  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4205  * strings, one with the root path in it and the other with the list of
4206  * locations. The list is in the same format as is found in nfr_refs.
4207  * It is a "," separated list of entries, where each of them is of the
4208  * form <server>:<rootpath>. For example
4209  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4210  * The nilp argument is set to 1 for the special case of a null fs_root
4211  * and an empty server list.
4212  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4213  * number of xdr bytes parsed in sump.
4214  */
4215 static int
4216 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4217     int *sump, int *nilp)
4218 {
4219 	u_int32_t *tl;
4220 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4221 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4222 	struct list {
4223 		SLIST_ENTRY(list) next;
4224 		int len;
4225 		u_char host[1];
4226 	} *lsp, *nlsp;
4227 	SLIST_HEAD(, list) head;
4228 
4229 	*fsrootp = NULL;
4230 	*srvp = NULL;
4231 	*nilp = 0;
4232 
4233 	/*
4234 	 * Get the fs_root path and check for the special case of null path
4235 	 * and 0 length server list.
4236 	 */
4237 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4238 	len = fxdr_unsigned(int, *tl);
4239 	if (len < 0 || len > 10240) {
4240 		error = NFSERR_BADXDR;
4241 		goto nfsmout;
4242 	}
4243 	if (len == 0) {
4244 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4245 		if (*tl != 0) {
4246 			error = NFSERR_BADXDR;
4247 			goto nfsmout;
4248 		}
4249 		*nilp = 1;
4250 		*sump = 2 * NFSX_UNSIGNED;
4251 		error = 0;
4252 		goto nfsmout;
4253 	}
4254 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4255 	error = nfsrv_mtostr(nd, cp, len);
4256 	if (!error) {
4257 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4258 		cnt = fxdr_unsigned(int, *tl);
4259 		if (cnt <= 0)
4260 			error = NFSERR_BADXDR;
4261 	}
4262 	if (error)
4263 		goto nfsmout;
4264 
4265 	/*
4266 	 * Now, loop through the location list and make up the srvlist.
4267 	 */
4268 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4269 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4270 	slen = 1024;
4271 	siz = 0;
4272 	for (i = 0; i < cnt; i++) {
4273 		SLIST_INIT(&head);
4274 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4275 		nsrv = fxdr_unsigned(int, *tl);
4276 		if (nsrv <= 0) {
4277 			error = NFSERR_BADXDR;
4278 			goto nfsmout;
4279 		}
4280 
4281 		/*
4282 		 * Handle the first server by putting it in the srvstr.
4283 		 */
4284 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4285 		len = fxdr_unsigned(int, *tl);
4286 		if (len <= 0 || len > 1024) {
4287 			error = NFSERR_BADXDR;
4288 			goto nfsmout;
4289 		}
4290 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4291 		if (cp3 != cp2) {
4292 			*cp3++ = ',';
4293 			siz++;
4294 		}
4295 		error = nfsrv_mtostr(nd, cp3, len);
4296 		if (error)
4297 			goto nfsmout;
4298 		cp3 += len;
4299 		*cp3++ = ':';
4300 		siz += (len + 1);
4301 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4302 		for (j = 1; j < nsrv; j++) {
4303 			/*
4304 			 * Yuck, put them in an slist and process them later.
4305 			 */
4306 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4307 			len = fxdr_unsigned(int, *tl);
4308 			if (len <= 0 || len > 1024) {
4309 				error = NFSERR_BADXDR;
4310 				goto nfsmout;
4311 			}
4312 			lsp = (struct list *)malloc(sizeof (struct list)
4313 			    + len, M_TEMP, M_WAITOK);
4314 			error = nfsrv_mtostr(nd, lsp->host, len);
4315 			if (error)
4316 				goto nfsmout;
4317 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4318 			lsp->len = len;
4319 			SLIST_INSERT_HEAD(&head, lsp, next);
4320 		}
4321 
4322 		/*
4323 		 * Finally, we can get the path.
4324 		 */
4325 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4326 		len = fxdr_unsigned(int, *tl);
4327 		if (len <= 0 || len > 1024) {
4328 			error = NFSERR_BADXDR;
4329 			goto nfsmout;
4330 		}
4331 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4332 		error = nfsrv_mtostr(nd, cp3, len);
4333 		if (error)
4334 			goto nfsmout;
4335 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4336 		str = cp3;
4337 		stringlen = len;
4338 		cp3 += len;
4339 		siz += len;
4340 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4341 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4342 			    &cp2, &cp3, &slen);
4343 			*cp3++ = ',';
4344 			NFSBCOPY(lsp->host, cp3, lsp->len);
4345 			cp3 += lsp->len;
4346 			*cp3++ = ':';
4347 			NFSBCOPY(str, cp3, stringlen);
4348 			cp3 += stringlen;
4349 			*cp3 = '\0';
4350 			siz += (lsp->len + stringlen + 2);
4351 			free(lsp, M_TEMP);
4352 		}
4353 	}
4354 	*fsrootp = cp;
4355 	*srvp = cp2;
4356 	*sump = xdrsum;
4357 	NFSEXITCODE2(0, nd);
4358 	return (0);
4359 nfsmout:
4360 	if (cp != NULL)
4361 		free(cp, M_NFSSTRING);
4362 	if (cp2 != NULL)
4363 		free(cp2, M_NFSSTRING);
4364 	NFSEXITCODE2(error, nd);
4365 	return (error);
4366 }
4367 
4368 /*
4369  * Make the malloc'd space large enough. This is a pain, but the xdr
4370  * doesn't set an upper bound on the side, so...
4371  */
4372 static void
4373 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4374 {
4375 	u_char *cp;
4376 	int i;
4377 
4378 	if (siz <= *slenp)
4379 		return;
4380 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4381 	NFSBCOPY(*cpp, cp, *slenp);
4382 	free(*cpp, M_NFSSTRING);
4383 	i = *cpp2 - *cpp;
4384 	*cpp = cp;
4385 	*cpp2 = cp + i;
4386 	*slenp = siz + 1024;
4387 }
4388 
4389 /*
4390  * Initialize the reply header data structures.
4391  */
4392 void
4393 nfsrvd_rephead(struct nfsrv_descript *nd)
4394 {
4395 	struct mbuf *mreq;
4396 
4397 	/*
4398 	 * If this is a big reply, use a cluster.
4399 	 */
4400 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4401 	    nfs_bigreply[nd->nd_procnum]) {
4402 		NFSMCLGET(mreq, M_WAITOK);
4403 		nd->nd_mreq = mreq;
4404 		nd->nd_mb = mreq;
4405 	} else {
4406 		NFSMGET(mreq);
4407 		nd->nd_mreq = mreq;
4408 		nd->nd_mb = mreq;
4409 	}
4410 	nd->nd_bpos = mtod(mreq, caddr_t);
4411 	mreq->m_len = 0;
4412 
4413 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4414 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4415 }
4416 
4417 /*
4418  * Lock a socket against others.
4419  * Currently used to serialize connect/disconnect attempts.
4420  */
4421 int
4422 newnfs_sndlock(int *flagp)
4423 {
4424 	struct timespec ts;
4425 
4426 	NFSLOCKSOCK();
4427 	while (*flagp & NFSR_SNDLOCK) {
4428 		*flagp |= NFSR_WANTSND;
4429 		ts.tv_sec = 0;
4430 		ts.tv_nsec = 0;
4431 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4432 		    PZERO - 1, "nfsndlck", &ts);
4433 	}
4434 	*flagp |= NFSR_SNDLOCK;
4435 	NFSUNLOCKSOCK();
4436 	return (0);
4437 }
4438 
4439 /*
4440  * Unlock the stream socket for others.
4441  */
4442 void
4443 newnfs_sndunlock(int *flagp)
4444 {
4445 
4446 	NFSLOCKSOCK();
4447 	if ((*flagp & NFSR_SNDLOCK) == 0)
4448 		panic("nfs sndunlock");
4449 	*flagp &= ~NFSR_SNDLOCK;
4450 	if (*flagp & NFSR_WANTSND) {
4451 		*flagp &= ~NFSR_WANTSND;
4452 		wakeup((caddr_t)flagp);
4453 	}
4454 	NFSUNLOCKSOCK();
4455 }
4456 
4457 int
4458 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4459     struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4460 {
4461 	struct in_addr saddr;
4462 	uint32_t portnum, *tl;
4463 	int i, j, k;
4464 	sa_family_t af = AF_UNSPEC;
4465 	char addr[64], protocol[5], *cp;
4466 	int cantparse = 0, error = 0;
4467 	uint16_t portv;
4468 
4469 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4470 	i = fxdr_unsigned(int, *tl);
4471 	if (i >= 3 && i <= 4) {
4472 		error = nfsrv_mtostr(nd, protocol, i);
4473 		if (error)
4474 			goto nfsmout;
4475 		if (strcmp(protocol, "tcp") == 0) {
4476 			af = AF_INET;
4477 			*isudp = 0;
4478 		} else if (strcmp(protocol, "udp") == 0) {
4479 			af = AF_INET;
4480 			*isudp = 1;
4481 		} else if (strcmp(protocol, "tcp6") == 0) {
4482 			af = AF_INET6;
4483 			*isudp = 0;
4484 		} else if (strcmp(protocol, "udp6") == 0) {
4485 			af = AF_INET6;
4486 			*isudp = 1;
4487 		} else
4488 			cantparse = 1;
4489 	} else {
4490 		cantparse = 1;
4491 		if (i > 0) {
4492 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4493 			if (error)
4494 				goto nfsmout;
4495 		}
4496 	}
4497 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4498 	i = fxdr_unsigned(int, *tl);
4499 	if (i < 0) {
4500 		error = NFSERR_BADXDR;
4501 		goto nfsmout;
4502 	} else if (cantparse == 0 && i >= 11 && i < 64) {
4503 		/*
4504 		 * The shortest address is 11chars and the longest is < 64.
4505 		 */
4506 		error = nfsrv_mtostr(nd, addr, i);
4507 		if (error)
4508 			goto nfsmout;
4509 
4510 		/* Find the port# at the end and extract that. */
4511 		i = strlen(addr);
4512 		k = 0;
4513 		cp = &addr[i - 1];
4514 		/* Count back two '.'s from end to get port# field. */
4515 		for (j = 0; j < i; j++) {
4516 			if (*cp == '.') {
4517 				k++;
4518 				if (k == 2)
4519 					break;
4520 			}
4521 			cp--;
4522 		}
4523 		if (k == 2) {
4524 			/*
4525 			 * The NFSv4 port# is appended as .N.N, where N is
4526 			 * a decimal # in the range 0-255, just like an inet4
4527 			 * address. Cheat and use inet_aton(), which will
4528 			 * return a Class A address and then shift the high
4529 			 * order 8bits over to convert it to the port#.
4530 			 */
4531 			*cp++ = '\0';
4532 			if (inet_aton(cp, &saddr) == 1) {
4533 				portnum = ntohl(saddr.s_addr);
4534 				portv = (uint16_t)((portnum >> 16) |
4535 				    (portnum & 0xff));
4536 			} else
4537 				cantparse = 1;
4538 		} else
4539 			cantparse = 1;
4540 		if (cantparse == 0) {
4541 			if (af == AF_INET) {
4542 				if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4543 					sin->sin_len = sizeof(*sin);
4544 					sin->sin_family = AF_INET;
4545 					sin->sin_port = htons(portv);
4546 					*saf = af;
4547 					return (0);
4548 				}
4549 			} else {
4550 				if (inet_pton(af, addr, &sin6->sin6_addr)
4551 				    == 1) {
4552 					sin6->sin6_len = sizeof(*sin6);
4553 					sin6->sin6_family = AF_INET6;
4554 					sin6->sin6_port = htons(portv);
4555 					*saf = af;
4556 					return (0);
4557 				}
4558 			}
4559 		}
4560 	} else {
4561 		if (i > 0) {
4562 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4563 			if (error)
4564 				goto nfsmout;
4565 		}
4566 	}
4567 	error = EPERM;
4568 nfsmout:
4569 	return (error);
4570 }
4571 
4572 /*
4573  * Handle an NFSv4.1 Sequence request for the session.
4574  * If reply != NULL, use it to return the cached reply, as required.
4575  * The client gets a cached reply via this call for callbacks, however the
4576  * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4577  */
4578 int
4579 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4580     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4581 {
4582 	int error;
4583 
4584 	error = 0;
4585 	if (reply != NULL)
4586 		*reply = NULL;
4587 	if (slotid > maxslot)
4588 		return (NFSERR_BADSLOT);
4589 	if (seqid == slots[slotid].nfssl_seq) {
4590 		/* A retry. */
4591 		if (slots[slotid].nfssl_inprog != 0)
4592 			error = NFSERR_DELAY;
4593 		else if (slots[slotid].nfssl_reply != NULL) {
4594 			if (reply != NULL) {
4595 				*reply = slots[slotid].nfssl_reply;
4596 				slots[slotid].nfssl_reply = NULL;
4597 			}
4598 			slots[slotid].nfssl_inprog = 1;
4599 			error = NFSERR_REPLYFROMCACHE;
4600 		} else
4601 			/* No reply cached, so just do it. */
4602 			slots[slotid].nfssl_inprog = 1;
4603 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4604 		if (slots[slotid].nfssl_reply != NULL)
4605 			m_freem(slots[slotid].nfssl_reply);
4606 		slots[slotid].nfssl_reply = NULL;
4607 		slots[slotid].nfssl_inprog = 1;
4608 		slots[slotid].nfssl_seq++;
4609 	} else
4610 		error = NFSERR_SEQMISORDERED;
4611 	return (error);
4612 }
4613 
4614 /*
4615  * Cache this reply for the slot.
4616  * Use the "rep" argument to return the cached reply if repstat is set to
4617  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4618  */
4619 void
4620 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4621    struct mbuf **rep)
4622 {
4623 
4624 	if (repstat == NFSERR_REPLYFROMCACHE) {
4625 		*rep = slots[slotid].nfssl_reply;
4626 		slots[slotid].nfssl_reply = NULL;
4627 	} else {
4628 		if (slots[slotid].nfssl_reply != NULL)
4629 			m_freem(slots[slotid].nfssl_reply);
4630 		slots[slotid].nfssl_reply = *rep;
4631 	}
4632 	slots[slotid].nfssl_inprog = 0;
4633 }
4634 
4635 /*
4636  * Generate the xdr for an NFSv4.1 Sequence Operation.
4637  */
4638 void
4639 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4640     struct nfsclsession *sep, int dont_replycache)
4641 {
4642 	uint32_t *tl, slotseq = 0;
4643 	int error, maxslot, slotpos;
4644 	uint8_t sessionid[NFSX_V4SESSIONID];
4645 
4646 	error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4647 	    sessionid);
4648 	nd->nd_maxreq = sep->nfsess_maxreq;
4649 	nd->nd_maxresp = sep->nfsess_maxresp;
4650 
4651 	/* Build the Sequence arguments. */
4652 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4653 	nd->nd_sequence = tl;
4654 	bcopy(sessionid, tl, NFSX_V4SESSIONID);
4655 	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4656 	nd->nd_slotseq = tl;
4657 	if (error == 0) {
4658 		nd->nd_flag |= ND_HASSLOTID;
4659 		nd->nd_slotid = slotpos;
4660 		*tl++ = txdr_unsigned(slotseq);
4661 		*tl++ = txdr_unsigned(slotpos);
4662 		*tl++ = txdr_unsigned(maxslot);
4663 		if (dont_replycache == 0)
4664 			*tl = newnfs_true;
4665 		else
4666 			*tl = newnfs_false;
4667 	} else {
4668 		/*
4669 		 * There are two errors and the rest of the session can
4670 		 * just be zeros.
4671 		 * NFSERR_BADSESSION: This bad session should just generate
4672 		 *    the same error again when the RPC is retried.
4673 		 * ESTALE: A forced dismount is in progress and will cause the
4674 		 *    RPC to fail later.
4675 		 */
4676 		*tl++ = 0;
4677 		*tl++ = 0;
4678 		*tl++ = 0;
4679 		*tl = 0;
4680 	}
4681 	nd->nd_flag |= ND_HASSEQUENCE;
4682 }
4683 
4684 int
4685 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4686     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4687 {
4688 	int i, maxslot, slotpos;
4689 	uint64_t bitval;
4690 
4691 	/* Find an unused slot. */
4692 	slotpos = -1;
4693 	maxslot = -1;
4694 	mtx_lock(&sep->nfsess_mtx);
4695 	do {
4696 		if (nmp != NULL && sep->nfsess_defunct != 0) {
4697 			/* Just return the bad session. */
4698 			bcopy(sep->nfsess_sessionid, sessionid,
4699 			    NFSX_V4SESSIONID);
4700 			mtx_unlock(&sep->nfsess_mtx);
4701 			return (NFSERR_BADSESSION);
4702 		}
4703 		bitval = 1;
4704 		for (i = 0; i < sep->nfsess_foreslots; i++) {
4705 			if ((bitval & sep->nfsess_slots) == 0) {
4706 				slotpos = i;
4707 				sep->nfsess_slots |= bitval;
4708 				sep->nfsess_slotseq[i]++;
4709 				*slotseqp = sep->nfsess_slotseq[i];
4710 				break;
4711 			}
4712 			bitval <<= 1;
4713 		}
4714 		if (slotpos == -1) {
4715 			/*
4716 			 * If a forced dismount is in progress, just return.
4717 			 * This RPC attempt will fail when it calls
4718 			 * newnfs_request().
4719 			 */
4720 			if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4721 				mtx_unlock(&sep->nfsess_mtx);
4722 				return (ESTALE);
4723 			}
4724 			/* Wake up once/sec, to check for a forced dismount. */
4725 			(void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4726 			    PZERO, "nfsclseq", hz);
4727 		}
4728 	} while (slotpos == -1);
4729 	/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4730 	bitval = 1;
4731 	for (i = 0; i < 64; i++) {
4732 		if ((bitval & sep->nfsess_slots) != 0)
4733 			maxslot = i;
4734 		bitval <<= 1;
4735 	}
4736 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4737 	mtx_unlock(&sep->nfsess_mtx);
4738 	*slotposp = slotpos;
4739 	*maxslotp = maxslot;
4740 	return (0);
4741 }
4742 
4743 /*
4744  * Free a session slot.
4745  */
4746 void
4747 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4748 {
4749 	uint64_t bitval;
4750 
4751 	bitval = 1;
4752 	if (slot > 0)
4753 		bitval <<= slot;
4754 	mtx_lock(&sep->nfsess_mtx);
4755 	if ((bitval & sep->nfsess_slots) == 0)
4756 		printf("freeing free slot!!\n");
4757 	sep->nfsess_slots &= ~bitval;
4758 	wakeup(&sep->nfsess_slots);
4759 	mtx_unlock(&sep->nfsess_mtx);
4760 }
4761 
4762 /*
4763  * Search for a matching pnfsd DS, based on the nmp arg.
4764  * Return one if found, NULL otherwise.
4765  */
4766 struct nfsdevice *
4767 nfsv4_findmirror(struct nfsmount *nmp)
4768 {
4769 	struct nfsdevice *ds;
4770 
4771 	mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4772 	/*
4773 	 * Search the DS server list for a match with nmp.
4774 	 */
4775 	if (nfsrv_devidcnt == 0)
4776 		return (NULL);
4777 	TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4778 		if (ds->nfsdev_nmp == nmp) {
4779 			NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4780 			break;
4781 		}
4782 	}
4783 	return (ds);
4784 }
4785 
4786 /*
4787  * Fill in the fields of "struct nfsrv_descript".
4788  */
4789 void
4790 nfsm_set(struct nfsrv_descript *nd, u_int offs)
4791 {
4792 	struct mbuf *m;
4793 
4794 	m = nd->nd_mb;
4795 	nd->nd_bpos = mtod(m, char *) + offs;
4796 }
4797