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