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