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