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