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