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