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