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