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