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