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