xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision b214fcceacad6b842545150664bd2695c1c2b34f)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 /*
40  * These functions support the macros and help fiddle mbuf chains for
41  * the nfs op functions. They do things like create the rpc header and
42  * copy data between mbuf chains and uio lists.
43  */
44 #include "opt_inet.h"
45 #include "opt_inet6.h"
46 
47 #include <fs/nfs/nfsport.h>
48 
49 #include <sys/extattr.h>
50 
51 #include <security/mac/mac_framework.h>
52 
53 #include <vm/vm_param.h>
54 
55 /*
56  * Data items converted to xdr at startup, since they are constant
57  * This is kinda hokey, but may save a little time doing byte swaps
58  */
59 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
60 
61 /* And other global data */
62 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
63 		      NFFIFO, NFNON };
64 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
65 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
66 struct timeval nfsboottime;	/* Copy boottime once, so it never changes */
67 int nfscl_ticks;
68 int nfsrv_useacl = 1;
69 struct nfssockreq nfsrv_nfsuserdsock;
70 nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
71 static int nfsrv_userdupcalls = 0;
72 struct nfsreqhead nfsd_reqq;
73 uid_t nfsrv_defaultuid = UID_NOBODY;
74 gid_t nfsrv_defaultgid = GID_NOGROUP;
75 int nfsrv_lease = NFSRV_LEASE;
76 int ncl_mbuf_mlen = MLEN;
77 int nfsd_enable_stringtouid = 0;
78 int nfsrv_doflexfile = 0;
79 static int nfs_enable_uidtostring = 0;
80 NFSNAMEIDMUTEX;
81 NFSSOCKMUTEX;
82 extern int nfsrv_lughashsize;
83 extern struct mtx nfsrv_dslock_mtx;
84 extern volatile int nfsrv_devidcnt;
85 extern int nfscl_debuglevel;
86 extern struct nfsdevicehead nfsrv_devidhead;
87 extern struct nfsstatsv1 nfsstatsv1;
88 extern uint32_t nfs_srvmaxio;
89 
90 SYSCTL_DECL(_vfs_nfs);
91 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
92     &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
93 
94 int nfsrv_maxpnfsmirror = 1;
95 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
96     &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
97 
98 /*
99  * This array of structures indicates, for V4:
100  * retfh - which of 3 types of calling args are used
101  *	0 - doesn't change cfh or use a sfh
102  *	1 - replaces cfh with a new one (unless it returns an error status)
103  *	2 - uses cfh and sfh
104  * needscfh - if the op wants a cfh and premtime
105  *	0 - doesn't use a cfh
106  *	1 - uses a cfh, but doesn't want pre-op attributes
107  *	2 - uses a cfh and wants pre-op attributes
108  * savereply - indicates a non-idempotent Op
109  *	0 - not non-idempotent
110  *	1 - non-idempotent
111  * Ops that are ordered via seqid# are handled separately from these
112  * non-idempotent Ops.
113  * Define it here, since it is used by both the client and server.
114  */
115 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
116 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
117 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
118 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
119 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Access */
120 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Close */
121 	{ 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 },		/* Commit */
122 	{ 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Create */
123 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Delegpurge */
124 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Delegreturn */
125 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Getattr */
126 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* GetFH */
127 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Link */
128 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Lock */
129 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* LockT */
130 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* LockU */
131 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Lookup */
132 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Lookupp */
133 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* NVerify */
134 	{ 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },		/* Open */
135 	{ 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenAttr */
136 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenConfirm */
137 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenDowngrade */
138 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutFH */
139 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutPubFH */
140 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutRootFH */
141 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* Read */
142 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Readdir */
143 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* ReadLink */
144 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Remove */
145 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Rename */
146 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Renew */
147 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* RestoreFH */
148 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SaveFH */
149 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SecInfo */
150 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Setattr */
151 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SetClientID */
152 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SetClientIDConfirm */
153 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Verify */
154 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Write */
155 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* ReleaseLockOwner */
156 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Backchannel Ctrl */
157 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Bind Conn to Sess */
158 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Exchange ID */
159 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Create Session */
160 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Destroy Session */
161 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Free StateID */
162 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Dir Deleg */
163 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Device Info */
164 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Device List */
165 	{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 },		/* Layout Commit */
166 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Layout Get */
167 	{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },		/* Layout Return */
168 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Secinfo No name */
169 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Sequence */
170 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Set SSV */
171 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Test StateID */
172 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Want Delegation */
173 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Destroy ClientID */
174 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Reclaim Complete */
175 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Allocate */
176 	{ 2, 1, 1, 0, LK_SHARED, 1, 0 },		/* Copy */
177 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Copy Notify */
178 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Deallocate */
179 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* IO Advise */
180 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Layout Error */
181 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Layout Stats */
182 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Offload Cancel */
183 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Offload Status */
184 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Read Plus */
185 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* Seek */
186 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Write Same */
187 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Clone */
188 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Getxattr */
189 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Setxattr */
190 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Listxattrs */
191 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Removexattr */
192 };
193 
194 static int ncl_mbuf_mhlen = MHLEN;
195 static int nfsrv_usercnt = 0;
196 static int nfsrv_dnsnamelen;
197 static u_char *nfsrv_dnsname = NULL;
198 static int nfsrv_usermax = 999999999;
199 struct nfsrv_lughash {
200 	struct mtx		mtx;
201 	struct nfsuserhashhead	lughead;
202 };
203 static struct nfsrv_lughash	*nfsuserhash;
204 static struct nfsrv_lughash	*nfsusernamehash;
205 static struct nfsrv_lughash	*nfsgrouphash;
206 static struct nfsrv_lughash	*nfsgroupnamehash;
207 
208 /*
209  * This static array indicates whether or not the RPC generates a large
210  * reply. This is used by nfs_reply() to decide whether or not an mbuf
211  * cluster should be allocated. (If a cluster is required by an RPC
212  * marked 0 in this array, the code will still work, just not quite as
213  * efficiently.)
214  */
215 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
216     0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
217     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
218     1, 0, 0, 1, 0, 0, 0, 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 };
307 
308 /*
309  * NFS RPCS that have large request message size.
310  */
311 static int nfs_bigrequest[NFSV42_NPROCS] = {
312 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
313 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
314 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
315 	0
316 };
317 
318 /*
319  * Start building a request. Mostly just put the first file handle in
320  * place.
321  */
322 void
323 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
324     u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
325     int vers, int minorvers)
326 {
327 	struct mbuf *mb;
328 	u_int32_t *tl;
329 	int opcnt;
330 	nfsattrbit_t attrbits;
331 
332 	/*
333 	 * First, fill in some of the fields of nd.
334 	 */
335 	nd->nd_slotseq = NULL;
336 	if (vers == NFS_VER4) {
337 		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
338 		if (minorvers == NFSV41_MINORVERSION)
339 			nd->nd_flag |= ND_NFSV41;
340 		else if (minorvers == NFSV42_MINORVERSION)
341 			nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
342 	} else if (vers == NFS_VER3)
343 		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
344 	else {
345 		if (NFSHASNFSV4(nmp)) {
346 			nd->nd_flag = ND_NFSV4 | ND_NFSCL;
347 			if (nmp->nm_minorvers == 1)
348 				nd->nd_flag |= ND_NFSV41;
349 			else if (nmp->nm_minorvers == 2)
350 				nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
351 		} else if (NFSHASNFSV3(nmp))
352 			nd->nd_flag = ND_NFSV3 | ND_NFSCL;
353 		else
354 			nd->nd_flag = ND_NFSV2 | ND_NFSCL;
355 	}
356 	nd->nd_procnum = procnum;
357 	nd->nd_repstat = 0;
358 	nd->nd_maxextsiz = 0;
359 
360 	/*
361 	 * Get the first mbuf for the request.
362 	 */
363 	if (nfs_bigrequest[procnum])
364 		NFSMCLGET(mb, M_WAITOK);
365 	else
366 		NFSMGET(mb);
367 	mb->m_len = 0;
368 	nd->nd_mreq = nd->nd_mb = mb;
369 	nd->nd_bpos = mtod(mb, char *);
370 
371 	/*
372 	 * And fill the first file handle into the request.
373 	 */
374 	if (nd->nd_flag & ND_NFSV4) {
375 		opcnt = nfsv4_opmap[procnum].opcnt +
376 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
377 		if ((nd->nd_flag & ND_NFSV41) != 0) {
378 			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
379 			if (procnum == NFSPROC_RENEW)
380 				/*
381 				 * For the special case of Renew, just do a
382 				 * Sequence Op.
383 				 */
384 				opcnt = 1;
385 			else if (procnum == NFSPROC_WRITEDS ||
386 			    procnum == NFSPROC_COMMITDS)
387 				/*
388 				 * For the special case of a Writeor Commit to
389 				 * a DS, the opcnt == 3, for Sequence, PutFH,
390 				 * Write/Commit.
391 				 */
392 				opcnt = 3;
393 		}
394 		/*
395 		 * What should the tag really be?
396 		 */
397 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
398 			nfsv4_opmap[procnum].taglen);
399 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
400 		if ((nd->nd_flag & ND_NFSV42) != 0)
401 			*tl++ = txdr_unsigned(NFSV42_MINORVERSION);
402 		else if ((nd->nd_flag & ND_NFSV41) != 0)
403 			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
404 		else
405 			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
406 		if (opcntpp != NULL)
407 			*opcntpp = tl;
408 		*tl = txdr_unsigned(opcnt);
409 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
410 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
411 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
412 			    0)
413 				nd->nd_flag |= ND_LOOPBADSESS;
414 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
415 			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
416 			if (sep == NULL) {
417 				sep = nfsmnt_mdssession(nmp);
418 				nfsv4_setsequence(nmp, nd, sep,
419 				    nfs_bigreply[procnum]);
420 			} else
421 				nfsv4_setsequence(nmp, nd, sep,
422 				    nfs_bigreply[procnum]);
423 		}
424 		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
425 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
426 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
427 			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
428 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
429 			    == 2 && procnum != NFSPROC_WRITEDS &&
430 			    procnum != NFSPROC_COMMITDS) {
431 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
432 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
433 				/*
434 				 * For Lookup Ops, we want all the directory
435 				 * attributes, so we can load the name cache.
436 				 */
437 				if (procnum == NFSPROC_LOOKUP ||
438 				    procnum == NFSPROC_LOOKUPP ||
439 				    procnum == NFSPROC_LOOKUPOPEN)
440 					NFSGETATTR_ATTRBIT(&attrbits);
441 				else {
442 					NFSWCCATTR_ATTRBIT(&attrbits);
443 					nd->nd_flag |= ND_V4WCCATTR;
444 				}
445 				(void) nfsrv_putattrbit(nd, &attrbits);
446 			}
447 		}
448 		if (procnum != NFSPROC_RENEW ||
449 		    (nd->nd_flag & ND_NFSV41) == 0) {
450 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
451 			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
452 		}
453 	} else {
454 		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
455 	}
456 	if (procnum < NFSV42_NPROCS)
457 		NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
458 }
459 
460 /*
461  * Put a state Id in the mbuf list.
462  */
463 void
464 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
465 {
466 	nfsv4stateid_t *st;
467 
468 	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
469 	if (flag == NFSSTATEID_PUTALLZERO) {
470 		st->seqid = 0;
471 		st->other[0] = 0;
472 		st->other[1] = 0;
473 		st->other[2] = 0;
474 	} else if (flag == NFSSTATEID_PUTALLONE) {
475 		st->seqid = 0xffffffff;
476 		st->other[0] = 0xffffffff;
477 		st->other[1] = 0xffffffff;
478 		st->other[2] = 0xffffffff;
479 	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
480 		st->seqid = 0;
481 		st->other[0] = stateidp->other[0];
482 		st->other[1] = stateidp->other[1];
483 		st->other[2] = stateidp->other[2];
484 	} else {
485 		st->seqid = stateidp->seqid;
486 		st->other[0] = stateidp->other[0];
487 		st->other[1] = stateidp->other[1];
488 		st->other[2] = stateidp->other[2];
489 	}
490 }
491 
492 /*
493  * Fill in the setable attributes. The full argument indicates whether
494  * to fill in them all or just mode and time.
495  */
496 void
497 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
498     struct vnode *vp, int flags, u_int32_t rdev)
499 {
500 	u_int32_t *tl;
501 	struct nfsv2_sattr *sp;
502 	nfsattrbit_t attrbits;
503 	struct nfsnode *np;
504 
505 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
506 	case ND_NFSV2:
507 		NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
508 		if (vap->va_mode == (mode_t)VNOVAL)
509 			sp->sa_mode = newnfs_xdrneg1;
510 		else
511 			sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
512 		if (vap->va_uid == (uid_t)VNOVAL)
513 			sp->sa_uid = newnfs_xdrneg1;
514 		else
515 			sp->sa_uid = txdr_unsigned(vap->va_uid);
516 		if (vap->va_gid == (gid_t)VNOVAL)
517 			sp->sa_gid = newnfs_xdrneg1;
518 		else
519 			sp->sa_gid = txdr_unsigned(vap->va_gid);
520 		if (flags & NFSSATTR_SIZE0)
521 			sp->sa_size = 0;
522 		else if (flags & NFSSATTR_SIZENEG1)
523 			sp->sa_size = newnfs_xdrneg1;
524 		else if (flags & NFSSATTR_SIZERDEV)
525 			sp->sa_size = txdr_unsigned(rdev);
526 		else
527 			sp->sa_size = txdr_unsigned(vap->va_size);
528 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
529 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
530 		break;
531 	case ND_NFSV3:
532 		if (vap->va_mode != (mode_t)VNOVAL) {
533 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
534 			*tl++ = newnfs_true;
535 			*tl = txdr_unsigned(vap->va_mode);
536 		} else {
537 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
538 			*tl = newnfs_false;
539 		}
540 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
541 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
542 			*tl++ = newnfs_true;
543 			*tl = txdr_unsigned(vap->va_uid);
544 		} else {
545 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
546 			*tl = newnfs_false;
547 		}
548 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
549 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
550 			*tl++ = newnfs_true;
551 			*tl = txdr_unsigned(vap->va_gid);
552 		} else {
553 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
554 			*tl = newnfs_false;
555 		}
556 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
557 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
558 			*tl++ = newnfs_true;
559 			txdr_hyper(vap->va_size, tl);
560 		} else {
561 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
562 			*tl = newnfs_false;
563 		}
564 		if (vap->va_atime.tv_sec != VNOVAL) {
565 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
566 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
567 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
568 				txdr_nfsv3time(&vap->va_atime, tl);
569 			} else {
570 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
571 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
572 			}
573 		} else {
574 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
575 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
576 		}
577 		if (vap->va_mtime.tv_sec != VNOVAL) {
578 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
579 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
580 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
581 				txdr_nfsv3time(&vap->va_mtime, tl);
582 			} else {
583 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
584 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
585 			}
586 		} else {
587 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
588 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
589 		}
590 		break;
591 	case ND_NFSV4:
592 		NFSZERO_ATTRBIT(&attrbits);
593 		if (vap->va_mode != (mode_t)VNOVAL)
594 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
595 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
596 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
597 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
598 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
599 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
600 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
601 		if (vap->va_atime.tv_sec != VNOVAL)
602 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
603 		if (vap->va_mtime.tv_sec != VNOVAL)
604 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
605 		if (vap->va_birthtime.tv_sec != VNOVAL &&
606 		    strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0) {
607 			/*
608 			 * We can only test for support of TimeCreate if
609 			 * the "vp" argument is for an NFS vnode.
610 			 */
611 			np = VTONFS(vp);
612 			if (NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
613 			    NFSATTRBIT_TIMECREATE))
614 				NFSSETBIT_ATTRBIT(&attrbits,
615 				    NFSATTRBIT_TIMECREATE);
616 		}
617 		(void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
618 		    &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
619 		break;
620 	}
621 }
622 
623 #ifndef APPLE
624 /*
625  * copies mbuf chain to the uio scatter/gather list
626  */
627 int
628 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
629 {
630 	char *mbufcp, *uiocp;
631 	int xfer, left, len;
632 	struct mbuf *mp;
633 	long uiosiz, rem;
634 	int error = 0;
635 
636 	mp = nd->nd_md;
637 	mbufcp = nd->nd_dpos;
638 	len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
639 	rem = NFSM_RNDUP(siz) - siz;
640 	while (siz > 0) {
641 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
642 			error = EBADRPC;
643 			goto out;
644 		}
645 		left = uiop->uio_iov->iov_len;
646 		uiocp = uiop->uio_iov->iov_base;
647 		if (left > siz)
648 			left = siz;
649 		uiosiz = left;
650 		while (left > 0) {
651 			while (len == 0) {
652 				mp = mp->m_next;
653 				if (mp == NULL) {
654 					error = EBADRPC;
655 					goto out;
656 				}
657 				mbufcp = mtod(mp, caddr_t);
658 				len = mp->m_len;
659 				KASSERT(len >= 0,
660 				    ("len %d, corrupted mbuf?", len));
661 			}
662 			xfer = (left > len) ? len : left;
663 #ifdef notdef
664 			/* Not Yet.. */
665 			if (uiop->uio_iov->iov_op != NULL)
666 				(*(uiop->uio_iov->iov_op))
667 				(mbufcp, uiocp, xfer);
668 			else
669 #endif
670 			if (uiop->uio_segflg == UIO_SYSSPACE)
671 				NFSBCOPY(mbufcp, uiocp, xfer);
672 			else
673 				copyout(mbufcp, uiocp, xfer);
674 			left -= xfer;
675 			len -= xfer;
676 			mbufcp += xfer;
677 			uiocp += xfer;
678 			uiop->uio_offset += xfer;
679 			uiop->uio_resid -= xfer;
680 		}
681 		if (uiop->uio_iov->iov_len <= siz) {
682 			uiop->uio_iovcnt--;
683 			uiop->uio_iov++;
684 		} else {
685 			uiop->uio_iov->iov_base = (void *)
686 				((char *)uiop->uio_iov->iov_base + uiosiz);
687 			uiop->uio_iov->iov_len -= uiosiz;
688 		}
689 		siz -= uiosiz;
690 	}
691 	nd->nd_dpos = mbufcp;
692 	nd->nd_md = mp;
693 	if (rem > 0) {
694 		if (len < rem)
695 			error = nfsm_advance(nd, rem, len);
696 		else
697 			nd->nd_dpos += rem;
698 	}
699 
700 out:
701 	NFSEXITCODE2(error, nd);
702 	return (error);
703 }
704 #endif	/* !APPLE */
705 
706 /*
707  * Help break down an mbuf chain by setting the first siz bytes contiguous
708  * pointed to by returned val.
709  * This is used by the macro NFSM_DISSECT for tough
710  * cases.
711  */
712 void *
713 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
714 {
715 	struct mbuf *mp2;
716 	int siz2, xfer;
717 	caddr_t p;
718 	int left;
719 	caddr_t retp;
720 
721 	retp = NULL;
722 	left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
723 	while (left == 0) {
724 		nd->nd_md = nd->nd_md->m_next;
725 		if (nd->nd_md == NULL)
726 			return (retp);
727 		left = nd->nd_md->m_len;
728 		nd->nd_dpos = mtod(nd->nd_md, caddr_t);
729 	}
730 	if (left >= siz) {
731 		retp = nd->nd_dpos;
732 		nd->nd_dpos += siz;
733 	} else if (nd->nd_md->m_next == NULL) {
734 		return (retp);
735 	} else if (siz > ncl_mbuf_mhlen) {
736 		panic("nfs S too big");
737 	} else {
738 		MGET(mp2, MT_DATA, how);
739 		if (mp2 == NULL)
740 			return (NULL);
741 		mp2->m_next = nd->nd_md->m_next;
742 		nd->nd_md->m_next = mp2;
743 		nd->nd_md->m_len -= left;
744 		nd->nd_md = mp2;
745 		retp = p = mtod(mp2, caddr_t);
746 		NFSBCOPY(nd->nd_dpos, p, left);	/* Copy what was left */
747 		siz2 = siz - left;
748 		p += left;
749 		mp2 = mp2->m_next;
750 		/* Loop around copying up the siz2 bytes */
751 		while (siz2 > 0) {
752 			if (mp2 == NULL)
753 				return (NULL);
754 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
755 			if (xfer > 0) {
756 				NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
757 				mp2->m_data += xfer;
758 				mp2->m_len -= xfer;
759 				p += xfer;
760 				siz2 -= xfer;
761 			}
762 			if (siz2 > 0)
763 				mp2 = mp2->m_next;
764 		}
765 		nd->nd_md->m_len = siz;
766 		nd->nd_md = mp2;
767 		nd->nd_dpos = mtod(mp2, caddr_t);
768 	}
769 	return (retp);
770 }
771 
772 /*
773  * Advance the position in the mbuf chain.
774  * If offs == 0, this is a no-op, but it is simpler to just return from
775  * here than check for offs > 0 for all calls to nfsm_advance.
776  * If left == -1, it should be calculated here.
777  */
778 int
779 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
780 {
781 	int error = 0;
782 
783 	if (offs == 0)
784 		goto out;
785 	/*
786 	 * A negative offs might indicate a corrupted mbuf chain and,
787 	 * as such, a printf is logged.
788 	 */
789 	if (offs < 0) {
790 		printf("nfsrv_advance: negative offs\n");
791 		error = EBADRPC;
792 		goto out;
793 	}
794 
795 	/*
796 	 * If left == -1, calculate it here.
797 	 */
798 	if (left == -1)
799 		left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
800 		    nd->nd_dpos;
801 
802 	/*
803 	 * Loop around, advancing over the mbuf data.
804 	 */
805 	while (offs > left) {
806 		offs -= left;
807 		nd->nd_md = nd->nd_md->m_next;
808 		if (nd->nd_md == NULL) {
809 			error = EBADRPC;
810 			goto out;
811 		}
812 		left = nd->nd_md->m_len;
813 		nd->nd_dpos = mtod(nd->nd_md, caddr_t);
814 	}
815 	nd->nd_dpos += offs;
816 
817 out:
818 	NFSEXITCODE(error);
819 	return (error);
820 }
821 
822 /*
823  * Copy a string into mbuf(s).
824  * Return the number of bytes output, including XDR overheads.
825  */
826 int
827 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
828 {
829 	struct mbuf *m2;
830 	int xfer, left;
831 	struct mbuf *m1;
832 	int rem, bytesize;
833 	u_int32_t *tl;
834 	char *cp2;
835 
836 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
837 	*tl = txdr_unsigned(siz);
838 	rem = NFSM_RNDUP(siz) - siz;
839 	bytesize = NFSX_UNSIGNED + siz + rem;
840 	m2 = nd->nd_mb;
841 	cp2 = nd->nd_bpos;
842 	if ((nd->nd_flag & ND_EXTPG) != 0)
843 		left = nd->nd_bextpgsiz;
844 	else
845 		left = M_TRAILINGSPACE(m2);
846 
847 	KASSERT(((m2->m_flags & (M_EXT | M_EXTPG)) ==
848 	    (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) != 0) ||
849 	    ((m2->m_flags & (M_EXT | M_EXTPG)) !=
850 	    (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) == 0),
851 	    ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed"));
852 	/*
853 	 * Loop around copying the string to mbuf(s).
854 	 */
855 	while (siz > 0) {
856 		if (left == 0) {
857 			if ((nd->nd_flag & ND_EXTPG) != 0) {
858 				m2 = nfsm_add_ext_pgs(m2,
859 				    nd->nd_maxextsiz, &nd->nd_bextpg);
860 				cp2 = (char *)(void *)PHYS_TO_DMAP(
861 				    m2->m_epg_pa[nd->nd_bextpg]);
862 				nd->nd_bextpgsiz = left = PAGE_SIZE;
863 			} else {
864 				if (siz > ncl_mbuf_mlen)
865 					NFSMCLGET(m1, M_WAITOK);
866 				else
867 					NFSMGET(m1);
868 				m1->m_len = 0;
869 				cp2 = mtod(m1, char *);
870 				left = M_TRAILINGSPACE(m1);
871 				m2->m_next = m1;
872 				m2 = m1;
873 			}
874 		}
875 		if (left >= siz)
876 			xfer = siz;
877 		else
878 			xfer = left;
879 		NFSBCOPY(cp, cp2, xfer);
880 		cp += xfer;
881 		cp2 += xfer;
882 		m2->m_len += xfer;
883 		siz -= xfer;
884 		left -= xfer;
885 		if ((nd->nd_flag & ND_EXTPG) != 0) {
886 			nd->nd_bextpgsiz -= xfer;
887 			m2->m_epg_last_len += xfer;
888 		}
889 		if (siz == 0 && rem) {
890 			if (left < rem)
891 				panic("nfsm_strtom");
892 			NFSBZERO(cp2, rem);
893 			m2->m_len += rem;
894 			cp2 += rem;
895 			if ((nd->nd_flag & ND_EXTPG) != 0) {
896 				nd->nd_bextpgsiz -= rem;
897 				m2->m_epg_last_len += rem;
898 			}
899 		}
900 	}
901 	nd->nd_mb = m2;
902 	if ((nd->nd_flag & ND_EXTPG) != 0)
903 		nd->nd_bpos = cp2;
904 	else
905 		nd->nd_bpos = mtod(m2, char *) + m2->m_len;
906 	return (bytesize);
907 }
908 
909 /*
910  * Called once to initialize data structures...
911  */
912 void
913 newnfs_init(void)
914 {
915 	static int nfs_inited = 0;
916 
917 	if (nfs_inited)
918 		return;
919 	nfs_inited = 1;
920 
921 	newnfs_true = txdr_unsigned(TRUE);
922 	newnfs_false = txdr_unsigned(FALSE);
923 	newnfs_xdrneg1 = txdr_unsigned(-1);
924 	nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
925 	if (nfscl_ticks < 1)
926 		nfscl_ticks = 1;
927 	NFSSETBOOTTIME(nfsboottime);
928 
929 	/*
930 	 * Initialize reply list and start timer
931 	 */
932 	TAILQ_INIT(&nfsd_reqq);
933 	NFS_TIMERINIT;
934 }
935 
936 /*
937  * Put a file handle in an mbuf list.
938  * If the size argument == 0, just use the default size.
939  * set_true == 1 if there should be an newnfs_true prepended on the file handle.
940  * Return the number of bytes output, including XDR overhead.
941  */
942 int
943 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
944 {
945 	u_int32_t *tl;
946 	u_int8_t *cp;
947 	int fullsiz, bytesize = 0;
948 
949 	if (size == 0)
950 		size = NFSX_MYFH;
951 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
952 	case ND_NFSV2:
953 		if (size > NFSX_V2FH)
954 			panic("fh size > NFSX_V2FH for NFSv2");
955 		NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
956 		NFSBCOPY(fhp, cp, size);
957 		if (size < NFSX_V2FH)
958 			NFSBZERO(cp + size, NFSX_V2FH - size);
959 		bytesize = NFSX_V2FH;
960 		break;
961 	case ND_NFSV3:
962 	case ND_NFSV4:
963 		fullsiz = NFSM_RNDUP(size);
964 		if (set_true) {
965 		    bytesize = 2 * NFSX_UNSIGNED + fullsiz;
966 		    NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
967 		    *tl = newnfs_true;
968 		} else {
969 		    bytesize = NFSX_UNSIGNED + fullsiz;
970 		}
971 		(void) nfsm_strtom(nd, fhp, size);
972 		break;
973 	}
974 	return (bytesize);
975 }
976 
977 /*
978  * This function compares two net addresses by family and returns TRUE
979  * if they are the same host.
980  * If there is any doubt, return FALSE.
981  * The AF_INET family is handled as a special case so that address mbufs
982  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
983  */
984 int
985 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
986 {
987 #ifdef INET
988 	struct sockaddr_in *inetaddr;
989 #endif
990 
991 	switch (family) {
992 #ifdef INET
993 	case AF_INET:
994 		inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
995 		if (inetaddr->sin_family == AF_INET &&
996 		    inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
997 			return (1);
998 		break;
999 #endif
1000 #ifdef INET6
1001 	case AF_INET6:
1002 		{
1003 		struct sockaddr_in6 *inetaddr6;
1004 
1005 		inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
1006 		/* XXX - should test sin6_scope_id ? */
1007 		if (inetaddr6->sin6_family == AF_INET6 &&
1008 		    IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
1009 			  &haddr->had_inet6))
1010 			return (1);
1011 		}
1012 		break;
1013 #endif
1014 	}
1015 	return (0);
1016 }
1017 
1018 /*
1019  * Similar to the above, but takes to NFSSOCKADDR_T args.
1020  */
1021 int
1022 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
1023 {
1024 	struct sockaddr_in *addr1, *addr2;
1025 	struct sockaddr *inaddr;
1026 
1027 	inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
1028 	switch (inaddr->sa_family) {
1029 	case AF_INET:
1030 		addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
1031 		addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
1032 		if (addr2->sin_family == AF_INET &&
1033 		    addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
1034 			return (1);
1035 		break;
1036 #ifdef INET6
1037 	case AF_INET6:
1038 		{
1039 		struct sockaddr_in6 *inet6addr1, *inet6addr2;
1040 
1041 		inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
1042 		inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
1043 		/* XXX - should test sin6_scope_id ? */
1044 		if (inet6addr2->sin6_family == AF_INET6 &&
1045 		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1046 			  &inet6addr2->sin6_addr))
1047 			return (1);
1048 		}
1049 		break;
1050 #endif
1051 	}
1052 	return (0);
1053 }
1054 
1055 /*
1056  * Dissect a file handle on the client.
1057  */
1058 int
1059 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1060 {
1061 	u_int32_t *tl;
1062 	struct nfsfh *nfhp;
1063 	int error, len;
1064 
1065 	*nfhpp = NULL;
1066 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1067 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1068 		if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1069 			len > NFSX_FHMAX) {
1070 			error = EBADRPC;
1071 			goto nfsmout;
1072 		}
1073 	} else
1074 		len = NFSX_V2FH;
1075 	nfhp = malloc(sizeof (struct nfsfh) + len,
1076 	    M_NFSFH, M_WAITOK);
1077 	error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1078 	if (error) {
1079 		free(nfhp, M_NFSFH);
1080 		goto nfsmout;
1081 	}
1082 	nfhp->nfh_len = len;
1083 	*nfhpp = nfhp;
1084 nfsmout:
1085 	NFSEXITCODE2(error, nd);
1086 	return (error);
1087 }
1088 
1089 /*
1090  * Break down the nfsv4 acl.
1091  * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1092  */
1093 int
1094 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1095     int *aclsizep, __unused NFSPROC_T *p)
1096 {
1097 	u_int32_t *tl;
1098 	int i, aclsize;
1099 	int acecnt, error = 0, aceerr = 0, acesize;
1100 
1101 	*aclerrp = 0;
1102 	if (aclp)
1103 		aclp->acl_cnt = 0;
1104 	/*
1105 	 * Parse out the ace entries and expect them to conform to
1106 	 * what can be supported by R/W/X bits.
1107 	 */
1108 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1109 	aclsize = NFSX_UNSIGNED;
1110 	acecnt = fxdr_unsigned(int, *tl);
1111 	/*
1112 	 * The RFCs do not define a fixed limit to the number of ACEs in
1113 	 * an ACL, but 10240 should be more than sufficient.
1114 	 */
1115 	if (acecnt < 0 || acecnt > 10240) {
1116 		error = NFSERR_BADXDR;
1117 		goto nfsmout;
1118 	}
1119 	if (acecnt > ACL_MAX_ENTRIES)
1120 		aceerr = NFSERR_ATTRNOTSUPP;
1121 	if (nfsrv_useacl == 0)
1122 		aceerr = NFSERR_ATTRNOTSUPP;
1123 	for (i = 0; i < acecnt; i++) {
1124 		if (aclp && !aceerr)
1125 			error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1126 			    &aceerr, &acesize, p);
1127 		else
1128 			error = nfsrv_skipace(nd, &acesize);
1129 		if (error)
1130 			goto nfsmout;
1131 		aclsize += acesize;
1132 	}
1133 	if (aclp && !aceerr)
1134 		aclp->acl_cnt = acecnt;
1135 	if (aceerr)
1136 		*aclerrp = aceerr;
1137 	if (aclsizep)
1138 		*aclsizep = aclsize;
1139 nfsmout:
1140 	NFSEXITCODE2(error, nd);
1141 	return (error);
1142 }
1143 
1144 /*
1145  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1146  */
1147 static int
1148 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1149 {
1150 	u_int32_t *tl;
1151 	int error, len = 0;
1152 
1153 	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1154 	len = fxdr_unsigned(int, *(tl + 3));
1155 	error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1156 nfsmout:
1157 	*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1158 	NFSEXITCODE2(error, nd);
1159 	return (error);
1160 }
1161 
1162 /*
1163  * Get attribute bits from an mbuf list.
1164  * Returns EBADRPC for a parsing error, 0 otherwise.
1165  * If the clearinvalid flag is set, clear the bits not supported.
1166  */
1167 int
1168 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1169     int *retnotsupp)
1170 {
1171 	u_int32_t *tl;
1172 	int cnt, i, outcnt;
1173 	int error = 0;
1174 
1175 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1176 	cnt = fxdr_unsigned(int, *tl);
1177 	if (cnt < 0) {
1178 		error = NFSERR_BADXDR;
1179 		goto nfsmout;
1180 	}
1181 	if (cnt > NFSATTRBIT_MAXWORDS)
1182 		outcnt = NFSATTRBIT_MAXWORDS;
1183 	else
1184 		outcnt = cnt;
1185 	NFSZERO_ATTRBIT(attrbitp);
1186 	if (outcnt > 0) {
1187 		NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1188 		for (i = 0; i < outcnt; i++)
1189 			attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1190 	}
1191 	for (i = 0; i < (cnt - outcnt); i++) {
1192 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1193 		if (retnotsupp != NULL && *tl != 0)
1194 			*retnotsupp = NFSERR_ATTRNOTSUPP;
1195 	}
1196 	if (cntp)
1197 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1198 nfsmout:
1199 	NFSEXITCODE2(error, nd);
1200 	return (error);
1201 }
1202 
1203 /*
1204  * Get the attributes for V4.
1205  * If the compare flag is true, test for any attribute changes,
1206  * otherwise return the attribute values.
1207  * These attributes cover fields in "struct vattr", "struct statfs",
1208  * "struct nfsfsinfo", the file handle and the lease duration.
1209  * The value of retcmpp is set to 1 if all attributes are the same,
1210  * and 0 otherwise.
1211  * Returns EBADRPC if it can't be parsed, 0 otherwise.
1212  */
1213 int
1214 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1215     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1216     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1217     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1218     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1219 {
1220 	u_int32_t *tl;
1221 	int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1222 	int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1223 	u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1224 	nfsattrbit_t attrbits, retattrbits, checkattrbits;
1225 	struct nfsfh *tnfhp;
1226 	struct nfsreferral *refp;
1227 	u_quad_t tquad;
1228 	nfsquad_t tnfsquad;
1229 	struct timespec temptime;
1230 	uid_t uid;
1231 	gid_t gid;
1232 	u_int32_t freenum = 0, tuint;
1233 	u_int64_t uquad = 0, thyp, thyp2;
1234 #ifdef QUOTA
1235 	struct dqblk dqb;
1236 	uid_t savuid;
1237 #endif
1238 
1239 	CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1240 	if (compare) {
1241 		retnotsup = 0;
1242 		error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1243 	} else {
1244 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1245 	}
1246 	if (error)
1247 		goto nfsmout;
1248 
1249 	if (compare) {
1250 		*retcmpp = retnotsup;
1251 	} else {
1252 		/*
1253 		 * Just set default values to some of the important ones.
1254 		 */
1255 		if (nap != NULL) {
1256 			nap->na_type = VREG;
1257 			nap->na_mode = 0;
1258 			nap->na_rdev = (NFSDEV_T)0;
1259 			nap->na_mtime.tv_sec = 0;
1260 			nap->na_mtime.tv_nsec = 0;
1261 			nap->na_btime.tv_sec = -1;
1262 			nap->na_btime.tv_nsec = 0;
1263 			nap->na_gen = 0;
1264 			nap->na_flags = 0;
1265 			nap->na_blocksize = NFS_FABLKSIZE;
1266 		}
1267 		if (sbp != NULL) {
1268 			sbp->f_bsize = NFS_FABLKSIZE;
1269 			sbp->f_blocks = 0;
1270 			sbp->f_bfree = 0;
1271 			sbp->f_bavail = 0;
1272 			sbp->f_files = 0;
1273 			sbp->f_ffree = 0;
1274 		}
1275 		if (fsp != NULL) {
1276 			fsp->fs_rtmax = 8192;
1277 			fsp->fs_rtpref = 8192;
1278 			fsp->fs_maxname = NFS_MAXNAMLEN;
1279 			fsp->fs_wtmax = 8192;
1280 			fsp->fs_wtpref = 8192;
1281 			fsp->fs_wtmult = NFS_FABLKSIZE;
1282 			fsp->fs_dtpref = 8192;
1283 			fsp->fs_maxfilesize = 0xffffffffffffffffull;
1284 			fsp->fs_timedelta.tv_sec = 0;
1285 			fsp->fs_timedelta.tv_nsec = 1;
1286 			fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1287 				NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1288 		}
1289 		if (pc != NULL) {
1290 			pc->pc_linkmax = NFS_LINK_MAX;
1291 			pc->pc_namemax = NAME_MAX;
1292 			pc->pc_notrunc = 0;
1293 			pc->pc_chownrestricted = 0;
1294 			pc->pc_caseinsensitive = 0;
1295 			pc->pc_casepreserving = 1;
1296 		}
1297 		if (sfp != NULL) {
1298 			sfp->sf_ffiles = UINT64_MAX;
1299 			sfp->sf_tfiles = UINT64_MAX;
1300 			sfp->sf_afiles = UINT64_MAX;
1301 			sfp->sf_fbytes = UINT64_MAX;
1302 			sfp->sf_tbytes = UINT64_MAX;
1303 			sfp->sf_abytes = UINT64_MAX;
1304 		}
1305 	}
1306 
1307 	/*
1308 	 * Loop around getting the attributes.
1309 	 */
1310 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1311 	attrsize = fxdr_unsigned(int, *tl);
1312 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1313 	    if (attrsum > attrsize) {
1314 		error = NFSERR_BADXDR;
1315 		goto nfsmout;
1316 	    }
1317 	    if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1318 		switch (bitpos) {
1319 		case NFSATTRBIT_SUPPORTEDATTRS:
1320 			retnotsup = 0;
1321 			if (compare || nap == NULL)
1322 			    error = nfsrv_getattrbits(nd, &retattrbits,
1323 				&cnt, &retnotsup);
1324 			else
1325 			    error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1326 				&cnt, &retnotsup);
1327 			if (error)
1328 			    goto nfsmout;
1329 			if (compare && !(*retcmpp)) {
1330 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1331 
1332 			   /* Some filesystem do not support NFSv4ACL   */
1333 			   if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1334 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1335 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1336 		   	   }
1337 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1338 			       || retnotsup)
1339 				*retcmpp = NFSERR_NOTSAME;
1340 			}
1341 			attrsum += cnt;
1342 			break;
1343 		case NFSATTRBIT_TYPE:
1344 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1345 			if (compare) {
1346 				if (!(*retcmpp)) {
1347 				    if (nap->na_type != nfsv34tov_type(*tl))
1348 					*retcmpp = NFSERR_NOTSAME;
1349 				}
1350 			} else if (nap != NULL) {
1351 				nap->na_type = nfsv34tov_type(*tl);
1352 			}
1353 			attrsum += NFSX_UNSIGNED;
1354 			break;
1355 		case NFSATTRBIT_FHEXPIRETYPE:
1356 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1357 			if (compare && !(*retcmpp)) {
1358 				if (fxdr_unsigned(int, *tl) !=
1359 					NFSV4FHTYPE_PERSISTENT)
1360 					*retcmpp = NFSERR_NOTSAME;
1361 			}
1362 			attrsum += NFSX_UNSIGNED;
1363 			break;
1364 		case NFSATTRBIT_CHANGE:
1365 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1366 			if (compare) {
1367 				if (!(*retcmpp)) {
1368 				    if (nap->na_filerev != fxdr_hyper(tl))
1369 					*retcmpp = NFSERR_NOTSAME;
1370 				}
1371 			} else if (nap != NULL) {
1372 				nap->na_filerev = fxdr_hyper(tl);
1373 			}
1374 			attrsum += NFSX_HYPER;
1375 			break;
1376 		case NFSATTRBIT_SIZE:
1377 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1378 			if (compare) {
1379 				if (!(*retcmpp)) {
1380 				    if (nap->na_size != fxdr_hyper(tl))
1381 					*retcmpp = NFSERR_NOTSAME;
1382 				}
1383 			} else if (nap != NULL) {
1384 				nap->na_size = fxdr_hyper(tl);
1385 			}
1386 			attrsum += NFSX_HYPER;
1387 			break;
1388 		case NFSATTRBIT_LINKSUPPORT:
1389 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1390 			if (compare) {
1391 				if (!(*retcmpp)) {
1392 				    if (fsp->fs_properties & NFSV3_FSFLINK) {
1393 					if (*tl == newnfs_false)
1394 						*retcmpp = NFSERR_NOTSAME;
1395 				    } else {
1396 					if (*tl == newnfs_true)
1397 						*retcmpp = NFSERR_NOTSAME;
1398 				    }
1399 				}
1400 			} else if (fsp != NULL) {
1401 				if (*tl == newnfs_true)
1402 					fsp->fs_properties |= NFSV3_FSFLINK;
1403 				else
1404 					fsp->fs_properties &= ~NFSV3_FSFLINK;
1405 			}
1406 			attrsum += NFSX_UNSIGNED;
1407 			break;
1408 		case NFSATTRBIT_SYMLINKSUPPORT:
1409 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1410 			if (compare) {
1411 				if (!(*retcmpp)) {
1412 				    if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1413 					if (*tl == newnfs_false)
1414 						*retcmpp = NFSERR_NOTSAME;
1415 				    } else {
1416 					if (*tl == newnfs_true)
1417 						*retcmpp = NFSERR_NOTSAME;
1418 				    }
1419 				}
1420 			} else if (fsp != NULL) {
1421 				if (*tl == newnfs_true)
1422 					fsp->fs_properties |= NFSV3_FSFSYMLINK;
1423 				else
1424 					fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1425 			}
1426 			attrsum += NFSX_UNSIGNED;
1427 			break;
1428 		case NFSATTRBIT_NAMEDATTR:
1429 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1430 			if (compare && !(*retcmpp)) {
1431 				if (*tl != newnfs_false)
1432 					*retcmpp = NFSERR_NOTSAME;
1433 			}
1434 			attrsum += NFSX_UNSIGNED;
1435 			break;
1436 		case NFSATTRBIT_FSID:
1437 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1438 			thyp = fxdr_hyper(tl);
1439 			tl += 2;
1440 			thyp2 = fxdr_hyper(tl);
1441 			if (compare) {
1442 			    if (*retcmpp == 0) {
1443 				if (thyp != (u_int64_t)
1444 				    vp->v_mount->mnt_stat.f_fsid.val[0] ||
1445 				    thyp2 != (u_int64_t)
1446 				    vp->v_mount->mnt_stat.f_fsid.val[1])
1447 					*retcmpp = NFSERR_NOTSAME;
1448 			    }
1449 			} else if (nap != NULL) {
1450 				nap->na_filesid[0] = thyp;
1451 				nap->na_filesid[1] = thyp2;
1452 			}
1453 			attrsum += (4 * NFSX_UNSIGNED);
1454 			break;
1455 		case NFSATTRBIT_UNIQUEHANDLES:
1456 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1457 			if (compare && !(*retcmpp)) {
1458 				if (*tl != newnfs_true)
1459 					*retcmpp = NFSERR_NOTSAME;
1460 			}
1461 			attrsum += NFSX_UNSIGNED;
1462 			break;
1463 		case NFSATTRBIT_LEASETIME:
1464 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1465 			if (compare) {
1466 				if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1467 				    !(*retcmpp))
1468 					*retcmpp = NFSERR_NOTSAME;
1469 			} else if (leasep != NULL) {
1470 				*leasep = fxdr_unsigned(u_int32_t, *tl);
1471 			}
1472 			attrsum += NFSX_UNSIGNED;
1473 			break;
1474 		case NFSATTRBIT_RDATTRERROR:
1475 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1476 			if (compare) {
1477 				 if (!(*retcmpp))
1478 					*retcmpp = NFSERR_INVAL;
1479 			} else if (rderrp != NULL) {
1480 				*rderrp = fxdr_unsigned(u_int32_t, *tl);
1481 			}
1482 			attrsum += NFSX_UNSIGNED;
1483 			break;
1484 		case NFSATTRBIT_ACL:
1485 			if (compare) {
1486 			  if (!(*retcmpp)) {
1487 			    if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1488 				NFSACL_T *naclp;
1489 
1490 				naclp = acl_alloc(M_WAITOK);
1491 				error = nfsrv_dissectacl(nd, naclp, &aceerr,
1492 				    &cnt, p);
1493 				if (error) {
1494 				    acl_free(naclp);
1495 				    goto nfsmout;
1496 				}
1497 				if (aceerr || aclp == NULL ||
1498 				    nfsrv_compareacl(aclp, naclp))
1499 				    *retcmpp = NFSERR_NOTSAME;
1500 				acl_free(naclp);
1501 			    } else {
1502 				error = nfsrv_dissectacl(nd, NULL, &aceerr,
1503 				    &cnt, p);
1504 				if (error)
1505 				    goto nfsmout;
1506 				*retcmpp = NFSERR_ATTRNOTSUPP;
1507 			    }
1508 			  }
1509 			} else {
1510 				if (vp != NULL && aclp != NULL)
1511 				    error = nfsrv_dissectacl(nd, aclp, &aceerr,
1512 					&cnt, p);
1513 				else
1514 				    error = nfsrv_dissectacl(nd, NULL, &aceerr,
1515 					&cnt, p);
1516 				if (error)
1517 				    goto nfsmout;
1518 			}
1519 
1520 			attrsum += cnt;
1521 			break;
1522 		case NFSATTRBIT_ACLSUPPORT:
1523 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1524 			if (compare && !(*retcmpp)) {
1525 				if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1526 					if (fxdr_unsigned(u_int32_t, *tl) !=
1527 					    NFSV4ACE_SUPTYPES)
1528 						*retcmpp = NFSERR_NOTSAME;
1529 				} else {
1530 					*retcmpp = NFSERR_ATTRNOTSUPP;
1531 				}
1532 			}
1533 			attrsum += NFSX_UNSIGNED;
1534 			break;
1535 		case NFSATTRBIT_ARCHIVE:
1536 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1537 			if (compare && !(*retcmpp))
1538 				*retcmpp = NFSERR_ATTRNOTSUPP;
1539 			attrsum += NFSX_UNSIGNED;
1540 			break;
1541 		case NFSATTRBIT_CANSETTIME:
1542 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1543 			if (compare) {
1544 				if (!(*retcmpp)) {
1545 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1546 					if (*tl == newnfs_false)
1547 						*retcmpp = NFSERR_NOTSAME;
1548 				    } else {
1549 					if (*tl == newnfs_true)
1550 						*retcmpp = NFSERR_NOTSAME;
1551 				    }
1552 				}
1553 			} else if (fsp != NULL) {
1554 				if (*tl == newnfs_true)
1555 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1556 				else
1557 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1558 			}
1559 			attrsum += NFSX_UNSIGNED;
1560 			break;
1561 		case NFSATTRBIT_CASEINSENSITIVE:
1562 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1563 			if (compare) {
1564 				if (!(*retcmpp)) {
1565 				    if (*tl != newnfs_false)
1566 					*retcmpp = NFSERR_NOTSAME;
1567 				}
1568 			} else if (pc != NULL) {
1569 				pc->pc_caseinsensitive =
1570 				    fxdr_unsigned(u_int32_t, *tl);
1571 			}
1572 			attrsum += NFSX_UNSIGNED;
1573 			break;
1574 		case NFSATTRBIT_CASEPRESERVING:
1575 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1576 			if (compare) {
1577 				if (!(*retcmpp)) {
1578 				    if (*tl != newnfs_true)
1579 					*retcmpp = NFSERR_NOTSAME;
1580 				}
1581 			} else if (pc != NULL) {
1582 				pc->pc_casepreserving =
1583 				    fxdr_unsigned(u_int32_t, *tl);
1584 			}
1585 			attrsum += NFSX_UNSIGNED;
1586 			break;
1587 		case NFSATTRBIT_CHOWNRESTRICTED:
1588 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1589 			if (compare) {
1590 				if (!(*retcmpp)) {
1591 				    if (*tl != newnfs_true)
1592 					*retcmpp = NFSERR_NOTSAME;
1593 				}
1594 			} else if (pc != NULL) {
1595 				pc->pc_chownrestricted =
1596 				    fxdr_unsigned(u_int32_t, *tl);
1597 			}
1598 			attrsum += NFSX_UNSIGNED;
1599 			break;
1600 		case NFSATTRBIT_FILEHANDLE:
1601 			error = nfsm_getfh(nd, &tnfhp);
1602 			if (error)
1603 				goto nfsmout;
1604 			tfhsize = tnfhp->nfh_len;
1605 			if (compare) {
1606 				if (!(*retcmpp) &&
1607 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1608 				     fhp, fhsize))
1609 					*retcmpp = NFSERR_NOTSAME;
1610 				free(tnfhp, M_NFSFH);
1611 			} else if (nfhpp != NULL) {
1612 				*nfhpp = tnfhp;
1613 			} else {
1614 				free(tnfhp, M_NFSFH);
1615 			}
1616 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1617 			break;
1618 		case NFSATTRBIT_FILEID:
1619 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1620 			thyp = fxdr_hyper(tl);
1621 			if (compare) {
1622 				if (!(*retcmpp)) {
1623 					if (nap->na_fileid != thyp)
1624 						*retcmpp = NFSERR_NOTSAME;
1625 				}
1626 			} else if (nap != NULL)
1627 				nap->na_fileid = thyp;
1628 			attrsum += NFSX_HYPER;
1629 			break;
1630 		case NFSATTRBIT_FILESAVAIL:
1631 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1632 			if (compare) {
1633 				uquad = nfsv4_filesavail(sbp, vp->v_mount);
1634 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1635 					*retcmpp = NFSERR_NOTSAME;
1636 			} else if (sfp != NULL) {
1637 				sfp->sf_afiles = fxdr_hyper(tl);
1638 			}
1639 			attrsum += NFSX_HYPER;
1640 			break;
1641 		case NFSATTRBIT_FILESFREE:
1642 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1643 			if (compare) {
1644 				uquad = (uint64_t)sbp->f_ffree;
1645 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1646 					*retcmpp = NFSERR_NOTSAME;
1647 			} else if (sfp != NULL) {
1648 				sfp->sf_ffiles = fxdr_hyper(tl);
1649 			}
1650 			attrsum += NFSX_HYPER;
1651 			break;
1652 		case NFSATTRBIT_FILESTOTAL:
1653 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1654 			if (compare) {
1655 				uquad = sbp->f_files;
1656 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1657 					*retcmpp = NFSERR_NOTSAME;
1658 			} else if (sfp != NULL) {
1659 				sfp->sf_tfiles = fxdr_hyper(tl);
1660 			}
1661 			attrsum += NFSX_HYPER;
1662 			break;
1663 		case NFSATTRBIT_FSLOCATIONS:
1664 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1665 			if (error)
1666 				goto nfsmout;
1667 			attrsum += l;
1668 			if (compare && !(*retcmpp)) {
1669 				refp = nfsv4root_getreferral(vp, NULL, 0);
1670 				if (refp != NULL) {
1671 					if (cp == NULL || cp2 == NULL ||
1672 					    strcmp(cp, "/") ||
1673 					    strcmp(cp2, refp->nfr_srvlist))
1674 						*retcmpp = NFSERR_NOTSAME;
1675 				} else if (m == 0) {
1676 					*retcmpp = NFSERR_NOTSAME;
1677 				}
1678 			}
1679 			if (cp != NULL)
1680 				free(cp, M_NFSSTRING);
1681 			if (cp2 != NULL)
1682 				free(cp2, M_NFSSTRING);
1683 			break;
1684 		case NFSATTRBIT_HIDDEN:
1685 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1686 			if (compare && !(*retcmpp))
1687 				*retcmpp = NFSERR_ATTRNOTSUPP;
1688 			attrsum += NFSX_UNSIGNED;
1689 			break;
1690 		case NFSATTRBIT_HOMOGENEOUS:
1691 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1692 			if (compare) {
1693 				if (!(*retcmpp)) {
1694 				    if (fsp->fs_properties &
1695 					NFSV3_FSFHOMOGENEOUS) {
1696 					if (*tl == newnfs_false)
1697 						*retcmpp = NFSERR_NOTSAME;
1698 				    } else {
1699 					if (*tl == newnfs_true)
1700 						*retcmpp = NFSERR_NOTSAME;
1701 				    }
1702 				}
1703 			} else if (fsp != NULL) {
1704 				if (*tl == newnfs_true)
1705 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1706 				else
1707 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1708 			}
1709 			attrsum += NFSX_UNSIGNED;
1710 			break;
1711 		case NFSATTRBIT_MAXFILESIZE:
1712 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1713 			tnfsquad.qval = fxdr_hyper(tl);
1714 			if (compare) {
1715 				if (!(*retcmpp)) {
1716 					tquad = NFSRV_MAXFILESIZE;
1717 					if (tquad != tnfsquad.qval)
1718 						*retcmpp = NFSERR_NOTSAME;
1719 				}
1720 			} else if (fsp != NULL) {
1721 				fsp->fs_maxfilesize = tnfsquad.qval;
1722 			}
1723 			attrsum += NFSX_HYPER;
1724 			break;
1725 		case NFSATTRBIT_MAXLINK:
1726 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1727 			if (compare) {
1728 				if (!(*retcmpp)) {
1729 				    if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1730 					*retcmpp = NFSERR_NOTSAME;
1731 				}
1732 			} else if (pc != NULL) {
1733 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1734 			}
1735 			attrsum += NFSX_UNSIGNED;
1736 			break;
1737 		case NFSATTRBIT_MAXNAME:
1738 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1739 			if (compare) {
1740 				if (!(*retcmpp)) {
1741 				    if (fsp->fs_maxname !=
1742 					fxdr_unsigned(u_int32_t, *tl))
1743 						*retcmpp = NFSERR_NOTSAME;
1744 				}
1745 			} else {
1746 				tuint = fxdr_unsigned(u_int32_t, *tl);
1747 				/*
1748 				 * Some Linux NFSv4 servers report this
1749 				 * as 0 or 4billion, so I'll set it to
1750 				 * NFS_MAXNAMLEN. If a server actually creates
1751 				 * a name longer than NFS_MAXNAMLEN, it will
1752 				 * get an error back.
1753 				 */
1754 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1755 					tuint = NFS_MAXNAMLEN;
1756 				if (fsp != NULL)
1757 					fsp->fs_maxname = tuint;
1758 				if (pc != NULL)
1759 					pc->pc_namemax = tuint;
1760 			}
1761 			attrsum += NFSX_UNSIGNED;
1762 			break;
1763 		case NFSATTRBIT_MAXREAD:
1764 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1765 			if (compare) {
1766 				if (!(*retcmpp)) {
1767 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1768 					*(tl + 1)) || *tl != 0)
1769 					*retcmpp = NFSERR_NOTSAME;
1770 				}
1771 			} else if (fsp != NULL) {
1772 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1773 				fsp->fs_rtpref = fsp->fs_rtmax;
1774 				fsp->fs_dtpref = fsp->fs_rtpref;
1775 			}
1776 			attrsum += NFSX_HYPER;
1777 			break;
1778 		case NFSATTRBIT_MAXWRITE:
1779 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1780 			if (compare) {
1781 				if (!(*retcmpp)) {
1782 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1783 					*(tl + 1)) || *tl != 0)
1784 					*retcmpp = NFSERR_NOTSAME;
1785 				}
1786 			} else if (fsp != NULL) {
1787 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1788 				fsp->fs_wtpref = fsp->fs_wtmax;
1789 			}
1790 			attrsum += NFSX_HYPER;
1791 			break;
1792 		case NFSATTRBIT_MIMETYPE:
1793 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1794 			i = fxdr_unsigned(int, *tl);
1795 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1796 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1797 			if (error)
1798 				goto nfsmout;
1799 			if (compare && !(*retcmpp))
1800 				*retcmpp = NFSERR_ATTRNOTSUPP;
1801 			break;
1802 		case NFSATTRBIT_MODE:
1803 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1804 			if (compare) {
1805 				if (!(*retcmpp)) {
1806 				    if (nap->na_mode != nfstov_mode(*tl))
1807 					*retcmpp = NFSERR_NOTSAME;
1808 				}
1809 			} else if (nap != NULL) {
1810 				nap->na_mode = nfstov_mode(*tl);
1811 			}
1812 			attrsum += NFSX_UNSIGNED;
1813 			break;
1814 		case NFSATTRBIT_NOTRUNC:
1815 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1816 			if (compare) {
1817 				if (!(*retcmpp)) {
1818 				    if (*tl != newnfs_true)
1819 					*retcmpp = NFSERR_NOTSAME;
1820 				}
1821 			} else if (pc != NULL) {
1822 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1823 			}
1824 			attrsum += NFSX_UNSIGNED;
1825 			break;
1826 		case NFSATTRBIT_NUMLINKS:
1827 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1828 			tuint = fxdr_unsigned(u_int32_t, *tl);
1829 			if (compare) {
1830 			    if (!(*retcmpp)) {
1831 				if ((u_int32_t)nap->na_nlink != tuint)
1832 					*retcmpp = NFSERR_NOTSAME;
1833 			    }
1834 			} else if (nap != NULL) {
1835 				nap->na_nlink = tuint;
1836 			}
1837 			attrsum += NFSX_UNSIGNED;
1838 			break;
1839 		case NFSATTRBIT_OWNER:
1840 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1841 			j = fxdr_unsigned(int, *tl);
1842 			if (j < 0) {
1843 				error = NFSERR_BADXDR;
1844 				goto nfsmout;
1845 			}
1846 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1847 			if (j > NFSV4_SMALLSTR)
1848 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1849 			else
1850 				cp = namestr;
1851 			error = nfsrv_mtostr(nd, cp, j);
1852 			if (error) {
1853 				if (j > NFSV4_SMALLSTR)
1854 					free(cp, M_NFSSTRING);
1855 				goto nfsmout;
1856 			}
1857 			if (compare) {
1858 			    if (!(*retcmpp)) {
1859 				if (nfsv4_strtouid(nd, cp, j, &uid) ||
1860 				    nap->na_uid != uid)
1861 				    *retcmpp = NFSERR_NOTSAME;
1862 			    }
1863 			} else if (nap != NULL) {
1864 				if (nfsv4_strtouid(nd, cp, j, &uid))
1865 					nap->na_uid = nfsrv_defaultuid;
1866 				else
1867 					nap->na_uid = uid;
1868 			}
1869 			if (j > NFSV4_SMALLSTR)
1870 				free(cp, M_NFSSTRING);
1871 			break;
1872 		case NFSATTRBIT_OWNERGROUP:
1873 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1874 			j = fxdr_unsigned(int, *tl);
1875 			if (j < 0) {
1876 				error =  NFSERR_BADXDR;
1877 				goto nfsmout;
1878 			}
1879 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1880 			if (j > NFSV4_SMALLSTR)
1881 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1882 			else
1883 				cp = namestr;
1884 			error = nfsrv_mtostr(nd, cp, j);
1885 			if (error) {
1886 				if (j > NFSV4_SMALLSTR)
1887 					free(cp, M_NFSSTRING);
1888 				goto nfsmout;
1889 			}
1890 			if (compare) {
1891 			    if (!(*retcmpp)) {
1892 				if (nfsv4_strtogid(nd, cp, j, &gid) ||
1893 				    nap->na_gid != gid)
1894 				    *retcmpp = NFSERR_NOTSAME;
1895 			    }
1896 			} else if (nap != NULL) {
1897 				if (nfsv4_strtogid(nd, cp, j, &gid))
1898 					nap->na_gid = nfsrv_defaultgid;
1899 				else
1900 					nap->na_gid = gid;
1901 			}
1902 			if (j > NFSV4_SMALLSTR)
1903 				free(cp, M_NFSSTRING);
1904 			break;
1905 		case NFSATTRBIT_QUOTAHARD:
1906 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1907 			if (sbp != NULL) {
1908 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1909 				freenum = sbp->f_bfree;
1910 			    else
1911 				freenum = sbp->f_bavail;
1912 #ifdef QUOTA
1913 			    /*
1914 			     * ufs_quotactl() insists that the uid argument
1915 			     * equal p_ruid for non-root quota access, so
1916 			     * we'll just make sure that's the case.
1917 			     */
1918 			    savuid = p->p_cred->p_ruid;
1919 			    p->p_cred->p_ruid = cred->cr_uid;
1920 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1921 				USRQUOTA), cred->cr_uid, &dqb))
1922 				freenum = min(dqb.dqb_bhardlimit, freenum);
1923 			    p->p_cred->p_ruid = savuid;
1924 #endif	/* QUOTA */
1925 			    uquad = (u_int64_t)freenum;
1926 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1927 			}
1928 			if (compare && !(*retcmpp)) {
1929 				if (uquad != fxdr_hyper(tl))
1930 					*retcmpp = NFSERR_NOTSAME;
1931 			}
1932 			attrsum += NFSX_HYPER;
1933 			break;
1934 		case NFSATTRBIT_QUOTASOFT:
1935 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1936 			if (sbp != NULL) {
1937 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1938 				freenum = sbp->f_bfree;
1939 			    else
1940 				freenum = sbp->f_bavail;
1941 #ifdef QUOTA
1942 			    /*
1943 			     * ufs_quotactl() insists that the uid argument
1944 			     * equal p_ruid for non-root quota access, so
1945 			     * we'll just make sure that's the case.
1946 			     */
1947 			    savuid = p->p_cred->p_ruid;
1948 			    p->p_cred->p_ruid = cred->cr_uid;
1949 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1950 				USRQUOTA), cred->cr_uid, &dqb))
1951 				freenum = min(dqb.dqb_bsoftlimit, freenum);
1952 			    p->p_cred->p_ruid = savuid;
1953 #endif	/* QUOTA */
1954 			    uquad = (u_int64_t)freenum;
1955 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1956 			}
1957 			if (compare && !(*retcmpp)) {
1958 				if (uquad != fxdr_hyper(tl))
1959 					*retcmpp = NFSERR_NOTSAME;
1960 			}
1961 			attrsum += NFSX_HYPER;
1962 			break;
1963 		case NFSATTRBIT_QUOTAUSED:
1964 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1965 			if (sbp != NULL) {
1966 			    freenum = 0;
1967 #ifdef QUOTA
1968 			    /*
1969 			     * ufs_quotactl() insists that the uid argument
1970 			     * equal p_ruid for non-root quota access, so
1971 			     * we'll just make sure that's the case.
1972 			     */
1973 			    savuid = p->p_cred->p_ruid;
1974 			    p->p_cred->p_ruid = cred->cr_uid;
1975 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1976 				USRQUOTA), cred->cr_uid, &dqb))
1977 				freenum = dqb.dqb_curblocks;
1978 			    p->p_cred->p_ruid = savuid;
1979 #endif	/* QUOTA */
1980 			    uquad = (u_int64_t)freenum;
1981 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1982 			}
1983 			if (compare && !(*retcmpp)) {
1984 				if (uquad != fxdr_hyper(tl))
1985 					*retcmpp = NFSERR_NOTSAME;
1986 			}
1987 			attrsum += NFSX_HYPER;
1988 			break;
1989 		case NFSATTRBIT_RAWDEV:
1990 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1991 			j = fxdr_unsigned(int, *tl++);
1992 			k = fxdr_unsigned(int, *tl);
1993 			if (compare) {
1994 			    if (!(*retcmpp)) {
1995 				if (nap->na_rdev != NFSMAKEDEV(j, k))
1996 					*retcmpp = NFSERR_NOTSAME;
1997 			    }
1998 			} else if (nap != NULL) {
1999 				nap->na_rdev = NFSMAKEDEV(j, k);
2000 			}
2001 			attrsum += NFSX_V4SPECDATA;
2002 			break;
2003 		case NFSATTRBIT_SPACEAVAIL:
2004 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2005 			if (compare) {
2006 				if (priv_check_cred(cred,
2007 				    PRIV_VFS_BLOCKRESERVE))
2008 					uquad = sbp->f_bfree;
2009 				else
2010 					uquad = (uint64_t)sbp->f_bavail;
2011 				uquad *= sbp->f_bsize;
2012 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2013 					*retcmpp = NFSERR_NOTSAME;
2014 			} else if (sfp != NULL) {
2015 				sfp->sf_abytes = fxdr_hyper(tl);
2016 			}
2017 			attrsum += NFSX_HYPER;
2018 			break;
2019 		case NFSATTRBIT_SPACEFREE:
2020 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2021 			if (compare) {
2022 				uquad = sbp->f_bfree;
2023 				uquad *= sbp->f_bsize;
2024 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2025 					*retcmpp = NFSERR_NOTSAME;
2026 			} else if (sfp != NULL) {
2027 				sfp->sf_fbytes = fxdr_hyper(tl);
2028 			}
2029 			attrsum += NFSX_HYPER;
2030 			break;
2031 		case NFSATTRBIT_SPACETOTAL:
2032 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2033 			if (compare) {
2034 				uquad = sbp->f_blocks;
2035 				uquad *= sbp->f_bsize;
2036 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2037 					*retcmpp = NFSERR_NOTSAME;
2038 			} else if (sfp != NULL) {
2039 				sfp->sf_tbytes = fxdr_hyper(tl);
2040 			}
2041 			attrsum += NFSX_HYPER;
2042 			break;
2043 		case NFSATTRBIT_SPACEUSED:
2044 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2045 			thyp = fxdr_hyper(tl);
2046 			if (compare) {
2047 			    if (!(*retcmpp)) {
2048 				if ((u_int64_t)nap->na_bytes != thyp)
2049 					*retcmpp = NFSERR_NOTSAME;
2050 			    }
2051 			} else if (nap != NULL) {
2052 				nap->na_bytes = thyp;
2053 			}
2054 			attrsum += NFSX_HYPER;
2055 			break;
2056 		case NFSATTRBIT_SYSTEM:
2057 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2058 			if (compare && !(*retcmpp))
2059 				*retcmpp = NFSERR_ATTRNOTSUPP;
2060 			attrsum += NFSX_UNSIGNED;
2061 			break;
2062 		case NFSATTRBIT_TIMEACCESS:
2063 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2064 			fxdr_nfsv4time(tl, &temptime);
2065 			if (compare) {
2066 			    if (!(*retcmpp)) {
2067 				if (!NFS_CMPTIME(temptime, nap->na_atime))
2068 					*retcmpp = NFSERR_NOTSAME;
2069 			    }
2070 			} else if (nap != NULL) {
2071 				nap->na_atime = temptime;
2072 			}
2073 			attrsum += NFSX_V4TIME;
2074 			break;
2075 		case NFSATTRBIT_TIMEACCESSSET:
2076 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2077 			attrsum += NFSX_UNSIGNED;
2078 			i = fxdr_unsigned(int, *tl);
2079 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2080 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2081 				attrsum += NFSX_V4TIME;
2082 			}
2083 			if (compare && !(*retcmpp))
2084 				*retcmpp = NFSERR_INVAL;
2085 			break;
2086 		case NFSATTRBIT_TIMEBACKUP:
2087 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2088 			if (compare && !(*retcmpp))
2089 				*retcmpp = NFSERR_ATTRNOTSUPP;
2090 			attrsum += NFSX_V4TIME;
2091 			break;
2092 		case NFSATTRBIT_TIMECREATE:
2093 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2094 			fxdr_nfsv4time(tl, &temptime);
2095 			if (compare) {
2096 			    if (!(*retcmpp)) {
2097 				if (!NFS_CMPTIME(temptime, nap->na_btime))
2098 					*retcmpp = NFSERR_NOTSAME;
2099 			    }
2100 			} else if (nap != NULL) {
2101 				nap->na_btime = temptime;
2102 			}
2103 			attrsum += NFSX_V4TIME;
2104 			break;
2105 		case NFSATTRBIT_TIMEDELTA:
2106 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2107 			if (fsp != NULL) {
2108 			    if (compare) {
2109 				if (!(*retcmpp)) {
2110 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2111 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2112 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2113 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
2114 					 1000000000) ||
2115 					*tl != 0)
2116 					    *retcmpp = NFSERR_NOTSAME;
2117 				}
2118 			    } else {
2119 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2120 			    }
2121 			}
2122 			attrsum += NFSX_V4TIME;
2123 			break;
2124 		case NFSATTRBIT_TIMEMETADATA:
2125 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2126 			fxdr_nfsv4time(tl, &temptime);
2127 			if (compare) {
2128 			    if (!(*retcmpp)) {
2129 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
2130 					*retcmpp = NFSERR_NOTSAME;
2131 			    }
2132 			} else if (nap != NULL) {
2133 				nap->na_ctime = temptime;
2134 			}
2135 			attrsum += NFSX_V4TIME;
2136 			break;
2137 		case NFSATTRBIT_TIMEMODIFY:
2138 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2139 			fxdr_nfsv4time(tl, &temptime);
2140 			if (compare) {
2141 			    if (!(*retcmpp)) {
2142 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
2143 					*retcmpp = NFSERR_NOTSAME;
2144 			    }
2145 			} else if (nap != NULL) {
2146 				nap->na_mtime = temptime;
2147 			}
2148 			attrsum += NFSX_V4TIME;
2149 			break;
2150 		case NFSATTRBIT_TIMEMODIFYSET:
2151 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2152 			attrsum += NFSX_UNSIGNED;
2153 			i = fxdr_unsigned(int, *tl);
2154 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2155 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2156 				attrsum += NFSX_V4TIME;
2157 			}
2158 			if (compare && !(*retcmpp))
2159 				*retcmpp = NFSERR_INVAL;
2160 			break;
2161 		case NFSATTRBIT_MOUNTEDONFILEID:
2162 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2163 			thyp = fxdr_hyper(tl);
2164 			if (compare) {
2165 				if (!(*retcmpp)) {
2166 					if (!vp || !nfsrv_atroot(vp, &thyp2))
2167 						thyp2 = nap->na_fileid;
2168 					if (thyp2 != thyp)
2169 						*retcmpp = NFSERR_NOTSAME;
2170 				}
2171 			} else if (nap != NULL)
2172 				nap->na_mntonfileno = thyp;
2173 			attrsum += NFSX_HYPER;
2174 			break;
2175 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2176 			retnotsup = 0;
2177 			error = nfsrv_getattrbits(nd, &retattrbits,
2178 			    &cnt, &retnotsup);
2179 			if (error)
2180 			    goto nfsmout;
2181 			if (compare && !(*retcmpp)) {
2182 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2183 			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2184 			   NFSCLRBIT_ATTRBIT(&checkattrbits,
2185 				NFSATTRBIT_TIMEACCESSSET);
2186 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2187 			       || retnotsup)
2188 				*retcmpp = NFSERR_NOTSAME;
2189 			}
2190 			attrsum += cnt;
2191 			break;
2192 		case NFSATTRBIT_FSLAYOUTTYPE:
2193 		case NFSATTRBIT_LAYOUTTYPE:
2194 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2195 			attrsum += NFSX_UNSIGNED;
2196 			i = fxdr_unsigned(int, *tl);
2197 			/*
2198 			 * The RFCs do not define an upper limit for the
2199 			 * number of layout types, but 32 should be more
2200 			 * than enough.
2201 			 */
2202 			if (i < 0 || i > 32) {
2203 				error = NFSERR_BADXDR;
2204 				goto nfsmout;
2205 			}
2206 			if (i > 0) {
2207 				NFSM_DISSECT(tl, u_int32_t *, i *
2208 				    NFSX_UNSIGNED);
2209 				attrsum += i * NFSX_UNSIGNED;
2210 				j = fxdr_unsigned(int, *tl);
2211 				if (i == 1 && compare && !(*retcmpp) &&
2212 				    (((nfsrv_doflexfile != 0 ||
2213 				       nfsrv_maxpnfsmirror > 1) &&
2214 				      j != NFSLAYOUT_FLEXFILE) ||
2215 				    (nfsrv_doflexfile == 0 &&
2216 				     j != NFSLAYOUT_NFSV4_1_FILES)))
2217 					*retcmpp = NFSERR_NOTSAME;
2218 			}
2219 			if (nfsrv_devidcnt == 0) {
2220 				if (compare && !(*retcmpp) && i > 0)
2221 					*retcmpp = NFSERR_NOTSAME;
2222 			} else {
2223 				if (compare && !(*retcmpp) && i != 1)
2224 					*retcmpp = NFSERR_NOTSAME;
2225 			}
2226 			break;
2227 		case NFSATTRBIT_LAYOUTALIGNMENT:
2228 		case NFSATTRBIT_LAYOUTBLKSIZE:
2229 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2230 			attrsum += NFSX_UNSIGNED;
2231 			i = fxdr_unsigned(int, *tl);
2232 			if (compare && !(*retcmpp) && i != nfs_srvmaxio)
2233 				*retcmpp = NFSERR_NOTSAME;
2234 			break;
2235 		default:
2236 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2237 				bitpos);
2238 			if (compare && !(*retcmpp))
2239 				*retcmpp = NFSERR_ATTRNOTSUPP;
2240 			/*
2241 			 * and get out of the loop, since we can't parse
2242 			 * the unknown attrbute data.
2243 			 */
2244 			bitpos = NFSATTRBIT_MAX;
2245 			break;
2246 		}
2247 	}
2248 
2249 	/*
2250 	 * some clients pad the attrlist, so we need to skip over the
2251 	 * padding.
2252 	 */
2253 	if (attrsum > attrsize) {
2254 		error = NFSERR_BADXDR;
2255 	} else {
2256 		attrsize = NFSM_RNDUP(attrsize);
2257 		if (attrsum < attrsize)
2258 			error = nfsm_advance(nd, attrsize - attrsum, -1);
2259 	}
2260 nfsmout:
2261 	NFSEXITCODE2(error, nd);
2262 	return (error);
2263 }
2264 
2265 /*
2266  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2267  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2268  * The first argument is a pointer to an nfsv4lock structure.
2269  * The second argument is 1 iff a blocking lock is wanted.
2270  * If this argument is 0, the call waits until no thread either wants nor
2271  * holds an exclusive lock.
2272  * It returns 1 if the lock was acquired, 0 otherwise.
2273  * If several processes call this function concurrently wanting the exclusive
2274  * lock, one will get the lock and the rest will return without getting the
2275  * lock. (If the caller must have the lock, it simply calls this function in a
2276  *  loop until the function returns 1 to indicate the lock was acquired.)
2277  * Any usecnt must be decremented by calling nfsv4_relref() before
2278  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2279  * be called in a loop.
2280  * The isleptp argument is set to indicate if the call slept, iff not NULL
2281  * and the mp argument indicates to check for a forced dismount, iff not
2282  * NULL.
2283  */
2284 int
2285 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2286     struct mtx *mutex, struct mount *mp)
2287 {
2288 
2289 	if (isleptp)
2290 		*isleptp = 0;
2291 	/*
2292 	 * If a lock is wanted, loop around until the lock is acquired by
2293 	 * someone and then released. If I want the lock, try to acquire it.
2294 	 * For a lock to be issued, no lock must be in force and the usecnt
2295 	 * must be zero.
2296 	 */
2297 	if (iwantlock) {
2298 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2299 		lp->nfslock_usecnt == 0) {
2300 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2301 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
2302 		return (1);
2303 	    }
2304 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2305 	}
2306 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2307 		if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2308 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2309 			return (0);
2310 		}
2311 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2312 		if (isleptp)
2313 			*isleptp = 1;
2314 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
2315 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2316 		    lp->nfslock_usecnt == 0) {
2317 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2318 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
2319 			return (1);
2320 		}
2321 	}
2322 	return (0);
2323 }
2324 
2325 /*
2326  * Release the lock acquired by nfsv4_lock().
2327  * The second argument is set to 1 to indicate the nfslock_usecnt should be
2328  * incremented, as well.
2329  */
2330 void
2331 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2332 {
2333 
2334 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2335 	if (incref)
2336 		lp->nfslock_usecnt++;
2337 	nfsv4_wanted(lp);
2338 }
2339 
2340 /*
2341  * Release a reference cnt.
2342  */
2343 void
2344 nfsv4_relref(struct nfsv4lock *lp)
2345 {
2346 
2347 	if (lp->nfslock_usecnt <= 0)
2348 		panic("nfsv4root ref cnt");
2349 	lp->nfslock_usecnt--;
2350 	if (lp->nfslock_usecnt == 0)
2351 		nfsv4_wanted(lp);
2352 }
2353 
2354 /*
2355  * Get a reference cnt.
2356  * This function will wait for any exclusive lock to be released, but will
2357  * not wait for threads that want the exclusive lock. If priority needs
2358  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2359  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2360  * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2361  * return without getting a refcnt for that case.
2362  */
2363 void
2364 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
2365     struct mount *mp)
2366 {
2367 
2368 	if (isleptp)
2369 		*isleptp = 0;
2370 
2371 	/*
2372 	 * Wait for a lock held.
2373 	 */
2374 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2375 		if (mp != NULL && NFSCL_FORCEDISM(mp))
2376 			return;
2377 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2378 		if (isleptp)
2379 			*isleptp = 1;
2380 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
2381 	}
2382 	if (mp != NULL && NFSCL_FORCEDISM(mp))
2383 		return;
2384 
2385 	lp->nfslock_usecnt++;
2386 }
2387 
2388 /*
2389  * Get a reference as above, but return failure instead of sleeping if
2390  * an exclusive lock is held.
2391  */
2392 int
2393 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2394 {
2395 
2396 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2397 		return (0);
2398 
2399 	lp->nfslock_usecnt++;
2400 	return (1);
2401 }
2402 
2403 /*
2404  * Test for a lock. Return 1 if locked, 0 otherwise.
2405  */
2406 int
2407 nfsv4_testlock(struct nfsv4lock *lp)
2408 {
2409 
2410 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2411 	    lp->nfslock_usecnt == 0)
2412 		return (0);
2413 	return (1);
2414 }
2415 
2416 /*
2417  * Wake up anyone sleeping, waiting for this lock.
2418  */
2419 static void
2420 nfsv4_wanted(struct nfsv4lock *lp)
2421 {
2422 
2423 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2424 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2425 		wakeup((caddr_t)&lp->nfslock_lock);
2426 	}
2427 }
2428 
2429 /*
2430  * Copy a string from an mbuf list into a character array.
2431  * Return EBADRPC if there is an mbuf error,
2432  * 0 otherwise.
2433  */
2434 int
2435 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2436 {
2437 	char *cp;
2438 	int xfer, len;
2439 	struct mbuf *mp;
2440 	int rem, error = 0;
2441 
2442 	mp = nd->nd_md;
2443 	cp = nd->nd_dpos;
2444 	len = mtod(mp, caddr_t) + mp->m_len - cp;
2445 	rem = NFSM_RNDUP(siz) - siz;
2446 	while (siz > 0) {
2447 		if (len > siz)
2448 			xfer = siz;
2449 		else
2450 			xfer = len;
2451 		NFSBCOPY(cp, str, xfer);
2452 		str += xfer;
2453 		siz -= xfer;
2454 		if (siz > 0) {
2455 			mp = mp->m_next;
2456 			if (mp == NULL) {
2457 				error = EBADRPC;
2458 				goto out;
2459 			}
2460 			cp = mtod(mp, caddr_t);
2461 			len = mp->m_len;
2462 		} else {
2463 			cp += xfer;
2464 			len -= xfer;
2465 		}
2466 	}
2467 	*str = '\0';
2468 	nd->nd_dpos = cp;
2469 	nd->nd_md = mp;
2470 	if (rem > 0) {
2471 		if (len < rem)
2472 			error = nfsm_advance(nd, rem, len);
2473 		else
2474 			nd->nd_dpos += rem;
2475 	}
2476 
2477 out:
2478 	NFSEXITCODE2(error, nd);
2479 	return (error);
2480 }
2481 
2482 /*
2483  * Fill in the attributes as marked by the bitmap (V4).
2484  */
2485 int
2486 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2487     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2488     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2489     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2490     struct statfs *pnfssf)
2491 {
2492 	int bitpos, retnum = 0;
2493 	u_int32_t *tl;
2494 	int siz, prefixnum, error;
2495 	u_char *cp, namestr[NFSV4_SMALLSTR];
2496 	nfsattrbit_t attrbits, retbits;
2497 	nfsattrbit_t *retbitp = &retbits;
2498 	u_int32_t freenum, *retnump;
2499 	u_int64_t uquad;
2500 	struct statfs *fs;
2501 	struct nfsfsinfo fsinf;
2502 	struct timespec temptime;
2503 	NFSACL_T *aclp, *naclp = NULL;
2504 	size_t atsiz;
2505 	bool xattrsupp;
2506 #ifdef QUOTA
2507 	struct dqblk dqb;
2508 	uid_t savuid;
2509 #endif
2510 
2511 	/*
2512 	 * First, set the bits that can be filled and get fsinfo.
2513 	 */
2514 	NFSSET_ATTRBIT(retbitp, attrbitp);
2515 	/*
2516 	 * If both p and cred are NULL, it is a client side setattr call.
2517 	 * If both p and cred are not NULL, it is a server side reply call.
2518 	 * If p is not NULL and cred is NULL, it is a client side callback
2519 	 * reply call.
2520 	 */
2521 	if (p == NULL && cred == NULL) {
2522 		NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2523 		aclp = saclp;
2524 	} else {
2525 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2526 		naclp = acl_alloc(M_WAITOK);
2527 		aclp = naclp;
2528 	}
2529 	nfsvno_getfs(&fsinf, isdgram);
2530 #ifndef APPLE
2531 	/*
2532 	 * Get the VFS_STATFS(), since some attributes need them.
2533 	 */
2534 	fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2535 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2536 		error = VFS_STATFS(mp, fs);
2537 		if (error != 0) {
2538 			if (reterr) {
2539 				nd->nd_repstat = NFSERR_ACCES;
2540 				free(fs, M_STATFS);
2541 				return (0);
2542 			}
2543 			NFSCLRSTATFS_ATTRBIT(retbitp);
2544 		}
2545 		/*
2546 		 * Since NFS handles these values as unsigned on the
2547 		 * wire, there is no way to represent negative values,
2548 		 * so set them to 0. Without this, they will appear
2549 		 * to be very large positive values for clients like
2550 		 * Solaris10.
2551 		 */
2552 		if (fs->f_bavail < 0)
2553 			fs->f_bavail = 0;
2554 		if (fs->f_ffree < 0)
2555 			fs->f_ffree = 0;
2556 	}
2557 #endif
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, vnode_vtype(vp), 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