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