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