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