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