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