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