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