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