xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision d7d962ead0b6e5e8a39202d0590022082bf5bfb6)
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 #endif
2519 
2520 	/*
2521 	 * And the NFSv4 ACL...
2522 	 */
2523 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2524 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2525 		supports_nfsv4acls == 0))) {
2526 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2527 	}
2528 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2529 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2530 		    supports_nfsv4acls == 0)) {
2531 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2532 		} else if (naclp != NULL) {
2533 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2534 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2535 				if (error == 0)
2536 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2537 					    naclp, cred, p);
2538 				NFSVOPUNLOCK(vp);
2539 			} else
2540 				error = NFSERR_PERM;
2541 			if (error != 0) {
2542 				if (reterr) {
2543 					nd->nd_repstat = NFSERR_ACCES;
2544 					free(fs, M_STATFS);
2545 					return (0);
2546 				}
2547 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2548 			}
2549 		}
2550 	}
2551 
2552 	/* Check to see if Extended Attributes are supported. */
2553 	xattrsupp = false;
2554 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2555 		if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2556 			error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2557 			    "xxx", NULL, &atsiz, cred, p);
2558 			NFSVOPUNLOCK(vp);
2559 			if (error != EOPNOTSUPP)
2560 				xattrsupp = true;
2561 		}
2562 	}
2563 
2564 	/*
2565 	 * Put out the attribute bitmap for the ones being filled in
2566 	 * and get the field for the number of attributes returned.
2567 	 */
2568 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2569 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2570 	prefixnum += NFSX_UNSIGNED;
2571 
2572 	/*
2573 	 * Now, loop around filling in the attributes for each bit set.
2574 	 */
2575 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2576 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2577 		switch (bitpos) {
2578 		case NFSATTRBIT_SUPPORTEDATTRS:
2579 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2580 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2581 			    && supports_nfsv4acls == 0)) {
2582 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2583 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2584 			}
2585 			retnum += nfsrv_putattrbit(nd, &attrbits);
2586 			break;
2587 		case NFSATTRBIT_TYPE:
2588 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2589 			*tl = vtonfsv34_type(vap->va_type);
2590 			retnum += NFSX_UNSIGNED;
2591 			break;
2592 		case NFSATTRBIT_FHEXPIRETYPE:
2593 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2594 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2595 			retnum += NFSX_UNSIGNED;
2596 			break;
2597 		case NFSATTRBIT_CHANGE:
2598 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2599 			txdr_hyper(vap->va_filerev, tl);
2600 			retnum += NFSX_HYPER;
2601 			break;
2602 		case NFSATTRBIT_SIZE:
2603 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2604 			txdr_hyper(vap->va_size, tl);
2605 			retnum += NFSX_HYPER;
2606 			break;
2607 		case NFSATTRBIT_LINKSUPPORT:
2608 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2609 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2610 				*tl = newnfs_true;
2611 			else
2612 				*tl = newnfs_false;
2613 			retnum += NFSX_UNSIGNED;
2614 			break;
2615 		case NFSATTRBIT_SYMLINKSUPPORT:
2616 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2617 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2618 				*tl = newnfs_true;
2619 			else
2620 				*tl = newnfs_false;
2621 			retnum += NFSX_UNSIGNED;
2622 			break;
2623 		case NFSATTRBIT_NAMEDATTR:
2624 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2625 			*tl = newnfs_false;
2626 			retnum += NFSX_UNSIGNED;
2627 			break;
2628 		case NFSATTRBIT_FSID:
2629 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2630 			*tl++ = 0;
2631 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2632 			*tl++ = 0;
2633 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2634 			retnum += NFSX_V4FSID;
2635 			break;
2636 		case NFSATTRBIT_UNIQUEHANDLES:
2637 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2638 			*tl = newnfs_true;
2639 			retnum += NFSX_UNSIGNED;
2640 			break;
2641 		case NFSATTRBIT_LEASETIME:
2642 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2643 			*tl = txdr_unsigned(nfsrv_lease);
2644 			retnum += NFSX_UNSIGNED;
2645 			break;
2646 		case NFSATTRBIT_RDATTRERROR:
2647 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2648 			*tl = txdr_unsigned(rderror);
2649 			retnum += NFSX_UNSIGNED;
2650 			break;
2651 		/*
2652 		 * Recommended Attributes. (Only the supported ones.)
2653 		 */
2654 		case NFSATTRBIT_ACL:
2655 			retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2656 			break;
2657 		case NFSATTRBIT_ACLSUPPORT:
2658 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2659 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2660 			retnum += NFSX_UNSIGNED;
2661 			break;
2662 		case NFSATTRBIT_CANSETTIME:
2663 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2664 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2665 				*tl = newnfs_true;
2666 			else
2667 				*tl = newnfs_false;
2668 			retnum += NFSX_UNSIGNED;
2669 			break;
2670 		case NFSATTRBIT_CASEINSENSITIVE:
2671 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2672 			*tl = newnfs_false;
2673 			retnum += NFSX_UNSIGNED;
2674 			break;
2675 		case NFSATTRBIT_CASEPRESERVING:
2676 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2677 			*tl = newnfs_true;
2678 			retnum += NFSX_UNSIGNED;
2679 			break;
2680 		case NFSATTRBIT_CHOWNRESTRICTED:
2681 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2682 			*tl = newnfs_true;
2683 			retnum += NFSX_UNSIGNED;
2684 			break;
2685 		case NFSATTRBIT_FILEHANDLE:
2686 			retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2687 			break;
2688 		case NFSATTRBIT_FILEID:
2689 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2690 			uquad = vap->va_fileid;
2691 			txdr_hyper(uquad, tl);
2692 			retnum += NFSX_HYPER;
2693 			break;
2694 		case NFSATTRBIT_FILESAVAIL:
2695 			/*
2696 			 * Check quota and use min(quota, f_ffree).
2697 			 */
2698 			freenum = fs->f_ffree;
2699 #ifdef QUOTA
2700 			/*
2701 			 * ufs_quotactl() insists that the uid argument
2702 			 * equal p_ruid for non-root quota access, so
2703 			 * we'll just make sure that's the case.
2704 			 */
2705 			savuid = p->p_cred->p_ruid;
2706 			p->p_cred->p_ruid = cred->cr_uid;
2707 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2708 			    cred->cr_uid, &dqb))
2709 			    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2710 				freenum);
2711 			p->p_cred->p_ruid = savuid;
2712 #endif	/* QUOTA */
2713 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2714 			*tl++ = 0;
2715 			*tl = txdr_unsigned(freenum);
2716 			retnum += NFSX_HYPER;
2717 			break;
2718 		case NFSATTRBIT_FILESFREE:
2719 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2720 			*tl++ = 0;
2721 			*tl = txdr_unsigned(fs->f_ffree);
2722 			retnum += NFSX_HYPER;
2723 			break;
2724 		case NFSATTRBIT_FILESTOTAL:
2725 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2726 			*tl++ = 0;
2727 			*tl = txdr_unsigned(fs->f_files);
2728 			retnum += NFSX_HYPER;
2729 			break;
2730 		case NFSATTRBIT_FSLOCATIONS:
2731 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2732 			*tl++ = 0;
2733 			*tl = 0;
2734 			retnum += 2 * NFSX_UNSIGNED;
2735 			break;
2736 		case NFSATTRBIT_HOMOGENEOUS:
2737 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2738 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2739 				*tl = newnfs_true;
2740 			else
2741 				*tl = newnfs_false;
2742 			retnum += NFSX_UNSIGNED;
2743 			break;
2744 		case NFSATTRBIT_MAXFILESIZE:
2745 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2746 			uquad = NFSRV_MAXFILESIZE;
2747 			txdr_hyper(uquad, tl);
2748 			retnum += NFSX_HYPER;
2749 			break;
2750 		case NFSATTRBIT_MAXLINK:
2751 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2752 			*tl = txdr_unsigned(NFS_LINK_MAX);
2753 			retnum += NFSX_UNSIGNED;
2754 			break;
2755 		case NFSATTRBIT_MAXNAME:
2756 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2757 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
2758 			retnum += NFSX_UNSIGNED;
2759 			break;
2760 		case NFSATTRBIT_MAXREAD:
2761 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2762 			*tl++ = 0;
2763 			*tl = txdr_unsigned(fsinf.fs_rtmax);
2764 			retnum += NFSX_HYPER;
2765 			break;
2766 		case NFSATTRBIT_MAXWRITE:
2767 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2768 			*tl++ = 0;
2769 			*tl = txdr_unsigned(fsinf.fs_wtmax);
2770 			retnum += NFSX_HYPER;
2771 			break;
2772 		case NFSATTRBIT_MODE:
2773 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2774 			*tl = vtonfsv34_mode(vap->va_mode);
2775 			retnum += NFSX_UNSIGNED;
2776 			break;
2777 		case NFSATTRBIT_NOTRUNC:
2778 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2779 			*tl = newnfs_true;
2780 			retnum += NFSX_UNSIGNED;
2781 			break;
2782 		case NFSATTRBIT_NUMLINKS:
2783 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2784 			*tl = txdr_unsigned(vap->va_nlink);
2785 			retnum += NFSX_UNSIGNED;
2786 			break;
2787 		case NFSATTRBIT_OWNER:
2788 			cp = namestr;
2789 			nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2790 			retnum += nfsm_strtom(nd, cp, siz);
2791 			if (cp != namestr)
2792 				free(cp, M_NFSSTRING);
2793 			break;
2794 		case NFSATTRBIT_OWNERGROUP:
2795 			cp = namestr;
2796 			nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2797 			retnum += nfsm_strtom(nd, cp, siz);
2798 			if (cp != namestr)
2799 				free(cp, M_NFSSTRING);
2800 			break;
2801 		case NFSATTRBIT_QUOTAHARD:
2802 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2803 				freenum = fs->f_bfree;
2804 			else
2805 				freenum = fs->f_bavail;
2806 #ifdef QUOTA
2807 			/*
2808 			 * ufs_quotactl() insists that the uid argument
2809 			 * equal p_ruid for non-root quota access, so
2810 			 * we'll just make sure that's the case.
2811 			 */
2812 			savuid = p->p_cred->p_ruid;
2813 			p->p_cred->p_ruid = cred->cr_uid;
2814 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2815 			    cred->cr_uid, &dqb))
2816 			    freenum = min(dqb.dqb_bhardlimit, freenum);
2817 			p->p_cred->p_ruid = savuid;
2818 #endif	/* QUOTA */
2819 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2820 			uquad = (u_int64_t)freenum;
2821 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2822 			txdr_hyper(uquad, tl);
2823 			retnum += NFSX_HYPER;
2824 			break;
2825 		case NFSATTRBIT_QUOTASOFT:
2826 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2827 				freenum = fs->f_bfree;
2828 			else
2829 				freenum = fs->f_bavail;
2830 #ifdef QUOTA
2831 			/*
2832 			 * ufs_quotactl() insists that the uid argument
2833 			 * equal p_ruid for non-root quota access, so
2834 			 * we'll just make sure that's the case.
2835 			 */
2836 			savuid = p->p_cred->p_ruid;
2837 			p->p_cred->p_ruid = cred->cr_uid;
2838 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2839 			    cred->cr_uid, &dqb))
2840 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
2841 			p->p_cred->p_ruid = savuid;
2842 #endif	/* QUOTA */
2843 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2844 			uquad = (u_int64_t)freenum;
2845 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2846 			txdr_hyper(uquad, tl);
2847 			retnum += NFSX_HYPER;
2848 			break;
2849 		case NFSATTRBIT_QUOTAUSED:
2850 			freenum = 0;
2851 #ifdef QUOTA
2852 			/*
2853 			 * ufs_quotactl() insists that the uid argument
2854 			 * equal p_ruid for non-root quota access, so
2855 			 * we'll just make sure that's the case.
2856 			 */
2857 			savuid = p->p_cred->p_ruid;
2858 			p->p_cred->p_ruid = cred->cr_uid;
2859 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2860 			    cred->cr_uid, &dqb))
2861 			    freenum = dqb.dqb_curblocks;
2862 			p->p_cred->p_ruid = savuid;
2863 #endif	/* QUOTA */
2864 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2865 			uquad = (u_int64_t)freenum;
2866 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2867 			txdr_hyper(uquad, tl);
2868 			retnum += NFSX_HYPER;
2869 			break;
2870 		case NFSATTRBIT_RAWDEV:
2871 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2872 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2873 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2874 			retnum += NFSX_V4SPECDATA;
2875 			break;
2876 		case NFSATTRBIT_SPACEAVAIL:
2877 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2878 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2879 				if (pnfssf != NULL)
2880 					uquad = (u_int64_t)pnfssf->f_bfree;
2881 				else
2882 					uquad = (u_int64_t)fs->f_bfree;
2883 			} else {
2884 				if (pnfssf != NULL)
2885 					uquad = (u_int64_t)pnfssf->f_bavail;
2886 				else
2887 					uquad = (u_int64_t)fs->f_bavail;
2888 			}
2889 			if (pnfssf != NULL)
2890 				uquad *= pnfssf->f_bsize;
2891 			else
2892 				uquad *= fs->f_bsize;
2893 			txdr_hyper(uquad, tl);
2894 			retnum += NFSX_HYPER;
2895 			break;
2896 		case NFSATTRBIT_SPACEFREE:
2897 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2898 			if (pnfssf != NULL) {
2899 				uquad = (u_int64_t)pnfssf->f_bfree;
2900 				uquad *= pnfssf->f_bsize;
2901 			} else {
2902 				uquad = (u_int64_t)fs->f_bfree;
2903 				uquad *= fs->f_bsize;
2904 			}
2905 			txdr_hyper(uquad, tl);
2906 			retnum += NFSX_HYPER;
2907 			break;
2908 		case NFSATTRBIT_SPACETOTAL:
2909 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2910 			if (pnfssf != NULL) {
2911 				uquad = (u_int64_t)pnfssf->f_blocks;
2912 				uquad *= pnfssf->f_bsize;
2913 			} else {
2914 				uquad = (u_int64_t)fs->f_blocks;
2915 				uquad *= fs->f_bsize;
2916 			}
2917 			txdr_hyper(uquad, tl);
2918 			retnum += NFSX_HYPER;
2919 			break;
2920 		case NFSATTRBIT_SPACEUSED:
2921 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2922 			txdr_hyper(vap->va_bytes, tl);
2923 			retnum += NFSX_HYPER;
2924 			break;
2925 		case NFSATTRBIT_TIMEACCESS:
2926 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2927 			txdr_nfsv4time(&vap->va_atime, tl);
2928 			retnum += NFSX_V4TIME;
2929 			break;
2930 		case NFSATTRBIT_TIMEACCESSSET:
2931 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2932 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2933 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2934 				txdr_nfsv4time(&vap->va_atime, tl);
2935 				retnum += NFSX_V4SETTIME;
2936 			} else {
2937 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2938 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2939 				retnum += NFSX_UNSIGNED;
2940 			}
2941 			break;
2942 		case NFSATTRBIT_TIMEDELTA:
2943 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2944 			temptime.tv_sec = 0;
2945 			temptime.tv_nsec = 1000000000 / hz;
2946 			txdr_nfsv4time(&temptime, tl);
2947 			retnum += NFSX_V4TIME;
2948 			break;
2949 		case NFSATTRBIT_TIMEMETADATA:
2950 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2951 			txdr_nfsv4time(&vap->va_ctime, tl);
2952 			retnum += NFSX_V4TIME;
2953 			break;
2954 		case NFSATTRBIT_TIMEMODIFY:
2955 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2956 			txdr_nfsv4time(&vap->va_mtime, tl);
2957 			retnum += NFSX_V4TIME;
2958 			break;
2959 		case NFSATTRBIT_TIMECREATE:
2960 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2961 			txdr_nfsv4time(&vap->va_birthtime, tl);
2962 			retnum += NFSX_V4TIME;
2963 			break;
2964 		case NFSATTRBIT_TIMEMODIFYSET:
2965 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2966 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2967 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2968 				txdr_nfsv4time(&vap->va_mtime, tl);
2969 				retnum += NFSX_V4SETTIME;
2970 			} else {
2971 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2972 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2973 				retnum += NFSX_UNSIGNED;
2974 			}
2975 			break;
2976 		case NFSATTRBIT_MOUNTEDONFILEID:
2977 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2978 			if (at_root != 0)
2979 				uquad = mounted_on_fileno;
2980 			else
2981 				uquad = vap->va_fileid;
2982 			txdr_hyper(uquad, tl);
2983 			retnum += NFSX_HYPER;
2984 			break;
2985 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2986 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2987 			NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2988 			NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2989 			retnum += nfsrv_putattrbit(nd, &attrbits);
2990 			break;
2991 		case NFSATTRBIT_FSLAYOUTTYPE:
2992 		case NFSATTRBIT_LAYOUTTYPE:
2993 			if (nfsrv_devidcnt == 0)
2994 				siz = 1;
2995 			else
2996 				siz = 2;
2997 			if (siz == 2) {
2998 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2999 				*tl++ = txdr_unsigned(1);	/* One entry. */
3000 				if (nfsrv_doflexfile != 0 ||
3001 				    nfsrv_maxpnfsmirror > 1)
3002 					*tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3003 				else
3004 					*tl = txdr_unsigned(
3005 					    NFSLAYOUT_NFSV4_1_FILES);
3006 			} else {
3007 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3008 				*tl = 0;
3009 			}
3010 			retnum += siz * NFSX_UNSIGNED;
3011 			break;
3012 		case NFSATTRBIT_LAYOUTALIGNMENT:
3013 		case NFSATTRBIT_LAYOUTBLKSIZE:
3014 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3015 			*tl = txdr_unsigned(nfs_srvmaxio);
3016 			retnum += NFSX_UNSIGNED;
3017 			break;
3018 		case NFSATTRBIT_XATTRSUPPORT:
3019 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3020 			if (xattrsupp)
3021 				*tl = newnfs_true;
3022 			else
3023 				*tl = newnfs_false;
3024 			retnum += NFSX_UNSIGNED;
3025 			break;
3026 		default:
3027 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3028 		}
3029 	    }
3030 	}
3031 	if (naclp != NULL)
3032 		acl_free(naclp);
3033 	free(fs, M_STATFS);
3034 	*retnump = txdr_unsigned(retnum);
3035 	return (retnum + prefixnum);
3036 }
3037 
3038 /*
3039  * Put the attribute bits onto an mbuf list.
3040  * Return the number of bytes of output generated.
3041  */
3042 int
3043 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3044 {
3045 	u_int32_t *tl;
3046 	int cnt, i, bytesize;
3047 
3048 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3049 		if (attrbitp->bits[cnt - 1])
3050 			break;
3051 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3052 	NFSM_BUILD(tl, u_int32_t *, bytesize);
3053 	*tl++ = txdr_unsigned(cnt);
3054 	for (i = 0; i < cnt; i++)
3055 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
3056 	return (bytesize);
3057 }
3058 
3059 /*
3060  * Convert a uid to a string.
3061  * If the lookup fails, just output the digits.
3062  * uid - the user id
3063  * cpp - points to a buffer of size NFSV4_SMALLSTR
3064  *       (malloc a larger one, as required)
3065  * retlenp - pointer to length to be returned
3066  */
3067 void
3068 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3069 {
3070 	int i;
3071 	struct nfsusrgrp *usrp;
3072 	u_char *cp = *cpp;
3073 	uid_t tmp;
3074 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3075 	struct nfsrv_lughash *hp;
3076 
3077 	cnt = 0;
3078 tryagain:
3079 	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3080 		/*
3081 		 * Always map nfsrv_defaultuid to "nobody".
3082 		 */
3083 		if (uid == nfsrv_defaultuid) {
3084 			i = nfsrv_dnsnamelen + 7;
3085 			if (i > len) {
3086 				if (len > NFSV4_SMALLSTR)
3087 					free(cp, M_NFSSTRING);
3088 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3089 				*cpp = cp;
3090 				len = i;
3091 				goto tryagain;
3092 			}
3093 			*retlenp = i;
3094 			NFSBCOPY("nobody@", cp, 7);
3095 			cp += 7;
3096 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3097 			return;
3098 		}
3099 		hasampersand = 0;
3100 		hp = NFSUSERHASH(uid);
3101 		mtx_lock(&hp->mtx);
3102 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3103 			if (usrp->lug_uid == uid) {
3104 				if (usrp->lug_expiry < NFSD_MONOSEC)
3105 					break;
3106 				/*
3107 				 * If the name doesn't already have an '@'
3108 				 * in it, append @domainname to it.
3109 				 */
3110 				for (i = 0; i < usrp->lug_namelen; i++) {
3111 					if (usrp->lug_name[i] == '@') {
3112 						hasampersand = 1;
3113 						break;
3114 					}
3115 				}
3116 				if (hasampersand)
3117 					i = usrp->lug_namelen;
3118 				else
3119 					i = usrp->lug_namelen +
3120 					    nfsrv_dnsnamelen + 1;
3121 				if (i > len) {
3122 					mtx_unlock(&hp->mtx);
3123 					if (len > NFSV4_SMALLSTR)
3124 						free(cp, M_NFSSTRING);
3125 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3126 					*cpp = cp;
3127 					len = i;
3128 					goto tryagain;
3129 				}
3130 				*retlenp = i;
3131 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3132 				if (!hasampersand) {
3133 					cp += usrp->lug_namelen;
3134 					*cp++ = '@';
3135 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3136 				}
3137 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3138 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3139 				    lug_numhash);
3140 				mtx_unlock(&hp->mtx);
3141 				return;
3142 			}
3143 		}
3144 		mtx_unlock(&hp->mtx);
3145 		cnt++;
3146 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3147 		if (ret == 0 && cnt < 2)
3148 			goto tryagain;
3149 	}
3150 
3151 	/*
3152 	 * No match, just return a string of digits.
3153 	 */
3154 	tmp = uid;
3155 	i = 0;
3156 	while (tmp || i == 0) {
3157 		tmp /= 10;
3158 		i++;
3159 	}
3160 	len = (i > len) ? len : i;
3161 	*retlenp = len;
3162 	cp += (len - 1);
3163 	tmp = uid;
3164 	for (i = 0; i < len; i++) {
3165 		*cp-- = '0' + (tmp % 10);
3166 		tmp /= 10;
3167 	}
3168 	return;
3169 }
3170 
3171 /*
3172  * Get a credential for the uid with the server's group list.
3173  * If none is found, just return the credential passed in after
3174  * logging a warning message.
3175  */
3176 struct ucred *
3177 nfsrv_getgrpscred(struct ucred *oldcred)
3178 {
3179 	struct nfsusrgrp *usrp;
3180 	struct ucred *newcred;
3181 	int cnt, ret;
3182 	uid_t uid;
3183 	struct nfsrv_lughash *hp;
3184 
3185 	cnt = 0;
3186 	uid = oldcred->cr_uid;
3187 tryagain:
3188 	if (nfsrv_dnsnamelen > 0) {
3189 		hp = NFSUSERHASH(uid);
3190 		mtx_lock(&hp->mtx);
3191 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3192 			if (usrp->lug_uid == uid) {
3193 				if (usrp->lug_expiry < NFSD_MONOSEC)
3194 					break;
3195 				if (usrp->lug_cred != NULL) {
3196 					newcred = crhold(usrp->lug_cred);
3197 					crfree(oldcred);
3198 				} else
3199 					newcred = oldcred;
3200 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3201 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3202 				    lug_numhash);
3203 				mtx_unlock(&hp->mtx);
3204 				return (newcred);
3205 			}
3206 		}
3207 		mtx_unlock(&hp->mtx);
3208 		cnt++;
3209 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3210 		if (ret == 0 && cnt < 2)
3211 			goto tryagain;
3212 	}
3213 	return (oldcred);
3214 }
3215 
3216 /*
3217  * Convert a string to a uid.
3218  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3219  * return 0.
3220  * If this is called from a client side mount using AUTH_SYS and the
3221  * string is made up entirely of digits, just convert the string to
3222  * a number.
3223  */
3224 int
3225 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3226 {
3227 	int i;
3228 	char *cp, *endstr, *str0;
3229 	struct nfsusrgrp *usrp;
3230 	int cnt, ret;
3231 	int error = 0;
3232 	uid_t tuid;
3233 	struct nfsrv_lughash *hp, *hp2;
3234 
3235 	if (len == 0) {
3236 		error = NFSERR_BADOWNER;
3237 		goto out;
3238 	}
3239 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3240 	str0 = str;
3241 	tuid = (uid_t)strtoul(str0, &endstr, 10);
3242 	if ((endstr - str0) == len) {
3243 		/* A numeric string. */
3244 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3245 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3246 		      nfsd_enable_stringtouid != 0))
3247 			*uidp = tuid;
3248 		else
3249 			error = NFSERR_BADOWNER;
3250 		goto out;
3251 	}
3252 	/*
3253 	 * Look for an '@'.
3254 	 */
3255 	cp = strchr(str0, '@');
3256 	if (cp != NULL)
3257 		i = (int)(cp++ - str0);
3258 	else
3259 		i = len;
3260 
3261 	cnt = 0;
3262 tryagain:
3263 	if (nfsrv_dnsnamelen > 0) {
3264 		/*
3265 		 * If an '@' is found and the domain name matches, search for
3266 		 * the name with dns stripped off.
3267 		 * Mixed case alpahbetics will match for the domain name, but
3268 		 * all upper case will not.
3269 		 */
3270 		if (cnt == 0 && i < len && i > 0 &&
3271 		    (len - 1 - i) == nfsrv_dnsnamelen &&
3272 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3273 			len -= (nfsrv_dnsnamelen + 1);
3274 			*(cp - 1) = '\0';
3275 		}
3276 
3277 		/*
3278 		 * Check for the special case of "nobody".
3279 		 */
3280 		if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3281 			*uidp = nfsrv_defaultuid;
3282 			error = 0;
3283 			goto out;
3284 		}
3285 
3286 		hp = NFSUSERNAMEHASH(str, len);
3287 		mtx_lock(&hp->mtx);
3288 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3289 			if (usrp->lug_namelen == len &&
3290 			    !NFSBCMP(usrp->lug_name, str, len)) {
3291 				if (usrp->lug_expiry < NFSD_MONOSEC)
3292 					break;
3293 				hp2 = NFSUSERHASH(usrp->lug_uid);
3294 				mtx_lock(&hp2->mtx);
3295 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3296 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3297 				    lug_numhash);
3298 				*uidp = usrp->lug_uid;
3299 				mtx_unlock(&hp2->mtx);
3300 				mtx_unlock(&hp->mtx);
3301 				error = 0;
3302 				goto out;
3303 			}
3304 		}
3305 		mtx_unlock(&hp->mtx);
3306 		cnt++;
3307 		ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3308 		    str);
3309 		if (ret == 0 && cnt < 2)
3310 			goto tryagain;
3311 	}
3312 	error = NFSERR_BADOWNER;
3313 
3314 out:
3315 	NFSEXITCODE(error);
3316 	return (error);
3317 }
3318 
3319 /*
3320  * Convert a gid to a string.
3321  * gid - the group id
3322  * cpp - points to a buffer of size NFSV4_SMALLSTR
3323  *       (malloc a larger one, as required)
3324  * retlenp - pointer to length to be returned
3325  */
3326 void
3327 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3328 {
3329 	int i;
3330 	struct nfsusrgrp *usrp;
3331 	u_char *cp = *cpp;
3332 	gid_t tmp;
3333 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3334 	struct nfsrv_lughash *hp;
3335 
3336 	cnt = 0;
3337 tryagain:
3338 	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3339 		/*
3340 		 * Always map nfsrv_defaultgid to "nogroup".
3341 		 */
3342 		if (gid == nfsrv_defaultgid) {
3343 			i = nfsrv_dnsnamelen + 8;
3344 			if (i > len) {
3345 				if (len > NFSV4_SMALLSTR)
3346 					free(cp, M_NFSSTRING);
3347 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3348 				*cpp = cp;
3349 				len = i;
3350 				goto tryagain;
3351 			}
3352 			*retlenp = i;
3353 			NFSBCOPY("nogroup@", cp, 8);
3354 			cp += 8;
3355 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3356 			return;
3357 		}
3358 		hasampersand = 0;
3359 		hp = NFSGROUPHASH(gid);
3360 		mtx_lock(&hp->mtx);
3361 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3362 			if (usrp->lug_gid == gid) {
3363 				if (usrp->lug_expiry < NFSD_MONOSEC)
3364 					break;
3365 				/*
3366 				 * If the name doesn't already have an '@'
3367 				 * in it, append @domainname to it.
3368 				 */
3369 				for (i = 0; i < usrp->lug_namelen; i++) {
3370 					if (usrp->lug_name[i] == '@') {
3371 						hasampersand = 1;
3372 						break;
3373 					}
3374 				}
3375 				if (hasampersand)
3376 					i = usrp->lug_namelen;
3377 				else
3378 					i = usrp->lug_namelen +
3379 					    nfsrv_dnsnamelen + 1;
3380 				if (i > len) {
3381 					mtx_unlock(&hp->mtx);
3382 					if (len > NFSV4_SMALLSTR)
3383 						free(cp, M_NFSSTRING);
3384 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3385 					*cpp = cp;
3386 					len = i;
3387 					goto tryagain;
3388 				}
3389 				*retlenp = i;
3390 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3391 				if (!hasampersand) {
3392 					cp += usrp->lug_namelen;
3393 					*cp++ = '@';
3394 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3395 				}
3396 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3397 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3398 				    lug_numhash);
3399 				mtx_unlock(&hp->mtx);
3400 				return;
3401 			}
3402 		}
3403 		mtx_unlock(&hp->mtx);
3404 		cnt++;
3405 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3406 		if (ret == 0 && cnt < 2)
3407 			goto tryagain;
3408 	}
3409 
3410 	/*
3411 	 * No match, just return a string of digits.
3412 	 */
3413 	tmp = gid;
3414 	i = 0;
3415 	while (tmp || i == 0) {
3416 		tmp /= 10;
3417 		i++;
3418 	}
3419 	len = (i > len) ? len : i;
3420 	*retlenp = len;
3421 	cp += (len - 1);
3422 	tmp = gid;
3423 	for (i = 0; i < len; i++) {
3424 		*cp-- = '0' + (tmp % 10);
3425 		tmp /= 10;
3426 	}
3427 	return;
3428 }
3429 
3430 /*
3431  * Convert a string to a gid.
3432  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3433  * return 0.
3434  * If this is called from a client side mount using AUTH_SYS and the
3435  * string is made up entirely of digits, just convert the string to
3436  * a number.
3437  */
3438 int
3439 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3440 {
3441 	int i;
3442 	char *cp, *endstr, *str0;
3443 	struct nfsusrgrp *usrp;
3444 	int cnt, ret;
3445 	int error = 0;
3446 	gid_t tgid;
3447 	struct nfsrv_lughash *hp, *hp2;
3448 
3449 	if (len == 0) {
3450 		error =  NFSERR_BADOWNER;
3451 		goto out;
3452 	}
3453 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3454 	str0 = str;
3455 	tgid = (gid_t)strtoul(str0, &endstr, 10);
3456 	if ((endstr - str0) == len) {
3457 		/* A numeric string. */
3458 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3459 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3460 		      nfsd_enable_stringtouid != 0))
3461 			*gidp = tgid;
3462 		else
3463 			error = NFSERR_BADOWNER;
3464 		goto out;
3465 	}
3466 	/*
3467 	 * Look for an '@'.
3468 	 */
3469 	cp = strchr(str0, '@');
3470 	if (cp != NULL)
3471 		i = (int)(cp++ - str0);
3472 	else
3473 		i = len;
3474 
3475 	cnt = 0;
3476 tryagain:
3477 	if (nfsrv_dnsnamelen > 0) {
3478 		/*
3479 		 * If an '@' is found and the dns name matches, search for the
3480 		 * name with the dns stripped off.
3481 		 */
3482 		if (cnt == 0 && i < len && i > 0 &&
3483 		    (len - 1 - i) == nfsrv_dnsnamelen &&
3484 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3485 			len -= (nfsrv_dnsnamelen + 1);
3486 			*(cp - 1) = '\0';
3487 		}
3488 
3489 		/*
3490 		 * Check for the special case of "nogroup".
3491 		 */
3492 		if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3493 			*gidp = nfsrv_defaultgid;
3494 			error = 0;
3495 			goto out;
3496 		}
3497 
3498 		hp = NFSGROUPNAMEHASH(str, len);
3499 		mtx_lock(&hp->mtx);
3500 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3501 			if (usrp->lug_namelen == len &&
3502 			    !NFSBCMP(usrp->lug_name, str, len)) {
3503 				if (usrp->lug_expiry < NFSD_MONOSEC)
3504 					break;
3505 				hp2 = NFSGROUPHASH(usrp->lug_gid);
3506 				mtx_lock(&hp2->mtx);
3507 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3508 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3509 				    lug_numhash);
3510 				*gidp = usrp->lug_gid;
3511 				mtx_unlock(&hp2->mtx);
3512 				mtx_unlock(&hp->mtx);
3513 				error = 0;
3514 				goto out;
3515 			}
3516 		}
3517 		mtx_unlock(&hp->mtx);
3518 		cnt++;
3519 		ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3520 		    str);
3521 		if (ret == 0 && cnt < 2)
3522 			goto tryagain;
3523 	}
3524 	error = NFSERR_BADOWNER;
3525 
3526 out:
3527 	NFSEXITCODE(error);
3528 	return (error);
3529 }
3530 
3531 /*
3532  * Cmp len chars, allowing mixed case in the first argument to match lower
3533  * case in the second, but not if the first argument is all upper case.
3534  * Return 0 for a match, 1 otherwise.
3535  */
3536 static int
3537 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3538 {
3539 	int i;
3540 	u_char tmp;
3541 	int fndlower = 0;
3542 
3543 	for (i = 0; i < len; i++) {
3544 		if (*cp >= 'A' && *cp <= 'Z') {
3545 			tmp = *cp++ + ('a' - 'A');
3546 		} else {
3547 			tmp = *cp++;
3548 			if (tmp >= 'a' && tmp <= 'z')
3549 				fndlower = 1;
3550 		}
3551 		if (tmp != *cp2++)
3552 			return (1);
3553 	}
3554 	if (fndlower)
3555 		return (0);
3556 	else
3557 		return (1);
3558 }
3559 
3560 /*
3561  * Set the port for the nfsuserd.
3562  */
3563 int
3564 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3565 {
3566 	struct nfssockreq *rp;
3567 #ifdef INET
3568 	struct sockaddr_in *ad;
3569 #endif
3570 #ifdef INET6
3571 	struct sockaddr_in6 *ad6;
3572 	const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3573 #endif
3574 	int error;
3575 
3576 	NFSLOCKNAMEID();
3577 	if (nfsrv_nfsuserd != NOTRUNNING) {
3578 		NFSUNLOCKNAMEID();
3579 		error = EPERM;
3580 		goto out;
3581 	}
3582 	nfsrv_nfsuserd = STARTSTOP;
3583 	/*
3584 	 * Set up the socket record and connect.
3585 	 * Set nr_client NULL before unlocking, just to ensure that no other
3586 	 * process/thread/core will use a bogus old value.  This could only
3587 	 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3588 	 * broken.
3589 	 */
3590 	rp = &nfsrv_nfsuserdsock;
3591 	rp->nr_client = NULL;
3592 	NFSUNLOCKNAMEID();
3593 	rp->nr_sotype = SOCK_DGRAM;
3594 	rp->nr_soproto = IPPROTO_UDP;
3595 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3596 	rp->nr_cred = NULL;
3597 	rp->nr_prog = RPCPROG_NFSUSERD;
3598 	error = 0;
3599 	switch (nargs->nuserd_family) {
3600 #ifdef INET
3601 	case AF_INET:
3602 		rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3603 		    M_WAITOK | M_ZERO);
3604  		ad = (struct sockaddr_in *)rp->nr_nam;
3605 		ad->sin_len = sizeof(struct sockaddr_in);
3606  		ad->sin_family = AF_INET;
3607 		ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3608 		ad->sin_port = nargs->nuserd_port;
3609 		break;
3610 #endif
3611 #ifdef INET6
3612 	case AF_INET6:
3613 		rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3614 		    M_WAITOK | M_ZERO);
3615 		ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3616 		ad6->sin6_len = sizeof(struct sockaddr_in6);
3617 		ad6->sin6_family = AF_INET6;
3618 		ad6->sin6_addr = in6loopback;
3619 		ad6->sin6_port = nargs->nuserd_port;
3620 		break;
3621 #endif
3622 	default:
3623 		error = ENXIO;
3624  	}
3625 	rp->nr_vers = RPCNFSUSERD_VERS;
3626 	if (error == 0)
3627 		error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false,
3628 		    &rp->nr_client);
3629 	if (error == 0) {
3630 		NFSLOCKNAMEID();
3631 		nfsrv_nfsuserd = RUNNING;
3632 		NFSUNLOCKNAMEID();
3633 	} else {
3634 		free(rp->nr_nam, M_SONAME);
3635 		NFSLOCKNAMEID();
3636 		nfsrv_nfsuserd = NOTRUNNING;
3637 		NFSUNLOCKNAMEID();
3638 	}
3639 out:
3640 	NFSEXITCODE(error);
3641 	return (error);
3642 }
3643 
3644 /*
3645  * Delete the nfsuserd port.
3646  */
3647 void
3648 nfsrv_nfsuserddelport(void)
3649 {
3650 
3651 	NFSLOCKNAMEID();
3652 	if (nfsrv_nfsuserd != RUNNING) {
3653 		NFSUNLOCKNAMEID();
3654 		return;
3655 	}
3656 	nfsrv_nfsuserd = STARTSTOP;
3657 	/* Wait for all upcalls to complete. */
3658 	while (nfsrv_userdupcalls > 0)
3659 		msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3660 		    "nfsupcalls", 0);
3661 	NFSUNLOCKNAMEID();
3662 	newnfs_disconnect(NULL, &nfsrv_nfsuserdsock);
3663 	free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3664 	NFSLOCKNAMEID();
3665 	nfsrv_nfsuserd = NOTRUNNING;
3666 	NFSUNLOCKNAMEID();
3667 }
3668 
3669 /*
3670  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3671  * name<-->id cache.
3672  * Returns 0 upon success, non-zero otherwise.
3673  */
3674 static int
3675 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3676 {
3677 	u_int32_t *tl;
3678 	struct nfsrv_descript *nd;
3679 	int len;
3680 	struct nfsrv_descript nfsd;
3681 	struct ucred *cred;
3682 	int error;
3683 
3684 	NFSLOCKNAMEID();
3685 	if (nfsrv_nfsuserd != RUNNING) {
3686 		NFSUNLOCKNAMEID();
3687 		error = EPERM;
3688 		goto out;
3689 	}
3690 	/*
3691 	 * Maintain a count of upcalls in progress, so that nfsrv_X()
3692 	 * can wait until no upcalls are in progress.
3693 	 */
3694 	nfsrv_userdupcalls++;
3695 	NFSUNLOCKNAMEID();
3696 	KASSERT(nfsrv_userdupcalls > 0,
3697 	    ("nfsrv_getuser: non-positive upcalls"));
3698 	nd = &nfsd;
3699 	cred = newnfs_getcred();
3700 	nd->nd_flag = ND_GSSINITREPLY;
3701 	nfsrvd_rephead(nd);
3702 
3703 	nd->nd_procnum = procnum;
3704 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3705 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3706 		if (procnum == RPCNFSUSERD_GETUID)
3707 			*tl = txdr_unsigned(uid);
3708 		else
3709 			*tl = txdr_unsigned(gid);
3710 	} else {
3711 		len = strlen(name);
3712 		(void) nfsm_strtom(nd, name, len);
3713 	}
3714 	error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3715 		cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3716 	NFSLOCKNAMEID();
3717 	if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3718 		wakeup(&nfsrv_userdupcalls);
3719 	NFSUNLOCKNAMEID();
3720 	NFSFREECRED(cred);
3721 	if (!error) {
3722 		m_freem(nd->nd_mrep);
3723 		error = nd->nd_repstat;
3724 	}
3725 out:
3726 	NFSEXITCODE(error);
3727 	return (error);
3728 }
3729 
3730 /*
3731  * This function is called from the nfssvc(2) system call, to update the
3732  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3733  */
3734 int
3735 nfssvc_idname(struct nfsd_idargs *nidp)
3736 {
3737 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
3738 	struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3739 	int i, group_locked, groupname_locked, user_locked, username_locked;
3740 	int error = 0;
3741 	u_char *cp;
3742 	gid_t *grps;
3743 	struct ucred *cr;
3744 	static int onethread = 0;
3745 	static time_t lasttime = 0;
3746 
3747 	if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3748 		error = EINVAL;
3749 		goto out;
3750 	}
3751 	if (nidp->nid_flag & NFSID_INITIALIZE) {
3752 		cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3753 		error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3754 		if (error != 0) {
3755 			free(cp, M_NFSSTRING);
3756 			goto out;
3757 		}
3758 		if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3759 			/*
3760 			 * Free up all the old stuff and reinitialize hash
3761 			 * lists.  All mutexes for both lists must be locked,
3762 			 * with the user/group name ones before the uid/gid
3763 			 * ones, to avoid a LOR.
3764 			 */
3765 			for (i = 0; i < nfsrv_lughashsize; i++)
3766 				mtx_lock(&nfsusernamehash[i].mtx);
3767 			for (i = 0; i < nfsrv_lughashsize; i++)
3768 				mtx_lock(&nfsuserhash[i].mtx);
3769 			for (i = 0; i < nfsrv_lughashsize; i++)
3770 				TAILQ_FOREACH_SAFE(usrp,
3771 				    &nfsuserhash[i].lughead, lug_numhash, nusrp)
3772 					nfsrv_removeuser(usrp, 1);
3773 			for (i = 0; i < nfsrv_lughashsize; i++)
3774 				mtx_unlock(&nfsuserhash[i].mtx);
3775 			for (i = 0; i < nfsrv_lughashsize; i++)
3776 				mtx_unlock(&nfsusernamehash[i].mtx);
3777 			for (i = 0; i < nfsrv_lughashsize; i++)
3778 				mtx_lock(&nfsgroupnamehash[i].mtx);
3779 			for (i = 0; i < nfsrv_lughashsize; i++)
3780 				mtx_lock(&nfsgrouphash[i].mtx);
3781 			for (i = 0; i < nfsrv_lughashsize; i++)
3782 				TAILQ_FOREACH_SAFE(usrp,
3783 				    &nfsgrouphash[i].lughead, lug_numhash,
3784 				    nusrp)
3785 					nfsrv_removeuser(usrp, 0);
3786 			for (i = 0; i < nfsrv_lughashsize; i++)
3787 				mtx_unlock(&nfsgrouphash[i].mtx);
3788 			for (i = 0; i < nfsrv_lughashsize; i++)
3789 				mtx_unlock(&nfsgroupnamehash[i].mtx);
3790 			free(nfsrv_dnsname, M_NFSSTRING);
3791 			nfsrv_dnsname = NULL;
3792 		}
3793 		if (nfsuserhash == NULL) {
3794 			/* Allocate the hash tables. */
3795 			nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3796 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3797 			    M_ZERO);
3798 			for (i = 0; i < nfsrv_lughashsize; i++)
3799 				mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3800 				    NULL, MTX_DEF | MTX_DUPOK);
3801 			nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3802 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3803 			    M_ZERO);
3804 			for (i = 0; i < nfsrv_lughashsize; i++)
3805 				mtx_init(&nfsusernamehash[i].mtx,
3806 				    "nfsusrhash", NULL, MTX_DEF |
3807 				    MTX_DUPOK);
3808 			nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3809 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3810 			    M_ZERO);
3811 			for (i = 0; i < nfsrv_lughashsize; i++)
3812 				mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3813 				    NULL, MTX_DEF | MTX_DUPOK);
3814 			nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3815 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3816 			    M_ZERO);
3817 			for (i = 0; i < nfsrv_lughashsize; i++)
3818 			    mtx_init(&nfsgroupnamehash[i].mtx,
3819 			    "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3820 		}
3821 		/* (Re)initialize the list heads. */
3822 		for (i = 0; i < nfsrv_lughashsize; i++)
3823 			TAILQ_INIT(&nfsuserhash[i].lughead);
3824 		for (i = 0; i < nfsrv_lughashsize; i++)
3825 			TAILQ_INIT(&nfsusernamehash[i].lughead);
3826 		for (i = 0; i < nfsrv_lughashsize; i++)
3827 			TAILQ_INIT(&nfsgrouphash[i].lughead);
3828 		for (i = 0; i < nfsrv_lughashsize; i++)
3829 			TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3830 
3831 		/*
3832 		 * Put name in "DNS" string.
3833 		 */
3834 		nfsrv_dnsname = cp;
3835 		nfsrv_defaultuid = nidp->nid_uid;
3836 		nfsrv_defaultgid = nidp->nid_gid;
3837 		nfsrv_usercnt = 0;
3838 		nfsrv_usermax = nidp->nid_usermax;
3839 		atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3840 		goto out;
3841 	}
3842 
3843 	/*
3844 	 * malloc the new one now, so any potential sleep occurs before
3845 	 * manipulation of the lists.
3846 	 */
3847 	newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3848 	    M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3849 	error = copyin(nidp->nid_name, newusrp->lug_name,
3850 	    nidp->nid_namelen);
3851 	if (error == 0 && nidp->nid_ngroup > 0 &&
3852 	    (nidp->nid_flag & NFSID_ADDUID) != 0) {
3853 		grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3854 		    M_WAITOK);
3855 		error = copyin(nidp->nid_grps, grps,
3856 		    sizeof(gid_t) * nidp->nid_ngroup);
3857 		if (error == 0) {
3858 			/*
3859 			 * Create a credential just like svc_getcred(),
3860 			 * but using the group list provided.
3861 			 */
3862 			cr = crget();
3863 			cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3864 			crsetgroups(cr, nidp->nid_ngroup, grps);
3865 			cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3866 			cr->cr_prison = &prison0;
3867 			prison_hold(cr->cr_prison);
3868 #ifdef MAC
3869 			mac_cred_associate_nfsd(cr);
3870 #endif
3871 			newusrp->lug_cred = cr;
3872 		}
3873 		free(grps, M_TEMP);
3874 	}
3875 	if (error) {
3876 		free(newusrp, M_NFSUSERGROUP);
3877 		goto out;
3878 	}
3879 	newusrp->lug_namelen = nidp->nid_namelen;
3880 
3881 	/*
3882 	 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3883 	 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3884 	 * The flags user_locked, username_locked, group_locked and
3885 	 * groupname_locked are set to indicate all of those hash lists are
3886 	 * locked. hp_name != NULL  and hp_idnum != NULL indicates that
3887 	 * the respective one mutex is locked.
3888 	 */
3889 	user_locked = username_locked = group_locked = groupname_locked = 0;
3890 	hp_name = hp_idnum = NULL;
3891 
3892 	/*
3893 	 * Delete old entries, as required.
3894 	 */
3895 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3896 		/* Must lock all username hash lists first, to avoid a LOR. */
3897 		for (i = 0; i < nfsrv_lughashsize; i++)
3898 			mtx_lock(&nfsusernamehash[i].mtx);
3899 		username_locked = 1;
3900 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
3901 		mtx_lock(&hp_idnum->mtx);
3902 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3903 		    nusrp) {
3904 			if (usrp->lug_uid == nidp->nid_uid)
3905 				nfsrv_removeuser(usrp, 1);
3906 		}
3907 	} else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3908 		hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3909 		    newusrp->lug_namelen);
3910 		mtx_lock(&hp_name->mtx);
3911 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3912 		    nusrp) {
3913 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3914 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3915 			    usrp->lug_namelen)) {
3916 				thp = NFSUSERHASH(usrp->lug_uid);
3917 				mtx_lock(&thp->mtx);
3918 				nfsrv_removeuser(usrp, 1);
3919 				mtx_unlock(&thp->mtx);
3920 			}
3921 		}
3922 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
3923 		mtx_lock(&hp_idnum->mtx);
3924 	} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3925 		/* Must lock all groupname hash lists first, to avoid a LOR. */
3926 		for (i = 0; i < nfsrv_lughashsize; i++)
3927 			mtx_lock(&nfsgroupnamehash[i].mtx);
3928 		groupname_locked = 1;
3929 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3930 		mtx_lock(&hp_idnum->mtx);
3931 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3932 		    nusrp) {
3933 			if (usrp->lug_gid == nidp->nid_gid)
3934 				nfsrv_removeuser(usrp, 0);
3935 		}
3936 	} else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3937 		hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3938 		    newusrp->lug_namelen);
3939 		mtx_lock(&hp_name->mtx);
3940 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3941 		    nusrp) {
3942 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3943 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3944 			    usrp->lug_namelen)) {
3945 				thp = NFSGROUPHASH(usrp->lug_gid);
3946 				mtx_lock(&thp->mtx);
3947 				nfsrv_removeuser(usrp, 0);
3948 				mtx_unlock(&thp->mtx);
3949 			}
3950 		}
3951 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3952 		mtx_lock(&hp_idnum->mtx);
3953 	}
3954 
3955 	/*
3956 	 * Now, we can add the new one.
3957 	 */
3958 	if (nidp->nid_usertimeout)
3959 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3960 	else
3961 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
3962 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3963 		newusrp->lug_uid = nidp->nid_uid;
3964 		thp = NFSUSERHASH(newusrp->lug_uid);
3965 		mtx_assert(&thp->mtx, MA_OWNED);
3966 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3967 		thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3968 		mtx_assert(&thp->mtx, MA_OWNED);
3969 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3970 		atomic_add_int(&nfsrv_usercnt, 1);
3971 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3972 		newusrp->lug_gid = nidp->nid_gid;
3973 		thp = NFSGROUPHASH(newusrp->lug_gid);
3974 		mtx_assert(&thp->mtx, MA_OWNED);
3975 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3976 		thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3977 		mtx_assert(&thp->mtx, MA_OWNED);
3978 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3979 		atomic_add_int(&nfsrv_usercnt, 1);
3980 	} else {
3981 		if (newusrp->lug_cred != NULL)
3982 			crfree(newusrp->lug_cred);
3983 		free(newusrp, M_NFSUSERGROUP);
3984 	}
3985 
3986 	/*
3987 	 * Once per second, allow one thread to trim the cache.
3988 	 */
3989 	if (lasttime < NFSD_MONOSEC &&
3990 	    atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3991 		/*
3992 		 * First, unlock the single mutexes, so that all entries
3993 		 * can be locked and any LOR is avoided.
3994 		 */
3995 		if (hp_name != NULL) {
3996 			mtx_unlock(&hp_name->mtx);
3997 			hp_name = NULL;
3998 		}
3999 		if (hp_idnum != NULL) {
4000 			mtx_unlock(&hp_idnum->mtx);
4001 			hp_idnum = NULL;
4002 		}
4003 
4004 		if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4005 		    NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4006 			if (username_locked == 0) {
4007 				for (i = 0; i < nfsrv_lughashsize; i++)
4008 					mtx_lock(&nfsusernamehash[i].mtx);
4009 				username_locked = 1;
4010 			}
4011 			KASSERT(user_locked == 0,
4012 			    ("nfssvc_idname: user_locked"));
4013 			for (i = 0; i < nfsrv_lughashsize; i++)
4014 				mtx_lock(&nfsuserhash[i].mtx);
4015 			user_locked = 1;
4016 			for (i = 0; i < nfsrv_lughashsize; i++) {
4017 				TAILQ_FOREACH_SAFE(usrp,
4018 				    &nfsuserhash[i].lughead, lug_numhash,
4019 				    nusrp)
4020 					if (usrp->lug_expiry < NFSD_MONOSEC)
4021 						nfsrv_removeuser(usrp, 1);
4022 			}
4023 			for (i = 0; i < nfsrv_lughashsize; i++) {
4024 				/*
4025 				 * Trim the cache using an approximate LRU
4026 				 * algorithm.  This code deletes the least
4027 				 * recently used entry on each hash list.
4028 				 */
4029 				if (nfsrv_usercnt <= nfsrv_usermax)
4030 					break;
4031 				usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
4032 				if (usrp != NULL)
4033 					nfsrv_removeuser(usrp, 1);
4034 			}
4035 		} else {
4036 			if (groupname_locked == 0) {
4037 				for (i = 0; i < nfsrv_lughashsize; i++)
4038 					mtx_lock(&nfsgroupnamehash[i].mtx);
4039 				groupname_locked = 1;
4040 			}
4041 			KASSERT(group_locked == 0,
4042 			    ("nfssvc_idname: group_locked"));
4043 			for (i = 0; i < nfsrv_lughashsize; i++)
4044 				mtx_lock(&nfsgrouphash[i].mtx);
4045 			group_locked = 1;
4046 			for (i = 0; i < nfsrv_lughashsize; i++) {
4047 				TAILQ_FOREACH_SAFE(usrp,
4048 				    &nfsgrouphash[i].lughead, lug_numhash,
4049 				    nusrp)
4050 					if (usrp->lug_expiry < NFSD_MONOSEC)
4051 						nfsrv_removeuser(usrp, 0);
4052 			}
4053 			for (i = 0; i < nfsrv_lughashsize; i++) {
4054 				/*
4055 				 * Trim the cache using an approximate LRU
4056 				 * algorithm.  This code deletes the least
4057 				 * recently user entry on each hash list.
4058 				 */
4059 				if (nfsrv_usercnt <= nfsrv_usermax)
4060 					break;
4061 				usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4062 				if (usrp != NULL)
4063 					nfsrv_removeuser(usrp, 0);
4064 			}
4065 		}
4066 		lasttime = NFSD_MONOSEC;
4067 		atomic_store_rel_int(&onethread, 0);
4068 	}
4069 
4070 	/* Now, unlock all locked mutexes. */
4071 	if (hp_idnum != NULL)
4072 		mtx_unlock(&hp_idnum->mtx);
4073 	if (hp_name != NULL)
4074 		mtx_unlock(&hp_name->mtx);
4075 	if (user_locked != 0)
4076 		for (i = 0; i < nfsrv_lughashsize; i++)
4077 			mtx_unlock(&nfsuserhash[i].mtx);
4078 	if (username_locked != 0)
4079 		for (i = 0; i < nfsrv_lughashsize; i++)
4080 			mtx_unlock(&nfsusernamehash[i].mtx);
4081 	if (group_locked != 0)
4082 		for (i = 0; i < nfsrv_lughashsize; i++)
4083 			mtx_unlock(&nfsgrouphash[i].mtx);
4084 	if (groupname_locked != 0)
4085 		for (i = 0; i < nfsrv_lughashsize; i++)
4086 			mtx_unlock(&nfsgroupnamehash[i].mtx);
4087 out:
4088 	NFSEXITCODE(error);
4089 	return (error);
4090 }
4091 
4092 /*
4093  * Remove a user/group name element.
4094  */
4095 static void
4096 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4097 {
4098 	struct nfsrv_lughash *hp;
4099 
4100 	if (isuser != 0) {
4101 		hp = NFSUSERHASH(usrp->lug_uid);
4102 		mtx_assert(&hp->mtx, MA_OWNED);
4103 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4104 		hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4105 		mtx_assert(&hp->mtx, MA_OWNED);
4106 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4107 	} else {
4108 		hp = NFSGROUPHASH(usrp->lug_gid);
4109 		mtx_assert(&hp->mtx, MA_OWNED);
4110 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4111 		hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4112 		mtx_assert(&hp->mtx, MA_OWNED);
4113 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4114 	}
4115 	atomic_add_int(&nfsrv_usercnt, -1);
4116 	if (usrp->lug_cred != NULL)
4117 		crfree(usrp->lug_cred);
4118 	free(usrp, M_NFSUSERGROUP);
4119 }
4120 
4121 /*
4122  * Free up all the allocations related to the name<-->id cache.
4123  * This function should only be called when the nfsuserd daemon isn't
4124  * running, since it doesn't do any locking.
4125  * This function is meant to be used when the nfscommon module is unloaded.
4126  */
4127 void
4128 nfsrv_cleanusergroup(void)
4129 {
4130 	struct nfsrv_lughash *hp, *hp2;
4131 	struct nfsusrgrp *nusrp, *usrp;
4132 	int i;
4133 
4134 	if (nfsuserhash == NULL)
4135 		return;
4136 
4137 	for (i = 0; i < nfsrv_lughashsize; i++) {
4138 		hp = &nfsuserhash[i];
4139 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4140 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4141 			hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4142 			    usrp->lug_namelen);
4143 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4144 			if (usrp->lug_cred != NULL)
4145 				crfree(usrp->lug_cred);
4146 			free(usrp, M_NFSUSERGROUP);
4147 		}
4148 		hp = &nfsgrouphash[i];
4149 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4150 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4151 			hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4152 			    usrp->lug_namelen);
4153 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4154 			if (usrp->lug_cred != NULL)
4155 				crfree(usrp->lug_cred);
4156 			free(usrp, M_NFSUSERGROUP);
4157 		}
4158 		mtx_destroy(&nfsuserhash[i].mtx);
4159 		mtx_destroy(&nfsusernamehash[i].mtx);
4160 		mtx_destroy(&nfsgroupnamehash[i].mtx);
4161 		mtx_destroy(&nfsgrouphash[i].mtx);
4162 	}
4163 	free(nfsuserhash, M_NFSUSERGROUP);
4164 	free(nfsusernamehash, M_NFSUSERGROUP);
4165 	free(nfsgrouphash, M_NFSUSERGROUP);
4166 	free(nfsgroupnamehash, M_NFSUSERGROUP);
4167 	free(nfsrv_dnsname, M_NFSSTRING);
4168 }
4169 
4170 /*
4171  * This function scans a byte string and checks for UTF-8 compliance.
4172  * It returns 0 if it conforms and NFSERR_INVAL if not.
4173  */
4174 int
4175 nfsrv_checkutf8(u_int8_t *cp, int len)
4176 {
4177 	u_int32_t val = 0x0;
4178 	int cnt = 0, gotd = 0, shift = 0;
4179 	u_int8_t byte;
4180 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4181 	int error = 0;
4182 
4183 	/*
4184 	 * Here are what the variables are used for:
4185 	 * val - the calculated value of a multibyte char, used to check
4186 	 *       that it was coded with the correct range
4187 	 * cnt - the number of 10xxxxxx bytes to follow
4188 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4189 	 * shift - lower order bits of range (ie. "val >> shift" should
4190 	 *       not be 0, in other words, dividing by the lower bound
4191 	 *       of the range should get a non-zero value)
4192 	 * byte - used to calculate cnt
4193 	 */
4194 	while (len > 0) {
4195 		if (cnt > 0) {
4196 			/* This handles the 10xxxxxx bytes */
4197 			if ((*cp & 0xc0) != 0x80 ||
4198 			    (gotd && (*cp & 0x20))) {
4199 				error = NFSERR_INVAL;
4200 				goto out;
4201 			}
4202 			gotd = 0;
4203 			val <<= 6;
4204 			val |= (*cp & 0x3f);
4205 			cnt--;
4206 			if (cnt == 0 && (val >> shift) == 0x0) {
4207 				error = NFSERR_INVAL;
4208 				goto out;
4209 			}
4210 		} else if (*cp & 0x80) {
4211 			/* first byte of multi byte char */
4212 			byte = *cp;
4213 			while ((byte & 0x40) && cnt < 6) {
4214 				cnt++;
4215 				byte <<= 1;
4216 			}
4217 			if (cnt == 0 || cnt == 6) {
4218 				error = NFSERR_INVAL;
4219 				goto out;
4220 			}
4221 			val = (*cp & (0x3f >> cnt));
4222 			shift = utf8_shift[cnt - 1];
4223 			if (cnt == 2 && val == 0xd)
4224 				/* Check for the 0xd800-0xdfff case */
4225 				gotd = 1;
4226 		}
4227 		cp++;
4228 		len--;
4229 	}
4230 	if (cnt > 0)
4231 		error = NFSERR_INVAL;
4232 
4233 out:
4234 	NFSEXITCODE(error);
4235 	return (error);
4236 }
4237 
4238 /*
4239  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4240  * strings, one with the root path in it and the other with the list of
4241  * locations. The list is in the same format as is found in nfr_refs.
4242  * It is a "," separated list of entries, where each of them is of the
4243  * form <server>:<rootpath>. For example
4244  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4245  * The nilp argument is set to 1 for the special case of a null fs_root
4246  * and an empty server list.
4247  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4248  * number of xdr bytes parsed in sump.
4249  */
4250 static int
4251 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4252     int *sump, int *nilp)
4253 {
4254 	u_int32_t *tl;
4255 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4256 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4257 	struct list {
4258 		SLIST_ENTRY(list) next;
4259 		int len;
4260 		u_char host[1];
4261 	} *lsp, *nlsp;
4262 	SLIST_HEAD(, list) head;
4263 
4264 	*fsrootp = NULL;
4265 	*srvp = NULL;
4266 	*nilp = 0;
4267 
4268 	/*
4269 	 * Get the fs_root path and check for the special case of null path
4270 	 * and 0 length server list.
4271 	 */
4272 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4273 	len = fxdr_unsigned(int, *tl);
4274 	if (len < 0 || len > 10240) {
4275 		error = NFSERR_BADXDR;
4276 		goto nfsmout;
4277 	}
4278 	if (len == 0) {
4279 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4280 		if (*tl != 0) {
4281 			error = NFSERR_BADXDR;
4282 			goto nfsmout;
4283 		}
4284 		*nilp = 1;
4285 		*sump = 2 * NFSX_UNSIGNED;
4286 		error = 0;
4287 		goto nfsmout;
4288 	}
4289 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4290 	error = nfsrv_mtostr(nd, cp, len);
4291 	if (!error) {
4292 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4293 		cnt = fxdr_unsigned(int, *tl);
4294 		if (cnt <= 0)
4295 			error = NFSERR_BADXDR;
4296 	}
4297 	if (error)
4298 		goto nfsmout;
4299 
4300 	/*
4301 	 * Now, loop through the location list and make up the srvlist.
4302 	 */
4303 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4304 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4305 	slen = 1024;
4306 	siz = 0;
4307 	for (i = 0; i < cnt; i++) {
4308 		SLIST_INIT(&head);
4309 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4310 		nsrv = fxdr_unsigned(int, *tl);
4311 		if (nsrv <= 0) {
4312 			error = NFSERR_BADXDR;
4313 			goto nfsmout;
4314 		}
4315 
4316 		/*
4317 		 * Handle the first server by putting it in the srvstr.
4318 		 */
4319 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4320 		len = fxdr_unsigned(int, *tl);
4321 		if (len <= 0 || len > 1024) {
4322 			error = NFSERR_BADXDR;
4323 			goto nfsmout;
4324 		}
4325 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4326 		if (cp3 != cp2) {
4327 			*cp3++ = ',';
4328 			siz++;
4329 		}
4330 		error = nfsrv_mtostr(nd, cp3, len);
4331 		if (error)
4332 			goto nfsmout;
4333 		cp3 += len;
4334 		*cp3++ = ':';
4335 		siz += (len + 1);
4336 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4337 		for (j = 1; j < nsrv; j++) {
4338 			/*
4339 			 * Yuck, put them in an slist and process them later.
4340 			 */
4341 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4342 			len = fxdr_unsigned(int, *tl);
4343 			if (len <= 0 || len > 1024) {
4344 				error = NFSERR_BADXDR;
4345 				goto nfsmout;
4346 			}
4347 			lsp = (struct list *)malloc(sizeof (struct list)
4348 			    + len, M_TEMP, M_WAITOK);
4349 			error = nfsrv_mtostr(nd, lsp->host, len);
4350 			if (error)
4351 				goto nfsmout;
4352 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4353 			lsp->len = len;
4354 			SLIST_INSERT_HEAD(&head, lsp, next);
4355 		}
4356 
4357 		/*
4358 		 * Finally, we can get the path.
4359 		 */
4360 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4361 		len = fxdr_unsigned(int, *tl);
4362 		if (len <= 0 || len > 1024) {
4363 			error = NFSERR_BADXDR;
4364 			goto nfsmout;
4365 		}
4366 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4367 		error = nfsrv_mtostr(nd, cp3, len);
4368 		if (error)
4369 			goto nfsmout;
4370 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4371 		str = cp3;
4372 		stringlen = len;
4373 		cp3 += len;
4374 		siz += len;
4375 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4376 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4377 			    &cp2, &cp3, &slen);
4378 			*cp3++ = ',';
4379 			NFSBCOPY(lsp->host, cp3, lsp->len);
4380 			cp3 += lsp->len;
4381 			*cp3++ = ':';
4382 			NFSBCOPY(str, cp3, stringlen);
4383 			cp3 += stringlen;
4384 			*cp3 = '\0';
4385 			siz += (lsp->len + stringlen + 2);
4386 			free(lsp, M_TEMP);
4387 		}
4388 	}
4389 	*fsrootp = cp;
4390 	*srvp = cp2;
4391 	*sump = xdrsum;
4392 	NFSEXITCODE2(0, nd);
4393 	return (0);
4394 nfsmout:
4395 	if (cp != NULL)
4396 		free(cp, M_NFSSTRING);
4397 	if (cp2 != NULL)
4398 		free(cp2, M_NFSSTRING);
4399 	NFSEXITCODE2(error, nd);
4400 	return (error);
4401 }
4402 
4403 /*
4404  * Make the malloc'd space large enough. This is a pain, but the xdr
4405  * doesn't set an upper bound on the side, so...
4406  */
4407 static void
4408 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4409 {
4410 	u_char *cp;
4411 	int i;
4412 
4413 	if (siz <= *slenp)
4414 		return;
4415 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4416 	NFSBCOPY(*cpp, cp, *slenp);
4417 	free(*cpp, M_NFSSTRING);
4418 	i = *cpp2 - *cpp;
4419 	*cpp = cp;
4420 	*cpp2 = cp + i;
4421 	*slenp = siz + 1024;
4422 }
4423 
4424 /*
4425  * Initialize the reply header data structures.
4426  */
4427 void
4428 nfsrvd_rephead(struct nfsrv_descript *nd)
4429 {
4430 	struct mbuf *mreq;
4431 
4432 	if ((nd->nd_flag & ND_EXTPG) != 0) {
4433 		mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4434 		nd->nd_mreq = nd->nd_mb = mreq;
4435 		nd->nd_bpos = (char *)(void *)
4436 		    PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4437 		nd->nd_bextpg = 0;
4438 		nd->nd_bextpgsiz = PAGE_SIZE;
4439 	} else {
4440 		/*
4441 		 * If this is a big reply, use a cluster.
4442 		 */
4443 		if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4444 		    nfs_bigreply[nd->nd_procnum]) {
4445 			NFSMCLGET(mreq, M_WAITOK);
4446 			nd->nd_mreq = mreq;
4447 			nd->nd_mb = mreq;
4448 		} else {
4449 			NFSMGET(mreq);
4450 			nd->nd_mreq = mreq;
4451 			nd->nd_mb = mreq;
4452 		}
4453 		nd->nd_bpos = mtod(mreq, char *);
4454 		mreq->m_len = 0;
4455 	}
4456 
4457 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4458 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4459 }
4460 
4461 /*
4462  * Lock a socket against others.
4463  * Currently used to serialize connect/disconnect attempts.
4464  */
4465 int
4466 newnfs_sndlock(int *flagp)
4467 {
4468 	struct timespec ts;
4469 
4470 	NFSLOCKSOCK();
4471 	while (*flagp & NFSR_SNDLOCK) {
4472 		*flagp |= NFSR_WANTSND;
4473 		ts.tv_sec = 0;
4474 		ts.tv_nsec = 0;
4475 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4476 		    PZERO - 1, "nfsndlck", &ts);
4477 	}
4478 	*flagp |= NFSR_SNDLOCK;
4479 	NFSUNLOCKSOCK();
4480 	return (0);
4481 }
4482 
4483 /*
4484  * Unlock the stream socket for others.
4485  */
4486 void
4487 newnfs_sndunlock(int *flagp)
4488 {
4489 
4490 	NFSLOCKSOCK();
4491 	if ((*flagp & NFSR_SNDLOCK) == 0)
4492 		panic("nfs sndunlock");
4493 	*flagp &= ~NFSR_SNDLOCK;
4494 	if (*flagp & NFSR_WANTSND) {
4495 		*flagp &= ~NFSR_WANTSND;
4496 		wakeup((caddr_t)flagp);
4497 	}
4498 	NFSUNLOCKSOCK();
4499 }
4500 
4501 int
4502 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4503     struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4504 {
4505 	struct in_addr saddr;
4506 	uint32_t portnum, *tl;
4507 	int i, j, k;
4508 	sa_family_t af = AF_UNSPEC;
4509 	char addr[64], protocol[5], *cp;
4510 	int cantparse = 0, error = 0;
4511 	uint16_t portv;
4512 
4513 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4514 	i = fxdr_unsigned(int, *tl);
4515 	if (i >= 3 && i <= 4) {
4516 		error = nfsrv_mtostr(nd, protocol, i);
4517 		if (error)
4518 			goto nfsmout;
4519 		if (strcmp(protocol, "tcp") == 0) {
4520 			af = AF_INET;
4521 			*isudp = 0;
4522 		} else if (strcmp(protocol, "udp") == 0) {
4523 			af = AF_INET;
4524 			*isudp = 1;
4525 		} else if (strcmp(protocol, "tcp6") == 0) {
4526 			af = AF_INET6;
4527 			*isudp = 0;
4528 		} else if (strcmp(protocol, "udp6") == 0) {
4529 			af = AF_INET6;
4530 			*isudp = 1;
4531 		} else
4532 			cantparse = 1;
4533 	} else {
4534 		cantparse = 1;
4535 		if (i > 0) {
4536 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4537 			if (error)
4538 				goto nfsmout;
4539 		}
4540 	}
4541 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4542 	i = fxdr_unsigned(int, *tl);
4543 	if (i < 0) {
4544 		error = NFSERR_BADXDR;
4545 		goto nfsmout;
4546 	} else if (cantparse == 0 && i >= 11 && i < 64) {
4547 		/*
4548 		 * The shortest address is 11chars and the longest is < 64.
4549 		 */
4550 		error = nfsrv_mtostr(nd, addr, i);
4551 		if (error)
4552 			goto nfsmout;
4553 
4554 		/* Find the port# at the end and extract that. */
4555 		i = strlen(addr);
4556 		k = 0;
4557 		cp = &addr[i - 1];
4558 		/* Count back two '.'s from end to get port# field. */
4559 		for (j = 0; j < i; j++) {
4560 			if (*cp == '.') {
4561 				k++;
4562 				if (k == 2)
4563 					break;
4564 			}
4565 			cp--;
4566 		}
4567 		if (k == 2) {
4568 			/*
4569 			 * The NFSv4 port# is appended as .N.N, where N is
4570 			 * a decimal # in the range 0-255, just like an inet4
4571 			 * address. Cheat and use inet_aton(), which will
4572 			 * return a Class A address and then shift the high
4573 			 * order 8bits over to convert it to the port#.
4574 			 */
4575 			*cp++ = '\0';
4576 			if (inet_aton(cp, &saddr) == 1) {
4577 				portnum = ntohl(saddr.s_addr);
4578 				portv = (uint16_t)((portnum >> 16) |
4579 				    (portnum & 0xff));
4580 			} else
4581 				cantparse = 1;
4582 		} else
4583 			cantparse = 1;
4584 		if (cantparse == 0) {
4585 			if (af == AF_INET) {
4586 				if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4587 					sin->sin_len = sizeof(*sin);
4588 					sin->sin_family = AF_INET;
4589 					sin->sin_port = htons(portv);
4590 					*saf = af;
4591 					return (0);
4592 				}
4593 			} else {
4594 				if (inet_pton(af, addr, &sin6->sin6_addr)
4595 				    == 1) {
4596 					sin6->sin6_len = sizeof(*sin6);
4597 					sin6->sin6_family = AF_INET6;
4598 					sin6->sin6_port = htons(portv);
4599 					*saf = af;
4600 					return (0);
4601 				}
4602 			}
4603 		}
4604 	} else {
4605 		if (i > 0) {
4606 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4607 			if (error)
4608 				goto nfsmout;
4609 		}
4610 	}
4611 	error = EPERM;
4612 nfsmout:
4613 	return (error);
4614 }
4615 
4616 /*
4617  * Handle an NFSv4.1 Sequence request for the session.
4618  * If reply != NULL, use it to return the cached reply, as required.
4619  * The client gets a cached reply via this call for callbacks, however the
4620  * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
4621  */
4622 int
4623 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4624     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4625 {
4626 	struct mbuf *m;
4627 	int error;
4628 
4629 	error = 0;
4630 	if (reply != NULL)
4631 		*reply = NULL;
4632 	if (slotid > maxslot)
4633 		return (NFSERR_BADSLOT);
4634 	if (seqid == slots[slotid].nfssl_seq) {
4635 		/* A retry. */
4636 		if (slots[slotid].nfssl_inprog != 0)
4637 			error = NFSERR_DELAY;
4638 		else if (slots[slotid].nfssl_reply != NULL) {
4639 			if (reply != NULL) {
4640 				m = m_copym(slots[slotid].nfssl_reply, 0,
4641 				    M_COPYALL, M_NOWAIT);
4642 				if (m != NULL)
4643 					*reply = m;
4644 				else {
4645 					*reply = slots[slotid].nfssl_reply;
4646 					slots[slotid].nfssl_reply = NULL;
4647 				}
4648 			}
4649 			slots[slotid].nfssl_inprog = 1;
4650 			error = NFSERR_REPLYFROMCACHE;
4651 		} else
4652 			/* No reply cached, so just do it. */
4653 			slots[slotid].nfssl_inprog = 1;
4654 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4655 		if (slots[slotid].nfssl_reply != NULL)
4656 			m_freem(slots[slotid].nfssl_reply);
4657 		slots[slotid].nfssl_reply = NULL;
4658 		slots[slotid].nfssl_inprog = 1;
4659 		slots[slotid].nfssl_seq++;
4660 	} else
4661 		error = NFSERR_SEQMISORDERED;
4662 	return (error);
4663 }
4664 
4665 /*
4666  * Cache this reply for the slot.
4667  * Use the "rep" argument to return the cached reply if repstat is set to
4668  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4669  */
4670 void
4671 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4672    struct mbuf **rep)
4673 {
4674 	struct mbuf *m;
4675 
4676 	if (repstat == NFSERR_REPLYFROMCACHE) {
4677 		if (slots[slotid].nfssl_reply != NULL) {
4678 			/*
4679 			 * We cannot sleep here, but copy will usually
4680 			 * succeed.
4681 			 */
4682 			m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
4683 			    M_NOWAIT);
4684 			if (m != NULL)
4685 				*rep = m;
4686 			else {
4687 				/*
4688 				 * Multiple retries would be extremely rare,
4689 				 * so using the cached reply will likely
4690 				 * be ok.
4691 				 */
4692 				*rep = slots[slotid].nfssl_reply;
4693 				slots[slotid].nfssl_reply = NULL;
4694 			}
4695 		} else
4696 			*rep = NULL;
4697 	} else {
4698 		if (slots[slotid].nfssl_reply != NULL)
4699 			m_freem(slots[slotid].nfssl_reply);
4700 		slots[slotid].nfssl_reply = *rep;
4701 	}
4702 	slots[slotid].nfssl_inprog = 0;
4703 }
4704 
4705 /*
4706  * Generate the xdr for an NFSv4.1 Sequence Operation.
4707  */
4708 void
4709 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4710     struct nfsclsession *sep, int dont_replycache)
4711 {
4712 	uint32_t *tl, slotseq = 0;
4713 	int error, maxslot, slotpos;
4714 	uint8_t sessionid[NFSX_V4SESSIONID];
4715 
4716 	error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4717 	    sessionid);
4718 	nd->nd_maxreq = sep->nfsess_maxreq;
4719 	nd->nd_maxresp = sep->nfsess_maxresp;
4720 
4721 	/* Build the Sequence arguments. */
4722 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4723 	nd->nd_sequence = tl;
4724 	bcopy(sessionid, tl, NFSX_V4SESSIONID);
4725 	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4726 	nd->nd_slotseq = tl;
4727 	if (error == 0) {
4728 		nd->nd_flag |= ND_HASSLOTID;
4729 		nd->nd_slotid = slotpos;
4730 		*tl++ = txdr_unsigned(slotseq);
4731 		*tl++ = txdr_unsigned(slotpos);
4732 		*tl++ = txdr_unsigned(maxslot);
4733 		if (dont_replycache == 0)
4734 			*tl = newnfs_true;
4735 		else
4736 			*tl = newnfs_false;
4737 	} else {
4738 		/*
4739 		 * There are two errors and the rest of the session can
4740 		 * just be zeros.
4741 		 * NFSERR_BADSESSION: This bad session should just generate
4742 		 *    the same error again when the RPC is retried.
4743 		 * ESTALE: A forced dismount is in progress and will cause the
4744 		 *    RPC to fail later.
4745 		 */
4746 		*tl++ = 0;
4747 		*tl++ = 0;
4748 		*tl++ = 0;
4749 		*tl = 0;
4750 	}
4751 	nd->nd_flag |= ND_HASSEQUENCE;
4752 }
4753 
4754 int
4755 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4756     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4757 {
4758 	int i, maxslot, slotpos;
4759 	uint64_t bitval;
4760 
4761 	/* Find an unused slot. */
4762 	slotpos = -1;
4763 	maxslot = -1;
4764 	mtx_lock(&sep->nfsess_mtx);
4765 	do {
4766 		if (nmp != NULL && sep->nfsess_defunct != 0) {
4767 			/* Just return the bad session. */
4768 			bcopy(sep->nfsess_sessionid, sessionid,
4769 			    NFSX_V4SESSIONID);
4770 			mtx_unlock(&sep->nfsess_mtx);
4771 			return (NFSERR_BADSESSION);
4772 		}
4773 		bitval = 1;
4774 		for (i = 0; i < sep->nfsess_foreslots; i++) {
4775 			if ((bitval & sep->nfsess_slots) == 0) {
4776 				slotpos = i;
4777 				sep->nfsess_slots |= bitval;
4778 				sep->nfsess_slotseq[i]++;
4779 				*slotseqp = sep->nfsess_slotseq[i];
4780 				break;
4781 			}
4782 			bitval <<= 1;
4783 		}
4784 		if (slotpos == -1) {
4785 			/*
4786 			 * If a forced dismount is in progress, just return.
4787 			 * This RPC attempt will fail when it calls
4788 			 * newnfs_request().
4789 			 */
4790 			if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4791 				mtx_unlock(&sep->nfsess_mtx);
4792 				return (ESTALE);
4793 			}
4794 			/* Wake up once/sec, to check for a forced dismount. */
4795 			(void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4796 			    PZERO, "nfsclseq", hz);
4797 		}
4798 	} while (slotpos == -1);
4799 	/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4800 	bitval = 1;
4801 	for (i = 0; i < 64; i++) {
4802 		if ((bitval & sep->nfsess_slots) != 0)
4803 			maxslot = i;
4804 		bitval <<= 1;
4805 	}
4806 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4807 	mtx_unlock(&sep->nfsess_mtx);
4808 	*slotposp = slotpos;
4809 	*maxslotp = maxslot;
4810 	return (0);
4811 }
4812 
4813 /*
4814  * Free a session slot.
4815  */
4816 void
4817 nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
4818 {
4819 	uint64_t bitval;
4820 
4821 	bitval = 1;
4822 	if (slot > 0)
4823 		bitval <<= slot;
4824 	mtx_lock(&sep->nfsess_mtx);
4825 	if (resetseq)
4826 		sep->nfsess_slotseq[slot]--;
4827 	if ((bitval & sep->nfsess_slots) == 0)
4828 		printf("freeing free slot!!\n");
4829 	sep->nfsess_slots &= ~bitval;
4830 	wakeup(&sep->nfsess_slots);
4831 	mtx_unlock(&sep->nfsess_mtx);
4832 }
4833 
4834 /*
4835  * Search for a matching pnfsd DS, based on the nmp arg.
4836  * Return one if found, NULL otherwise.
4837  */
4838 struct nfsdevice *
4839 nfsv4_findmirror(struct nfsmount *nmp)
4840 {
4841 	struct nfsdevice *ds;
4842 
4843 	mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4844 	/*
4845 	 * Search the DS server list for a match with nmp.
4846 	 */
4847 	if (nfsrv_devidcnt == 0)
4848 		return (NULL);
4849 	TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4850 		if (ds->nfsdev_nmp == nmp) {
4851 			NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4852 			break;
4853 		}
4854 	}
4855 	return (ds);
4856 }
4857 
4858 /*
4859  * Fill in the fields of "struct nfsrv_descript".
4860  */
4861 void
4862 nfsm_set(struct nfsrv_descript *nd, u_int offs)
4863 {
4864 	struct mbuf *m;
4865 	int rlen;
4866 
4867 	m = nd->nd_mb;
4868 	if ((m->m_flags & M_EXTPG) != 0) {
4869 		nd->nd_bextpg = 0;
4870 		while (offs > 0) {
4871 			if (nd->nd_bextpg == 0)
4872 				rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
4873 			else
4874 				rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
4875 			if (offs <= rlen)
4876 				break;
4877 			offs -= rlen;
4878 			nd->nd_bextpg++;
4879 			if (nd->nd_bextpg == m->m_epg_npgs) {
4880 				printf("nfsm_set: build offs "
4881 				    "out of range\n");
4882 				nd->nd_bextpg--;
4883 				break;
4884 			}
4885 		}
4886 		nd->nd_bpos = (char *)(void *)
4887 		    PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
4888 		if (nd->nd_bextpg == 0)
4889 			nd->nd_bpos += m->m_epg_1st_off;
4890 		if (offs > 0) {
4891 			nd->nd_bpos += offs;
4892 			nd->nd_bextpgsiz = rlen - offs;
4893 		} else if (nd->nd_bextpg == 0)
4894 			nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
4895 		else
4896 			nd->nd_bextpgsiz = PAGE_SIZE;
4897 	} else
4898 		nd->nd_bpos = mtod(m, char *) + offs;
4899 }
4900 
4901 /*
4902  * Grow a ext_pgs mbuf list.  Either allocate another page or add
4903  * an mbuf to the list.
4904  */
4905 struct mbuf *
4906 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
4907 {
4908 	struct mbuf *mp;
4909 	vm_page_t pg;
4910 
4911 	if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
4912 		mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4913 		*bextpg = 0;
4914 		m->m_next = mp;
4915 	} else {
4916 		do {
4917 			pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
4918 			    VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP |
4919 			    VM_ALLOC_WIRED);
4920 			if (pg == NULL)
4921 				vm_wait(NULL);
4922 		} while (pg == NULL);
4923 		m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
4924 		*bextpg = m->m_epg_npgs;
4925 		m->m_epg_npgs++;
4926 		m->m_epg_last_len = 0;
4927 		mp = m;
4928 	}
4929 	return (mp);
4930 }
4931