xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision 7fdf0e883567d96d27d929c49a74d5fdb84d550b)
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 }
934 
935 /*
936  * Put a file handle in an mbuf list.
937  * If the size argument == 0, just use the default size.
938  * set_true == 1 if there should be an newnfs_true prepended on the file handle.
939  * Return the number of bytes output, including XDR overhead.
940  */
941 int
942 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
943 {
944 	u_int32_t *tl;
945 	u_int8_t *cp;
946 	int fullsiz, bytesize = 0;
947 
948 	if (size == 0)
949 		size = NFSX_MYFH;
950 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
951 	case ND_NFSV2:
952 		if (size > NFSX_V2FH)
953 			panic("fh size > NFSX_V2FH for NFSv2");
954 		NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
955 		NFSBCOPY(fhp, cp, size);
956 		if (size < NFSX_V2FH)
957 			NFSBZERO(cp + size, NFSX_V2FH - size);
958 		bytesize = NFSX_V2FH;
959 		break;
960 	case ND_NFSV3:
961 	case ND_NFSV4:
962 		fullsiz = NFSM_RNDUP(size);
963 		if (set_true) {
964 		    bytesize = 2 * NFSX_UNSIGNED + fullsiz;
965 		    NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
966 		    *tl = newnfs_true;
967 		} else {
968 		    bytesize = NFSX_UNSIGNED + fullsiz;
969 		}
970 		(void) nfsm_strtom(nd, fhp, size);
971 		break;
972 	}
973 	return (bytesize);
974 }
975 
976 /*
977  * This function compares two net addresses by family and returns TRUE
978  * if they are the same host.
979  * If there is any doubt, return FALSE.
980  * The AF_INET family is handled as a special case so that address mbufs
981  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
982  */
983 int
984 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
985 {
986 #ifdef INET
987 	struct sockaddr_in *inetaddr;
988 #endif
989 
990 	switch (family) {
991 #ifdef INET
992 	case AF_INET:
993 		inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
994 		if (inetaddr->sin_family == AF_INET &&
995 		    inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
996 			return (1);
997 		break;
998 #endif
999 #ifdef INET6
1000 	case AF_INET6:
1001 		{
1002 		struct sockaddr_in6 *inetaddr6;
1003 
1004 		inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
1005 		/* XXX - should test sin6_scope_id ? */
1006 		if (inetaddr6->sin6_family == AF_INET6 &&
1007 		    IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
1008 			  &haddr->had_inet6))
1009 			return (1);
1010 		}
1011 		break;
1012 #endif
1013 	}
1014 	return (0);
1015 }
1016 
1017 /*
1018  * Similar to the above, but takes to NFSSOCKADDR_T args.
1019  */
1020 int
1021 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
1022 {
1023 	struct sockaddr_in *addr1, *addr2;
1024 	struct sockaddr *inaddr;
1025 
1026 	inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
1027 	switch (inaddr->sa_family) {
1028 	case AF_INET:
1029 		addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
1030 		addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
1031 		if (addr2->sin_family == AF_INET &&
1032 		    addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
1033 			return (1);
1034 		break;
1035 #ifdef INET6
1036 	case AF_INET6:
1037 		{
1038 		struct sockaddr_in6 *inet6addr1, *inet6addr2;
1039 
1040 		inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
1041 		inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
1042 		/* XXX - should test sin6_scope_id ? */
1043 		if (inet6addr2->sin6_family == AF_INET6 &&
1044 		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1045 			  &inet6addr2->sin6_addr))
1046 			return (1);
1047 		}
1048 		break;
1049 #endif
1050 	}
1051 	return (0);
1052 }
1053 
1054 /*
1055  * Dissect a file handle on the client.
1056  */
1057 int
1058 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1059 {
1060 	u_int32_t *tl;
1061 	struct nfsfh *nfhp;
1062 	int error, len;
1063 
1064 	*nfhpp = NULL;
1065 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1066 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1067 		if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1068 			len > NFSX_FHMAX) {
1069 			error = EBADRPC;
1070 			goto nfsmout;
1071 		}
1072 	} else
1073 		len = NFSX_V2FH;
1074 	nfhp = malloc(sizeof (struct nfsfh) + len,
1075 	    M_NFSFH, M_WAITOK);
1076 	error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1077 	if (error) {
1078 		free(nfhp, M_NFSFH);
1079 		goto nfsmout;
1080 	}
1081 	nfhp->nfh_len = len;
1082 	*nfhpp = nfhp;
1083 nfsmout:
1084 	NFSEXITCODE2(error, nd);
1085 	return (error);
1086 }
1087 
1088 /*
1089  * Break down the nfsv4 acl.
1090  * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1091  */
1092 int
1093 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, bool dacl,
1094     int *aclerrp, int *aclsizep, __unused NFSPROC_T *p)
1095 {
1096 	u_int32_t *tl;
1097 	int i, aclsize;
1098 	int acecnt, error = 0, aceerr = 0, acesize;
1099 
1100 	*aclerrp = 0;
1101 	if (aclp)
1102 		aclp->acl_cnt = 0;
1103 	/*
1104 	 * Parse out the ace entries and expect them to conform to
1105 	 * what can be supported by R/W/X bits.
1106 	 */
1107 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1108 	aclsize = NFSX_UNSIGNED;
1109 	acecnt = fxdr_unsigned(int, *tl);
1110 	/*
1111 	 * The RFCs do not define a fixed limit to the number of ACEs in
1112 	 * an ACL, but 10240 should be more than sufficient.
1113 	 */
1114 	if (acecnt < 0 || acecnt > 10240) {
1115 		error = NFSERR_BADXDR;
1116 		goto nfsmout;
1117 	}
1118 	if (acecnt > ACL_MAX_ENTRIES)
1119 		aceerr = NFSERR_ATTRNOTSUPP;
1120 	if (nfsrv_useacl == 0)
1121 		aceerr = NFSERR_ATTRNOTSUPP;
1122 	for (i = 0; i < acecnt; i++) {
1123 		if (aclp && !aceerr)
1124 			error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1125 			    dacl, &aceerr, &acesize, p);
1126 		else
1127 			error = nfsrv_skipace(nd, &acesize);
1128 		if (error)
1129 			goto nfsmout;
1130 		aclsize += acesize;
1131 	}
1132 	if (aclp && !aceerr)
1133 		aclp->acl_cnt = acecnt;
1134 	if (aceerr)
1135 		*aclerrp = aceerr;
1136 	if (aclsizep)
1137 		*aclsizep = aclsize;
1138 nfsmout:
1139 	NFSEXITCODE2(error, nd);
1140 	return (error);
1141 }
1142 
1143 /*
1144  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1145  */
1146 static int
1147 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1148 {
1149 	u_int32_t *tl;
1150 	int error, len = 0;
1151 
1152 	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1153 	len = fxdr_unsigned(int, *(tl + 3));
1154 	error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1155 nfsmout:
1156 	*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1157 	NFSEXITCODE2(error, nd);
1158 	return (error);
1159 }
1160 
1161 /*
1162  * Get attribute bits from an mbuf list.
1163  * Returns EBADRPC for a parsing error, 0 otherwise.
1164  * If the clearinvalid flag is set, clear the bits not supported.
1165  */
1166 int
1167 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1168     int *retnotsupp)
1169 {
1170 	u_int32_t *tl;
1171 	int cnt, i, outcnt;
1172 	int error = 0;
1173 
1174 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1175 	cnt = fxdr_unsigned(int, *tl);
1176 	if (cnt < 0) {
1177 		error = NFSERR_BADXDR;
1178 		goto nfsmout;
1179 	}
1180 	if (cnt > NFSATTRBIT_MAXWORDS)
1181 		outcnt = NFSATTRBIT_MAXWORDS;
1182 	else
1183 		outcnt = cnt;
1184 	NFSZERO_ATTRBIT(attrbitp);
1185 	if (outcnt > 0) {
1186 		NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1187 		for (i = 0; i < outcnt; i++)
1188 			attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1189 	}
1190 	for (i = 0; i < (cnt - outcnt); i++) {
1191 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1192 		if (retnotsupp != NULL && *tl != 0)
1193 			*retnotsupp = NFSERR_ATTRNOTSUPP;
1194 	}
1195 	if (cntp)
1196 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1197 nfsmout:
1198 	NFSEXITCODE2(error, nd);
1199 	return (error);
1200 }
1201 
1202 /*
1203  * Get the attributes for V4.
1204  * If the compare flag is true, test for any attribute changes,
1205  * otherwise return the attribute values.
1206  * These attributes cover fields in "struct vattr", "struct statfs",
1207  * "struct nfsfsinfo", the file handle and the lease duration.
1208  * The value of retcmpp is set to 1 if all attributes are the same,
1209  * and 0 otherwise.
1210  * Returns EBADRPC if it can't be parsed, 0 otherwise.
1211  */
1212 int
1213 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1214     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1215     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1216     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1217     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1218 {
1219 	u_int32_t *tl;
1220 	int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1221 	int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1222 	u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1223 	nfsattrbit_t attrbits, retattrbits, checkattrbits;
1224 	struct nfsfh *tnfhp;
1225 	struct nfsreferral *refp;
1226 	u_quad_t tquad;
1227 	nfsquad_t tnfsquad;
1228 	struct timespec temptime;
1229 	uid_t uid;
1230 	gid_t gid;
1231 	u_int32_t freenum = 0, tuint;
1232 	u_int64_t uquad = 0, thyp, thyp2;
1233 #ifdef QUOTA
1234 	struct dqblk dqb;
1235 	uid_t savuid;
1236 #endif
1237 
1238 	CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1239 	if (compare) {
1240 		retnotsup = 0;
1241 		error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1242 	} else {
1243 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1244 	}
1245 	if (error)
1246 		goto nfsmout;
1247 
1248 	if (compare) {
1249 		*retcmpp = retnotsup;
1250 	} else {
1251 		/*
1252 		 * Just set default values to some of the important ones.
1253 		 */
1254 		if (nap != NULL) {
1255 			nap->na_type = VREG;
1256 			nap->na_mode = 0;
1257 			nap->na_rdev = (NFSDEV_T)0;
1258 			nap->na_mtime.tv_sec = 0;
1259 			nap->na_mtime.tv_nsec = 0;
1260 			nap->na_btime.tv_sec = -1;
1261 			nap->na_btime.tv_nsec = 0;
1262 			nap->na_gen = 0;
1263 			nap->na_flags = 0;
1264 			nap->na_blocksize = NFS_FABLKSIZE;
1265 		}
1266 		if (sbp != NULL) {
1267 			sbp->f_bsize = NFS_FABLKSIZE;
1268 			sbp->f_blocks = 0;
1269 			sbp->f_bfree = 0;
1270 			sbp->f_bavail = 0;
1271 			sbp->f_files = 0;
1272 			sbp->f_ffree = 0;
1273 		}
1274 		if (fsp != NULL) {
1275 			fsp->fs_rtmax = 8192;
1276 			fsp->fs_rtpref = 8192;
1277 			fsp->fs_maxname = NFS_MAXNAMLEN;
1278 			fsp->fs_wtmax = 8192;
1279 			fsp->fs_wtpref = 8192;
1280 			fsp->fs_wtmult = NFS_FABLKSIZE;
1281 			fsp->fs_dtpref = 8192;
1282 			fsp->fs_maxfilesize = 0xffffffffffffffffull;
1283 			fsp->fs_timedelta.tv_sec = 0;
1284 			fsp->fs_timedelta.tv_nsec = 1;
1285 			fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1286 				NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1287 		}
1288 		if (pc != NULL) {
1289 			pc->pc_linkmax = NFS_LINK_MAX;
1290 			pc->pc_namemax = NAME_MAX;
1291 			pc->pc_notrunc = 0;
1292 			pc->pc_chownrestricted = 0;
1293 			pc->pc_caseinsensitive = 0;
1294 			pc->pc_casepreserving = 1;
1295 		}
1296 		if (sfp != NULL) {
1297 			sfp->sf_ffiles = UINT64_MAX;
1298 			sfp->sf_tfiles = UINT64_MAX;
1299 			sfp->sf_afiles = UINT64_MAX;
1300 			sfp->sf_fbytes = UINT64_MAX;
1301 			sfp->sf_tbytes = UINT64_MAX;
1302 			sfp->sf_abytes = UINT64_MAX;
1303 		}
1304 	}
1305 
1306 	/*
1307 	 * Loop around getting the attributes.
1308 	 */
1309 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1310 	attrsize = fxdr_unsigned(int, *tl);
1311 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1312 	    if (attrsum > attrsize) {
1313 		error = NFSERR_BADXDR;
1314 		goto nfsmout;
1315 	    }
1316 	    if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1317 		switch (bitpos) {
1318 		case NFSATTRBIT_SUPPORTEDATTRS:
1319 			retnotsup = 0;
1320 			if (compare || nap == NULL)
1321 			    error = nfsrv_getattrbits(nd, &retattrbits,
1322 				&cnt, &retnotsup);
1323 			else
1324 			    error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1325 				&cnt, &retnotsup);
1326 			if (error)
1327 			    goto nfsmout;
1328 			if (compare && !(*retcmpp)) {
1329 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1330 
1331 			   /* Some filesystem do not support NFSv4ACL   */
1332 			   if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1333 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1334 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1335 		   	   }
1336 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1337 			       || retnotsup)
1338 				*retcmpp = NFSERR_NOTSAME;
1339 			}
1340 			attrsum += cnt;
1341 			break;
1342 		case NFSATTRBIT_TYPE:
1343 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1344 			if (compare) {
1345 				if (!(*retcmpp)) {
1346 				    if (nap->na_type != nfsv34tov_type(*tl))
1347 					*retcmpp = NFSERR_NOTSAME;
1348 				}
1349 			} else if (nap != NULL) {
1350 				nap->na_type = nfsv34tov_type(*tl);
1351 			}
1352 			attrsum += NFSX_UNSIGNED;
1353 			break;
1354 		case NFSATTRBIT_FHEXPIRETYPE:
1355 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1356 			if (compare && !(*retcmpp)) {
1357 				if (fxdr_unsigned(int, *tl) !=
1358 					NFSV4FHTYPE_PERSISTENT)
1359 					*retcmpp = NFSERR_NOTSAME;
1360 			}
1361 			attrsum += NFSX_UNSIGNED;
1362 			break;
1363 		case NFSATTRBIT_CHANGE:
1364 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1365 			if (compare) {
1366 				if (!(*retcmpp)) {
1367 				    if (nap->na_filerev != fxdr_hyper(tl))
1368 					*retcmpp = NFSERR_NOTSAME;
1369 				}
1370 			} else if (nap != NULL) {
1371 				nap->na_filerev = fxdr_hyper(tl);
1372 			}
1373 			attrsum += NFSX_HYPER;
1374 			break;
1375 		case NFSATTRBIT_SIZE:
1376 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1377 			if (compare) {
1378 				if (!(*retcmpp)) {
1379 				    if (nap->na_size != fxdr_hyper(tl))
1380 					*retcmpp = NFSERR_NOTSAME;
1381 				}
1382 			} else if (nap != NULL) {
1383 				nap->na_size = fxdr_hyper(tl);
1384 			}
1385 			attrsum += NFSX_HYPER;
1386 			break;
1387 		case NFSATTRBIT_LINKSUPPORT:
1388 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1389 			if (compare) {
1390 				if (!(*retcmpp)) {
1391 				    if (fsp->fs_properties & NFSV3_FSFLINK) {
1392 					if (*tl == newnfs_false)
1393 						*retcmpp = NFSERR_NOTSAME;
1394 				    } else {
1395 					if (*tl == newnfs_true)
1396 						*retcmpp = NFSERR_NOTSAME;
1397 				    }
1398 				}
1399 			} else if (fsp != NULL) {
1400 				if (*tl == newnfs_true)
1401 					fsp->fs_properties |= NFSV3_FSFLINK;
1402 				else
1403 					fsp->fs_properties &= ~NFSV3_FSFLINK;
1404 			}
1405 			attrsum += NFSX_UNSIGNED;
1406 			break;
1407 		case NFSATTRBIT_SYMLINKSUPPORT:
1408 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1409 			if (compare) {
1410 				if (!(*retcmpp)) {
1411 				    if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1412 					if (*tl == newnfs_false)
1413 						*retcmpp = NFSERR_NOTSAME;
1414 				    } else {
1415 					if (*tl == newnfs_true)
1416 						*retcmpp = NFSERR_NOTSAME;
1417 				    }
1418 				}
1419 			} else if (fsp != NULL) {
1420 				if (*tl == newnfs_true)
1421 					fsp->fs_properties |= NFSV3_FSFSYMLINK;
1422 				else
1423 					fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1424 			}
1425 			attrsum += NFSX_UNSIGNED;
1426 			break;
1427 		case NFSATTRBIT_NAMEDATTR:
1428 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1429 			if (compare && !(*retcmpp)) {
1430 				if (*tl != newnfs_false)
1431 					*retcmpp = NFSERR_NOTSAME;
1432 			}
1433 			attrsum += NFSX_UNSIGNED;
1434 			break;
1435 		case NFSATTRBIT_FSID:
1436 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1437 			thyp = fxdr_hyper(tl);
1438 			tl += 2;
1439 			thyp2 = fxdr_hyper(tl);
1440 			if (compare) {
1441 			    if (*retcmpp == 0) {
1442 				if (thyp != (u_int64_t)
1443 				    vp->v_mount->mnt_stat.f_fsid.val[0] ||
1444 				    thyp2 != (u_int64_t)
1445 				    vp->v_mount->mnt_stat.f_fsid.val[1])
1446 					*retcmpp = NFSERR_NOTSAME;
1447 			    }
1448 			} else if (nap != NULL) {
1449 				nap->na_filesid[0] = thyp;
1450 				nap->na_filesid[1] = thyp2;
1451 			}
1452 			attrsum += (4 * NFSX_UNSIGNED);
1453 			break;
1454 		case NFSATTRBIT_UNIQUEHANDLES:
1455 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1456 			if (compare && !(*retcmpp)) {
1457 				if (*tl != newnfs_true)
1458 					*retcmpp = NFSERR_NOTSAME;
1459 			}
1460 			attrsum += NFSX_UNSIGNED;
1461 			break;
1462 		case NFSATTRBIT_LEASETIME:
1463 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1464 			if (compare) {
1465 				if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1466 				    !(*retcmpp))
1467 					*retcmpp = NFSERR_NOTSAME;
1468 			} else if (leasep != NULL) {
1469 				*leasep = fxdr_unsigned(u_int32_t, *tl);
1470 			}
1471 			attrsum += NFSX_UNSIGNED;
1472 			break;
1473 		case NFSATTRBIT_RDATTRERROR:
1474 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1475 			if (compare) {
1476 				 if (!(*retcmpp))
1477 					*retcmpp = NFSERR_INVAL;
1478 			} else if (rderrp != NULL) {
1479 				*rderrp = fxdr_unsigned(u_int32_t, *tl);
1480 			}
1481 			attrsum += NFSX_UNSIGNED;
1482 			break;
1483 		case NFSATTRBIT_ACL:
1484 			if (compare) {
1485 			  if (!(*retcmpp)) {
1486 			    if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1487 				NFSACL_T *naclp;
1488 
1489 				naclp = acl_alloc(M_WAITOK);
1490 				error = nfsrv_dissectacl(nd, naclp, false,
1491 				    &aceerr, &cnt, p);
1492 				if (error) {
1493 				    acl_free(naclp);
1494 				    goto nfsmout;
1495 				}
1496 				if (aceerr || aclp == NULL ||
1497 				    nfsrv_compareacl(aclp, naclp))
1498 				    *retcmpp = NFSERR_NOTSAME;
1499 				acl_free(naclp);
1500 			    } else {
1501 				error = nfsrv_dissectacl(nd, NULL, false,
1502 				    &aceerr, &cnt, p);
1503 				if (error)
1504 				    goto nfsmout;
1505 				*retcmpp = NFSERR_ATTRNOTSUPP;
1506 			    }
1507 			  }
1508 			} else {
1509 				if (vp != NULL && aclp != NULL)
1510 				    error = nfsrv_dissectacl(nd, aclp, false,
1511 					&aceerr, &cnt, p);
1512 				else
1513 				    error = nfsrv_dissectacl(nd, NULL, false,
1514 					&aceerr, &cnt, p);
1515 				if (error)
1516 				    goto nfsmout;
1517 			}
1518 
1519 			attrsum += cnt;
1520 			break;
1521 		case NFSATTRBIT_ACLSUPPORT:
1522 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1523 			if (compare && !(*retcmpp)) {
1524 				if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1525 					if (fxdr_unsigned(u_int32_t, *tl) !=
1526 					    NFSV4ACE_SUPTYPES)
1527 						*retcmpp = NFSERR_NOTSAME;
1528 				} else {
1529 					*retcmpp = NFSERR_ATTRNOTSUPP;
1530 				}
1531 			}
1532 			attrsum += NFSX_UNSIGNED;
1533 			break;
1534 		case NFSATTRBIT_ARCHIVE:
1535 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1536 			if (compare && !(*retcmpp))
1537 				*retcmpp = NFSERR_ATTRNOTSUPP;
1538 			attrsum += NFSX_UNSIGNED;
1539 			break;
1540 		case NFSATTRBIT_CANSETTIME:
1541 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1542 			if (compare) {
1543 				if (!(*retcmpp)) {
1544 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1545 					if (*tl == newnfs_false)
1546 						*retcmpp = NFSERR_NOTSAME;
1547 				    } else {
1548 					if (*tl == newnfs_true)
1549 						*retcmpp = NFSERR_NOTSAME;
1550 				    }
1551 				}
1552 			} else if (fsp != NULL) {
1553 				if (*tl == newnfs_true)
1554 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1555 				else
1556 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1557 			}
1558 			attrsum += NFSX_UNSIGNED;
1559 			break;
1560 		case NFSATTRBIT_CASEINSENSITIVE:
1561 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1562 			if (compare) {
1563 				if (!(*retcmpp)) {
1564 				    if (*tl != newnfs_false)
1565 					*retcmpp = NFSERR_NOTSAME;
1566 				}
1567 			} else if (pc != NULL) {
1568 				pc->pc_caseinsensitive =
1569 				    fxdr_unsigned(u_int32_t, *tl);
1570 			}
1571 			attrsum += NFSX_UNSIGNED;
1572 			break;
1573 		case NFSATTRBIT_CASEPRESERVING:
1574 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1575 			if (compare) {
1576 				if (!(*retcmpp)) {
1577 				    if (*tl != newnfs_true)
1578 					*retcmpp = NFSERR_NOTSAME;
1579 				}
1580 			} else if (pc != NULL) {
1581 				pc->pc_casepreserving =
1582 				    fxdr_unsigned(u_int32_t, *tl);
1583 			}
1584 			attrsum += NFSX_UNSIGNED;
1585 			break;
1586 		case NFSATTRBIT_CHOWNRESTRICTED:
1587 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1588 			if (compare) {
1589 				if (!(*retcmpp)) {
1590 				    if (*tl != newnfs_true)
1591 					*retcmpp = NFSERR_NOTSAME;
1592 				}
1593 			} else if (pc != NULL) {
1594 				pc->pc_chownrestricted =
1595 				    fxdr_unsigned(u_int32_t, *tl);
1596 			}
1597 			attrsum += NFSX_UNSIGNED;
1598 			break;
1599 		case NFSATTRBIT_FILEHANDLE:
1600 			error = nfsm_getfh(nd, &tnfhp);
1601 			if (error)
1602 				goto nfsmout;
1603 			tfhsize = tnfhp->nfh_len;
1604 			if (compare) {
1605 				if (!(*retcmpp) &&
1606 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1607 				     fhp, fhsize))
1608 					*retcmpp = NFSERR_NOTSAME;
1609 				free(tnfhp, M_NFSFH);
1610 			} else if (nfhpp != NULL) {
1611 				*nfhpp = tnfhp;
1612 			} else {
1613 				free(tnfhp, M_NFSFH);
1614 			}
1615 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1616 			break;
1617 		case NFSATTRBIT_FILEID:
1618 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1619 			thyp = fxdr_hyper(tl);
1620 			if (compare) {
1621 				if (!(*retcmpp)) {
1622 					if (nap->na_fileid != thyp)
1623 						*retcmpp = NFSERR_NOTSAME;
1624 				}
1625 			} else if (nap != NULL)
1626 				nap->na_fileid = thyp;
1627 			attrsum += NFSX_HYPER;
1628 			break;
1629 		case NFSATTRBIT_FILESAVAIL:
1630 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1631 			if (compare) {
1632 				uquad = nfsv4_filesavail(sbp, vp->v_mount);
1633 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1634 					*retcmpp = NFSERR_NOTSAME;
1635 			} else if (sfp != NULL) {
1636 				sfp->sf_afiles = fxdr_hyper(tl);
1637 			}
1638 			attrsum += NFSX_HYPER;
1639 			break;
1640 		case NFSATTRBIT_FILESFREE:
1641 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1642 			if (compare) {
1643 				uquad = (uint64_t)sbp->f_ffree;
1644 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1645 					*retcmpp = NFSERR_NOTSAME;
1646 			} else if (sfp != NULL) {
1647 				sfp->sf_ffiles = fxdr_hyper(tl);
1648 			}
1649 			attrsum += NFSX_HYPER;
1650 			break;
1651 		case NFSATTRBIT_FILESTOTAL:
1652 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1653 			if (compare) {
1654 				uquad = sbp->f_files;
1655 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1656 					*retcmpp = NFSERR_NOTSAME;
1657 			} else if (sfp != NULL) {
1658 				sfp->sf_tfiles = fxdr_hyper(tl);
1659 			}
1660 			attrsum += NFSX_HYPER;
1661 			break;
1662 		case NFSATTRBIT_FSLOCATIONS:
1663 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1664 			if (error)
1665 				goto nfsmout;
1666 			attrsum += l;
1667 			if (compare && !(*retcmpp)) {
1668 				refp = nfsv4root_getreferral(vp, NULL, 0);
1669 				if (refp != NULL) {
1670 					if (cp == NULL || cp2 == NULL ||
1671 					    strcmp(cp, "/") ||
1672 					    strcmp(cp2, refp->nfr_srvlist))
1673 						*retcmpp = NFSERR_NOTSAME;
1674 				} else if (m == 0) {
1675 					*retcmpp = NFSERR_NOTSAME;
1676 				}
1677 			}
1678 			if (cp != NULL)
1679 				free(cp, M_NFSSTRING);
1680 			if (cp2 != NULL)
1681 				free(cp2, M_NFSSTRING);
1682 			break;
1683 		case NFSATTRBIT_HIDDEN:
1684 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1685 			if (compare && !(*retcmpp))
1686 				*retcmpp = NFSERR_ATTRNOTSUPP;
1687 			attrsum += NFSX_UNSIGNED;
1688 			break;
1689 		case NFSATTRBIT_HOMOGENEOUS:
1690 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1691 			if (compare) {
1692 				if (!(*retcmpp)) {
1693 				    if (fsp->fs_properties &
1694 					NFSV3_FSFHOMOGENEOUS) {
1695 					if (*tl == newnfs_false)
1696 						*retcmpp = NFSERR_NOTSAME;
1697 				    } else {
1698 					if (*tl == newnfs_true)
1699 						*retcmpp = NFSERR_NOTSAME;
1700 				    }
1701 				}
1702 			} else if (fsp != NULL) {
1703 				if (*tl == newnfs_true)
1704 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1705 				else
1706 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1707 			}
1708 			attrsum += NFSX_UNSIGNED;
1709 			break;
1710 		case NFSATTRBIT_MAXFILESIZE:
1711 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1712 			tnfsquad.qval = fxdr_hyper(tl);
1713 			if (compare) {
1714 				if (!(*retcmpp)) {
1715 					tquad = NFSRV_MAXFILESIZE;
1716 					if (tquad != tnfsquad.qval)
1717 						*retcmpp = NFSERR_NOTSAME;
1718 				}
1719 			} else if (fsp != NULL) {
1720 				fsp->fs_maxfilesize = tnfsquad.qval;
1721 			}
1722 			attrsum += NFSX_HYPER;
1723 			break;
1724 		case NFSATTRBIT_MAXLINK:
1725 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1726 			if (compare) {
1727 				if (!(*retcmpp)) {
1728 				    if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1729 					*retcmpp = NFSERR_NOTSAME;
1730 				}
1731 			} else if (pc != NULL) {
1732 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1733 			}
1734 			attrsum += NFSX_UNSIGNED;
1735 			break;
1736 		case NFSATTRBIT_MAXNAME:
1737 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1738 			if (compare) {
1739 				if (!(*retcmpp)) {
1740 				    if (fsp->fs_maxname !=
1741 					fxdr_unsigned(u_int32_t, *tl))
1742 						*retcmpp = NFSERR_NOTSAME;
1743 				}
1744 			} else {
1745 				tuint = fxdr_unsigned(u_int32_t, *tl);
1746 				/*
1747 				 * Some Linux NFSv4 servers report this
1748 				 * as 0 or 4billion, so I'll set it to
1749 				 * NFS_MAXNAMLEN. If a server actually creates
1750 				 * a name longer than NFS_MAXNAMLEN, it will
1751 				 * get an error back.
1752 				 */
1753 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1754 					tuint = NFS_MAXNAMLEN;
1755 				if (fsp != NULL)
1756 					fsp->fs_maxname = tuint;
1757 				if (pc != NULL)
1758 					pc->pc_namemax = tuint;
1759 			}
1760 			attrsum += NFSX_UNSIGNED;
1761 			break;
1762 		case NFSATTRBIT_MAXREAD:
1763 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1764 			if (compare) {
1765 				if (!(*retcmpp)) {
1766 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1767 					*(tl + 1)) || *tl != 0)
1768 					*retcmpp = NFSERR_NOTSAME;
1769 				}
1770 			} else if (fsp != NULL) {
1771 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1772 				fsp->fs_rtpref = fsp->fs_rtmax;
1773 				fsp->fs_dtpref = fsp->fs_rtpref;
1774 			}
1775 			attrsum += NFSX_HYPER;
1776 			break;
1777 		case NFSATTRBIT_MAXWRITE:
1778 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1779 			if (compare) {
1780 				if (!(*retcmpp)) {
1781 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1782 					*(tl + 1)) || *tl != 0)
1783 					*retcmpp = NFSERR_NOTSAME;
1784 				}
1785 			} else if (fsp != NULL) {
1786 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1787 				fsp->fs_wtpref = fsp->fs_wtmax;
1788 			}
1789 			attrsum += NFSX_HYPER;
1790 			break;
1791 		case NFSATTRBIT_MIMETYPE:
1792 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1793 			i = fxdr_unsigned(int, *tl);
1794 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1795 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1796 			if (error)
1797 				goto nfsmout;
1798 			if (compare && !(*retcmpp))
1799 				*retcmpp = NFSERR_ATTRNOTSUPP;
1800 			break;
1801 		case NFSATTRBIT_MODE:
1802 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1803 			if (compare) {
1804 				if (!(*retcmpp)) {
1805 				    if (nap->na_mode != nfstov_mode(*tl))
1806 					*retcmpp = NFSERR_NOTSAME;
1807 				}
1808 			} else if (nap != NULL) {
1809 				nap->na_mode = nfstov_mode(*tl);
1810 			}
1811 			attrsum += NFSX_UNSIGNED;
1812 			break;
1813 		case NFSATTRBIT_NOTRUNC:
1814 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1815 			if (compare) {
1816 				if (!(*retcmpp)) {
1817 				    if (*tl != newnfs_true)
1818 					*retcmpp = NFSERR_NOTSAME;
1819 				}
1820 			} else if (pc != NULL) {
1821 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1822 			}
1823 			attrsum += NFSX_UNSIGNED;
1824 			break;
1825 		case NFSATTRBIT_NUMLINKS:
1826 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1827 			tuint = fxdr_unsigned(u_int32_t, *tl);
1828 			if (compare) {
1829 			    if (!(*retcmpp)) {
1830 				if ((u_int32_t)nap->na_nlink != tuint)
1831 					*retcmpp = NFSERR_NOTSAME;
1832 			    }
1833 			} else if (nap != NULL) {
1834 				nap->na_nlink = tuint;
1835 			}
1836 			attrsum += NFSX_UNSIGNED;
1837 			break;
1838 		case NFSATTRBIT_OWNER:
1839 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1840 			j = fxdr_unsigned(int, *tl);
1841 			if (j < 0) {
1842 				error = NFSERR_BADXDR;
1843 				goto nfsmout;
1844 			}
1845 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1846 			if (j > NFSV4_SMALLSTR)
1847 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1848 			else
1849 				cp = namestr;
1850 			error = nfsrv_mtostr(nd, cp, j);
1851 			if (error) {
1852 				if (j > NFSV4_SMALLSTR)
1853 					free(cp, M_NFSSTRING);
1854 				goto nfsmout;
1855 			}
1856 			if (compare) {
1857 			    if (!(*retcmpp)) {
1858 				if (nfsv4_strtouid(nd, cp, j, &uid) ||
1859 				    nap->na_uid != uid)
1860 				    *retcmpp = NFSERR_NOTSAME;
1861 			    }
1862 			} else if (nap != NULL) {
1863 				if (nfsv4_strtouid(nd, cp, j, &uid))
1864 					nap->na_uid = nfsrv_defaultuid;
1865 				else
1866 					nap->na_uid = uid;
1867 			}
1868 			if (j > NFSV4_SMALLSTR)
1869 				free(cp, M_NFSSTRING);
1870 			break;
1871 		case NFSATTRBIT_OWNERGROUP:
1872 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1873 			j = fxdr_unsigned(int, *tl);
1874 			if (j < 0) {
1875 				error =  NFSERR_BADXDR;
1876 				goto nfsmout;
1877 			}
1878 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1879 			if (j > NFSV4_SMALLSTR)
1880 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1881 			else
1882 				cp = namestr;
1883 			error = nfsrv_mtostr(nd, cp, j);
1884 			if (error) {
1885 				if (j > NFSV4_SMALLSTR)
1886 					free(cp, M_NFSSTRING);
1887 				goto nfsmout;
1888 			}
1889 			if (compare) {
1890 			    if (!(*retcmpp)) {
1891 				if (nfsv4_strtogid(nd, cp, j, &gid) ||
1892 				    nap->na_gid != gid)
1893 				    *retcmpp = NFSERR_NOTSAME;
1894 			    }
1895 			} else if (nap != NULL) {
1896 				if (nfsv4_strtogid(nd, cp, j, &gid))
1897 					nap->na_gid = nfsrv_defaultgid;
1898 				else
1899 					nap->na_gid = gid;
1900 			}
1901 			if (j > NFSV4_SMALLSTR)
1902 				free(cp, M_NFSSTRING);
1903 			break;
1904 		case NFSATTRBIT_QUOTAHARD:
1905 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1906 			if (sbp != NULL) {
1907 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1908 				freenum = sbp->f_bfree;
1909 			    else
1910 				freenum = sbp->f_bavail;
1911 #ifdef QUOTA
1912 			    /*
1913 			     * ufs_quotactl() insists that the uid argument
1914 			     * equal p_ruid for non-root quota access, so
1915 			     * we'll just make sure that's the case.
1916 			     */
1917 			    savuid = p->p_cred->p_ruid;
1918 			    p->p_cred->p_ruid = cred->cr_uid;
1919 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1920 				USRQUOTA), cred->cr_uid, &dqb))
1921 				freenum = min(dqb.dqb_bhardlimit, freenum);
1922 			    p->p_cred->p_ruid = savuid;
1923 #endif	/* QUOTA */
1924 			    uquad = (u_int64_t)freenum;
1925 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1926 			}
1927 			if (compare && !(*retcmpp)) {
1928 				if (uquad != fxdr_hyper(tl))
1929 					*retcmpp = NFSERR_NOTSAME;
1930 			}
1931 			attrsum += NFSX_HYPER;
1932 			break;
1933 		case NFSATTRBIT_QUOTASOFT:
1934 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1935 			if (sbp != NULL) {
1936 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1937 				freenum = sbp->f_bfree;
1938 			    else
1939 				freenum = sbp->f_bavail;
1940 #ifdef QUOTA
1941 			    /*
1942 			     * ufs_quotactl() insists that the uid argument
1943 			     * equal p_ruid for non-root quota access, so
1944 			     * we'll just make sure that's the case.
1945 			     */
1946 			    savuid = p->p_cred->p_ruid;
1947 			    p->p_cred->p_ruid = cred->cr_uid;
1948 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1949 				USRQUOTA), cred->cr_uid, &dqb))
1950 				freenum = min(dqb.dqb_bsoftlimit, freenum);
1951 			    p->p_cred->p_ruid = savuid;
1952 #endif	/* QUOTA */
1953 			    uquad = (u_int64_t)freenum;
1954 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1955 			}
1956 			if (compare && !(*retcmpp)) {
1957 				if (uquad != fxdr_hyper(tl))
1958 					*retcmpp = NFSERR_NOTSAME;
1959 			}
1960 			attrsum += NFSX_HYPER;
1961 			break;
1962 		case NFSATTRBIT_QUOTAUSED:
1963 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1964 			if (sbp != NULL) {
1965 			    freenum = 0;
1966 #ifdef QUOTA
1967 			    /*
1968 			     * ufs_quotactl() insists that the uid argument
1969 			     * equal p_ruid for non-root quota access, so
1970 			     * we'll just make sure that's the case.
1971 			     */
1972 			    savuid = p->p_cred->p_ruid;
1973 			    p->p_cred->p_ruid = cred->cr_uid;
1974 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1975 				USRQUOTA), cred->cr_uid, &dqb))
1976 				freenum = dqb.dqb_curblocks;
1977 			    p->p_cred->p_ruid = savuid;
1978 #endif	/* QUOTA */
1979 			    uquad = (u_int64_t)freenum;
1980 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1981 			}
1982 			if (compare && !(*retcmpp)) {
1983 				if (uquad != fxdr_hyper(tl))
1984 					*retcmpp = NFSERR_NOTSAME;
1985 			}
1986 			attrsum += NFSX_HYPER;
1987 			break;
1988 		case NFSATTRBIT_RAWDEV:
1989 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1990 			j = fxdr_unsigned(int, *tl++);
1991 			k = fxdr_unsigned(int, *tl);
1992 			if (compare) {
1993 			    if (!(*retcmpp)) {
1994 				if (nap->na_rdev != NFSMAKEDEV(j, k))
1995 					*retcmpp = NFSERR_NOTSAME;
1996 			    }
1997 			} else if (nap != NULL) {
1998 				nap->na_rdev = NFSMAKEDEV(j, k);
1999 			}
2000 			attrsum += NFSX_V4SPECDATA;
2001 			break;
2002 		case NFSATTRBIT_SPACEAVAIL:
2003 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2004 			if (compare) {
2005 				if (priv_check_cred(cred,
2006 				    PRIV_VFS_BLOCKRESERVE))
2007 					uquad = sbp->f_bfree;
2008 				else
2009 					uquad = (uint64_t)sbp->f_bavail;
2010 				uquad *= sbp->f_bsize;
2011 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2012 					*retcmpp = NFSERR_NOTSAME;
2013 			} else if (sfp != NULL) {
2014 				sfp->sf_abytes = fxdr_hyper(tl);
2015 			}
2016 			attrsum += NFSX_HYPER;
2017 			break;
2018 		case NFSATTRBIT_SPACEFREE:
2019 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2020 			if (compare) {
2021 				uquad = sbp->f_bfree;
2022 				uquad *= sbp->f_bsize;
2023 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2024 					*retcmpp = NFSERR_NOTSAME;
2025 			} else if (sfp != NULL) {
2026 				sfp->sf_fbytes = fxdr_hyper(tl);
2027 			}
2028 			attrsum += NFSX_HYPER;
2029 			break;
2030 		case NFSATTRBIT_SPACETOTAL:
2031 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2032 			if (compare) {
2033 				uquad = sbp->f_blocks;
2034 				uquad *= sbp->f_bsize;
2035 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2036 					*retcmpp = NFSERR_NOTSAME;
2037 			} else if (sfp != NULL) {
2038 				sfp->sf_tbytes = fxdr_hyper(tl);
2039 			}
2040 			attrsum += NFSX_HYPER;
2041 			break;
2042 		case NFSATTRBIT_SPACEUSED:
2043 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2044 			thyp = fxdr_hyper(tl);
2045 			if (compare) {
2046 			    if (!(*retcmpp)) {
2047 				if ((u_int64_t)nap->na_bytes != thyp)
2048 					*retcmpp = NFSERR_NOTSAME;
2049 			    }
2050 			} else if (nap != NULL) {
2051 				nap->na_bytes = thyp;
2052 			}
2053 			attrsum += NFSX_HYPER;
2054 			break;
2055 		case NFSATTRBIT_SYSTEM:
2056 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2057 			if (compare && !(*retcmpp))
2058 				*retcmpp = NFSERR_ATTRNOTSUPP;
2059 			attrsum += NFSX_UNSIGNED;
2060 			break;
2061 		case NFSATTRBIT_TIMEACCESS:
2062 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2063 			fxdr_nfsv4time(tl, &temptime);
2064 			if (compare) {
2065 			    if (!(*retcmpp)) {
2066 				if (!NFS_CMPTIME(temptime, nap->na_atime))
2067 					*retcmpp = NFSERR_NOTSAME;
2068 			    }
2069 			} else if (nap != NULL) {
2070 				nap->na_atime = temptime;
2071 			}
2072 			attrsum += NFSX_V4TIME;
2073 			break;
2074 		case NFSATTRBIT_TIMEACCESSSET:
2075 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2076 			attrsum += NFSX_UNSIGNED;
2077 			i = fxdr_unsigned(int, *tl);
2078 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2079 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2080 				attrsum += NFSX_V4TIME;
2081 			}
2082 			if (compare && !(*retcmpp))
2083 				*retcmpp = NFSERR_INVAL;
2084 			break;
2085 		case NFSATTRBIT_TIMEBACKUP:
2086 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2087 			if (compare && !(*retcmpp))
2088 				*retcmpp = NFSERR_ATTRNOTSUPP;
2089 			attrsum += NFSX_V4TIME;
2090 			break;
2091 		case NFSATTRBIT_TIMECREATE:
2092 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2093 			fxdr_nfsv4time(tl, &temptime);
2094 			if (compare) {
2095 			    if (!(*retcmpp)) {
2096 				if (!NFS_CMPTIME(temptime, nap->na_btime))
2097 					*retcmpp = NFSERR_NOTSAME;
2098 			    }
2099 			} else if (nap != NULL) {
2100 				nap->na_btime = temptime;
2101 			}
2102 			attrsum += NFSX_V4TIME;
2103 			break;
2104 		case NFSATTRBIT_TIMEDELTA:
2105 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2106 			if (fsp != NULL) {
2107 			    if (compare) {
2108 				if (!(*retcmpp)) {
2109 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2110 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2111 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2112 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
2113 					 1000000000) ||
2114 					*tl != 0)
2115 					    *retcmpp = NFSERR_NOTSAME;
2116 				}
2117 			    } else {
2118 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2119 			    }
2120 			}
2121 			attrsum += NFSX_V4TIME;
2122 			break;
2123 		case NFSATTRBIT_TIMEMETADATA:
2124 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2125 			fxdr_nfsv4time(tl, &temptime);
2126 			if (compare) {
2127 			    if (!(*retcmpp)) {
2128 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
2129 					*retcmpp = NFSERR_NOTSAME;
2130 			    }
2131 			} else if (nap != NULL) {
2132 				nap->na_ctime = temptime;
2133 			}
2134 			attrsum += NFSX_V4TIME;
2135 			break;
2136 		case NFSATTRBIT_TIMEMODIFY:
2137 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2138 			fxdr_nfsv4time(tl, &temptime);
2139 			if (compare) {
2140 			    if (!(*retcmpp)) {
2141 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
2142 					*retcmpp = NFSERR_NOTSAME;
2143 			    }
2144 			} else if (nap != NULL) {
2145 				nap->na_mtime = temptime;
2146 			}
2147 			attrsum += NFSX_V4TIME;
2148 			break;
2149 		case NFSATTRBIT_TIMEMODIFYSET:
2150 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2151 			attrsum += NFSX_UNSIGNED;
2152 			i = fxdr_unsigned(int, *tl);
2153 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2154 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2155 				attrsum += NFSX_V4TIME;
2156 			}
2157 			if (compare && !(*retcmpp))
2158 				*retcmpp = NFSERR_INVAL;
2159 			break;
2160 		case NFSATTRBIT_MOUNTEDONFILEID:
2161 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2162 			thyp = fxdr_hyper(tl);
2163 			if (compare) {
2164 				if (!(*retcmpp)) {
2165 					if (!vp || !nfsrv_atroot(vp, &thyp2))
2166 						thyp2 = nap->na_fileid;
2167 					if (thyp2 != thyp)
2168 						*retcmpp = NFSERR_NOTSAME;
2169 				}
2170 			} else if (nap != NULL)
2171 				nap->na_mntonfileno = thyp;
2172 			attrsum += NFSX_HYPER;
2173 			break;
2174 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2175 			retnotsup = 0;
2176 			error = nfsrv_getattrbits(nd, &retattrbits,
2177 			    &cnt, &retnotsup);
2178 			if (error)
2179 			    goto nfsmout;
2180 			if (compare && !(*retcmpp)) {
2181 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2182 			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2183 			   NFSCLRBIT_ATTRBIT(&checkattrbits,
2184 				NFSATTRBIT_TIMEACCESSSET);
2185 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2186 			       || retnotsup)
2187 				*retcmpp = NFSERR_NOTSAME;
2188 			}
2189 			attrsum += cnt;
2190 			break;
2191 		case NFSATTRBIT_FSLAYOUTTYPE:
2192 		case NFSATTRBIT_LAYOUTTYPE:
2193 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2194 			attrsum += NFSX_UNSIGNED;
2195 			i = fxdr_unsigned(int, *tl);
2196 			/*
2197 			 * The RFCs do not define an upper limit for the
2198 			 * number of layout types, but 32 should be more
2199 			 * than enough.
2200 			 */
2201 			if (i < 0 || i > 32) {
2202 				error = NFSERR_BADXDR;
2203 				goto nfsmout;
2204 			}
2205 			if (i > 0) {
2206 				NFSM_DISSECT(tl, u_int32_t *, i *
2207 				    NFSX_UNSIGNED);
2208 				attrsum += i * NFSX_UNSIGNED;
2209 				j = fxdr_unsigned(int, *tl);
2210 				if (i == 1 && compare && !(*retcmpp) &&
2211 				    (((nfsrv_doflexfile != 0 ||
2212 				       nfsrv_maxpnfsmirror > 1) &&
2213 				      j != NFSLAYOUT_FLEXFILE) ||
2214 				    (nfsrv_doflexfile == 0 &&
2215 				     j != NFSLAYOUT_NFSV4_1_FILES)))
2216 					*retcmpp = NFSERR_NOTSAME;
2217 			}
2218 			if (nfsrv_devidcnt == 0) {
2219 				if (compare && !(*retcmpp) && i > 0)
2220 					*retcmpp = NFSERR_NOTSAME;
2221 			} else {
2222 				if (compare && !(*retcmpp) && i != 1)
2223 					*retcmpp = NFSERR_NOTSAME;
2224 			}
2225 			break;
2226 		case NFSATTRBIT_LAYOUTALIGNMENT:
2227 		case NFSATTRBIT_LAYOUTBLKSIZE:
2228 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2229 			attrsum += NFSX_UNSIGNED;
2230 			i = fxdr_unsigned(int, *tl);
2231 			if (compare && !(*retcmpp) && i != nfs_srvmaxio)
2232 				*retcmpp = NFSERR_NOTSAME;
2233 			break;
2234 		default:
2235 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2236 				bitpos);
2237 			if (compare && !(*retcmpp))
2238 				*retcmpp = NFSERR_ATTRNOTSUPP;
2239 			/*
2240 			 * and get out of the loop, since we can't parse
2241 			 * the unknown attrbute data.
2242 			 */
2243 			bitpos = NFSATTRBIT_MAX;
2244 			break;
2245 		}
2246 	}
2247 
2248 	/*
2249 	 * some clients pad the attrlist, so we need to skip over the
2250 	 * padding.
2251 	 */
2252 	if (attrsum > attrsize) {
2253 		error = NFSERR_BADXDR;
2254 	} else {
2255 		attrsize = NFSM_RNDUP(attrsize);
2256 		if (attrsum < attrsize)
2257 			error = nfsm_advance(nd, attrsize - attrsum, -1);
2258 	}
2259 nfsmout:
2260 	NFSEXITCODE2(error, nd);
2261 	return (error);
2262 }
2263 
2264 /*
2265  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2266  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2267  * The first argument is a pointer to an nfsv4lock structure.
2268  * The second argument is 1 iff a blocking lock is wanted.
2269  * If this argument is 0, the call waits until no thread either wants nor
2270  * holds an exclusive lock.
2271  * It returns 1 if the lock was acquired, 0 otherwise.
2272  * If several processes call this function concurrently wanting the exclusive
2273  * lock, one will get the lock and the rest will return without getting the
2274  * lock. (If the caller must have the lock, it simply calls this function in a
2275  *  loop until the function returns 1 to indicate the lock was acquired.)
2276  * Any usecnt must be decremented by calling nfsv4_relref() before
2277  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2278  * be called in a loop.
2279  * The isleptp argument is set to indicate if the call slept, iff not NULL
2280  * and the mp argument indicates to check for a forced dismount, iff not
2281  * NULL.
2282  */
2283 int
2284 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2285     struct mtx *mutex, struct mount *mp)
2286 {
2287 
2288 	if (isleptp)
2289 		*isleptp = 0;
2290 	/*
2291 	 * If a lock is wanted, loop around until the lock is acquired by
2292 	 * someone and then released. If I want the lock, try to acquire it.
2293 	 * For a lock to be issued, no lock must be in force and the usecnt
2294 	 * must be zero.
2295 	 */
2296 	if (iwantlock) {
2297 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2298 		lp->nfslock_usecnt == 0) {
2299 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2300 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
2301 		return (1);
2302 	    }
2303 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2304 	}
2305 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2306 		if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2307 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2308 			return (0);
2309 		}
2310 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2311 		if (isleptp)
2312 			*isleptp = 1;
2313 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
2314 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2315 		    lp->nfslock_usecnt == 0) {
2316 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2317 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
2318 			return (1);
2319 		}
2320 	}
2321 	return (0);
2322 }
2323 
2324 /*
2325  * Release the lock acquired by nfsv4_lock().
2326  * The second argument is set to 1 to indicate the nfslock_usecnt should be
2327  * incremented, as well.
2328  */
2329 void
2330 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2331 {
2332 
2333 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2334 	if (incref)
2335 		lp->nfslock_usecnt++;
2336 	nfsv4_wanted(lp);
2337 }
2338 
2339 /*
2340  * Release a reference cnt.
2341  */
2342 void
2343 nfsv4_relref(struct nfsv4lock *lp)
2344 {
2345 
2346 	if (lp->nfslock_usecnt <= 0)
2347 		panic("nfsv4root ref cnt");
2348 	lp->nfslock_usecnt--;
2349 	if (lp->nfslock_usecnt == 0)
2350 		nfsv4_wanted(lp);
2351 }
2352 
2353 /*
2354  * Get a reference cnt.
2355  * This function will wait for any exclusive lock to be released, but will
2356  * not wait for threads that want the exclusive lock. If priority needs
2357  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2358  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2359  * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2360  * return without getting a refcnt for that case.
2361  */
2362 void
2363 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
2364     struct mount *mp)
2365 {
2366 
2367 	if (isleptp)
2368 		*isleptp = 0;
2369 
2370 	/*
2371 	 * Wait for a lock held.
2372 	 */
2373 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2374 		if (mp != NULL && NFSCL_FORCEDISM(mp))
2375 			return;
2376 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2377 		if (isleptp)
2378 			*isleptp = 1;
2379 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
2380 	}
2381 	if (mp != NULL && NFSCL_FORCEDISM(mp))
2382 		return;
2383 
2384 	lp->nfslock_usecnt++;
2385 }
2386 
2387 /*
2388  * Get a reference as above, but return failure instead of sleeping if
2389  * an exclusive lock is held.
2390  */
2391 int
2392 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2393 {
2394 
2395 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2396 		return (0);
2397 
2398 	lp->nfslock_usecnt++;
2399 	return (1);
2400 }
2401 
2402 /*
2403  * Test for a lock. Return 1 if locked, 0 otherwise.
2404  */
2405 int
2406 nfsv4_testlock(struct nfsv4lock *lp)
2407 {
2408 
2409 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2410 	    lp->nfslock_usecnt == 0)
2411 		return (0);
2412 	return (1);
2413 }
2414 
2415 /*
2416  * Wake up anyone sleeping, waiting for this lock.
2417  */
2418 static void
2419 nfsv4_wanted(struct nfsv4lock *lp)
2420 {
2421 
2422 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2423 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2424 		wakeup((caddr_t)&lp->nfslock_lock);
2425 	}
2426 }
2427 
2428 /*
2429  * Copy a string from an mbuf list into a character array.
2430  * Return EBADRPC if there is an mbuf error,
2431  * 0 otherwise.
2432  */
2433 int
2434 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2435 {
2436 	char *cp;
2437 	int xfer, len;
2438 	struct mbuf *mp;
2439 	int rem, error = 0;
2440 
2441 	mp = nd->nd_md;
2442 	cp = nd->nd_dpos;
2443 	len = mtod(mp, caddr_t) + mp->m_len - cp;
2444 	rem = NFSM_RNDUP(siz) - siz;
2445 	while (siz > 0) {
2446 		if (len > siz)
2447 			xfer = siz;
2448 		else
2449 			xfer = len;
2450 		NFSBCOPY(cp, str, xfer);
2451 		str += xfer;
2452 		siz -= xfer;
2453 		if (siz > 0) {
2454 			mp = mp->m_next;
2455 			if (mp == NULL) {
2456 				error = EBADRPC;
2457 				goto out;
2458 			}
2459 			cp = mtod(mp, caddr_t);
2460 			len = mp->m_len;
2461 		} else {
2462 			cp += xfer;
2463 			len -= xfer;
2464 		}
2465 	}
2466 	*str = '\0';
2467 	nd->nd_dpos = cp;
2468 	nd->nd_md = mp;
2469 	if (rem > 0) {
2470 		if (len < rem)
2471 			error = nfsm_advance(nd, rem, len);
2472 		else
2473 			nd->nd_dpos += rem;
2474 	}
2475 
2476 out:
2477 	NFSEXITCODE2(error, nd);
2478 	return (error);
2479 }
2480 
2481 /*
2482  * Fill in the attributes as marked by the bitmap (V4).
2483  */
2484 int
2485 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2486     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2487     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2488     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2489     struct statfs *pnfssf)
2490 {
2491 	int bitpos, retnum = 0;
2492 	u_int32_t *tl;
2493 	int siz, prefixnum, error;
2494 	u_char *cp, namestr[NFSV4_SMALLSTR];
2495 	nfsattrbit_t attrbits, retbits;
2496 	nfsattrbit_t *retbitp = &retbits;
2497 	u_int32_t freenum, *retnump;
2498 	u_int64_t uquad;
2499 	struct statfs *fs;
2500 	struct nfsfsinfo fsinf;
2501 	struct timespec temptime;
2502 	NFSACL_T *aclp, *naclp = NULL;
2503 	size_t atsiz;
2504 	bool xattrsupp;
2505 #ifdef QUOTA
2506 	struct dqblk dqb;
2507 	uid_t savuid;
2508 #endif
2509 
2510 	/*
2511 	 * First, set the bits that can be filled and get fsinfo.
2512 	 */
2513 	NFSSET_ATTRBIT(retbitp, attrbitp);
2514 	/*
2515 	 * If both p and cred are NULL, it is a client side setattr call.
2516 	 * If both p and cred are not NULL, it is a server side reply call.
2517 	 * If p is not NULL and cred is NULL, it is a client side callback
2518 	 * reply call.
2519 	 */
2520 	if (p == NULL && cred == NULL) {
2521 		NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2522 		aclp = saclp;
2523 	} else {
2524 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2525 		naclp = acl_alloc(M_WAITOK);
2526 		aclp = naclp;
2527 	}
2528 	nfsvno_getfs(&fsinf, isdgram);
2529 #ifndef APPLE
2530 	/*
2531 	 * Get the VFS_STATFS(), since some attributes need them.
2532 	 */
2533 	fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2534 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2535 		error = VFS_STATFS(mp, fs);
2536 		if (error != 0) {
2537 			if (reterr) {
2538 				nd->nd_repstat = NFSERR_ACCES;
2539 				free(fs, M_STATFS);
2540 				return (0);
2541 			}
2542 			NFSCLRSTATFS_ATTRBIT(retbitp);
2543 		}
2544 		/*
2545 		 * Since NFS handles these values as unsigned on the
2546 		 * wire, there is no way to represent negative values,
2547 		 * so set them to 0. Without this, they will appear
2548 		 * to be very large positive values for clients like
2549 		 * Solaris10.
2550 		 */
2551 		if (fs->f_bavail < 0)
2552 			fs->f_bavail = 0;
2553 		if (fs->f_ffree < 0)
2554 			fs->f_ffree = 0;
2555 	}
2556 #endif
2557 
2558 	/*
2559 	 * And the NFSv4 ACL...
2560 	 */
2561 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2562 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2563 		supports_nfsv4acls == 0))) {
2564 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2565 	}
2566 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2567 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2568 		    supports_nfsv4acls == 0)) {
2569 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2570 		} else if (naclp != NULL) {
2571 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2572 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2573 				if (error == 0)
2574 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2575 					    naclp, cred, p);
2576 				NFSVOPUNLOCK(vp);
2577 			} else
2578 				error = NFSERR_PERM;
2579 			if (error != 0) {
2580 				if (reterr) {
2581 					nd->nd_repstat = NFSERR_ACCES;
2582 					free(fs, M_STATFS);
2583 					return (0);
2584 				}
2585 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2586 			}
2587 		}
2588 	}
2589 
2590 	/* Check to see if Extended Attributes are supported. */
2591 	xattrsupp = false;
2592 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2593 		if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2594 			error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2595 			    "xxx", NULL, &atsiz, cred, p);
2596 			NFSVOPUNLOCK(vp);
2597 			if (error != EOPNOTSUPP)
2598 				xattrsupp = true;
2599 		}
2600 	}
2601 
2602 	/*
2603 	 * Put out the attribute bitmap for the ones being filled in
2604 	 * and get the field for the number of attributes returned.
2605 	 */
2606 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2607 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2608 	prefixnum += NFSX_UNSIGNED;
2609 
2610 	/*
2611 	 * Now, loop around filling in the attributes for each bit set.
2612 	 */
2613 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2614 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2615 		switch (bitpos) {
2616 		case NFSATTRBIT_SUPPORTEDATTRS:
2617 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2618 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2619 			    && supports_nfsv4acls == 0)) {
2620 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2621 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2622 			}
2623 			retnum += nfsrv_putattrbit(nd, &attrbits);
2624 			break;
2625 		case NFSATTRBIT_TYPE:
2626 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2627 			*tl = vtonfsv34_type(vap->va_type);
2628 			retnum += NFSX_UNSIGNED;
2629 			break;
2630 		case NFSATTRBIT_FHEXPIRETYPE:
2631 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2632 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2633 			retnum += NFSX_UNSIGNED;
2634 			break;
2635 		case NFSATTRBIT_CHANGE:
2636 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2637 			txdr_hyper(vap->va_filerev, tl);
2638 			retnum += NFSX_HYPER;
2639 			break;
2640 		case NFSATTRBIT_SIZE:
2641 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2642 			txdr_hyper(vap->va_size, tl);
2643 			retnum += NFSX_HYPER;
2644 			break;
2645 		case NFSATTRBIT_LINKSUPPORT:
2646 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2647 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2648 				*tl = newnfs_true;
2649 			else
2650 				*tl = newnfs_false;
2651 			retnum += NFSX_UNSIGNED;
2652 			break;
2653 		case NFSATTRBIT_SYMLINKSUPPORT:
2654 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2655 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2656 				*tl = newnfs_true;
2657 			else
2658 				*tl = newnfs_false;
2659 			retnum += NFSX_UNSIGNED;
2660 			break;
2661 		case NFSATTRBIT_NAMEDATTR:
2662 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2663 			*tl = newnfs_false;
2664 			retnum += NFSX_UNSIGNED;
2665 			break;
2666 		case NFSATTRBIT_FSID:
2667 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2668 			*tl++ = 0;
2669 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2670 			*tl++ = 0;
2671 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2672 			retnum += NFSX_V4FSID;
2673 			break;
2674 		case NFSATTRBIT_UNIQUEHANDLES:
2675 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2676 			*tl = newnfs_true;
2677 			retnum += NFSX_UNSIGNED;
2678 			break;
2679 		case NFSATTRBIT_LEASETIME:
2680 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2681 			*tl = txdr_unsigned(nfsrv_lease);
2682 			retnum += NFSX_UNSIGNED;
2683 			break;
2684 		case NFSATTRBIT_RDATTRERROR:
2685 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2686 			*tl = txdr_unsigned(rderror);
2687 			retnum += NFSX_UNSIGNED;
2688 			break;
2689 		/*
2690 		 * Recommended Attributes. (Only the supported ones.)
2691 		 */
2692 		case NFSATTRBIT_ACL:
2693 			retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp),
2694 			    false, 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