xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision 388420e61318280931eec684bcd0c2917e9cb9ba)
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 			(void)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 		(void)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 operation bits from an mbuf list.
1227  * Returns EBADRPC for a parsing error, 0 otherwise.
1228  */
1229 int
1230 nfsrv_getopbits(struct nfsrv_descript *nd, nfsopbit_t *opbitp, int *cntp)
1231 {
1232 	uint32_t *tl;
1233 	int cnt, i, outcnt;
1234 	int error = 0;
1235 
1236 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1237 	cnt = fxdr_unsigned(int, *tl);
1238 	if (cnt < 0) {
1239 		error = NFSERR_BADXDR;
1240 		goto nfsmout;
1241 	}
1242 	if (cnt > NFSOPBIT_MAXWORDS)
1243 		outcnt = NFSOPBIT_MAXWORDS;
1244 	else
1245 		outcnt = cnt;
1246 	NFSZERO_OPBIT(opbitp);
1247 	if (outcnt > 0) {
1248 		NFSM_DISSECT(tl, uint32_t *, outcnt * NFSX_UNSIGNED);
1249 		for (i = 0; i < outcnt; i++)
1250 			opbitp->bits[i] = fxdr_unsigned(uint32_t, *tl++);
1251 	}
1252 	for (i = 0; i < (cnt - outcnt); i++) {
1253 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1254 		if (*tl != 0) {
1255 			error = NFSERR_BADXDR;
1256 			goto nfsmout;
1257 		}
1258 	}
1259 	if (cntp != NULL)
1260 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1261 nfsmout:
1262 	NFSEXITCODE2(error, nd);
1263 	return (error);
1264 }
1265 
1266 /*
1267  * Get the attributes for V4.
1268  * If the compare flag is true, test for any attribute changes,
1269  * otherwise return the attribute values.
1270  * These attributes cover fields in "struct vattr", "struct statfs",
1271  * "struct nfsfsinfo", the file handle and the lease duration.
1272  * The value of retcmpp is set to 1 if all attributes are the same,
1273  * and 0 otherwise.
1274  * Returns EBADRPC if it can't be parsed, 0 otherwise.
1275  */
1276 int
1277 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1278     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1279     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1280     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1281     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1282 {
1283 	u_int32_t *tl;
1284 	int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1285 	int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1286 	u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1287 	nfsattrbit_t attrbits, retattrbits, checkattrbits;
1288 	struct nfsfh *tnfhp;
1289 	struct nfsreferral *refp;
1290 	u_quad_t tquad;
1291 	nfsquad_t tnfsquad;
1292 	struct timespec temptime;
1293 	uid_t uid;
1294 	gid_t gid;
1295 	u_int32_t freenum = 0, tuint;
1296 	u_int64_t uquad = 0, thyp, thyp2;
1297 #ifdef QUOTA
1298 	struct dqblk dqb;
1299 	uid_t savuid;
1300 #endif
1301 
1302 	CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1303 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
1304 	if (compare) {
1305 		retnotsup = 0;
1306 		error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1307 	} else {
1308 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1309 	}
1310 	if (error)
1311 		goto nfsmout;
1312 
1313 	if (compare) {
1314 		*retcmpp = retnotsup;
1315 	} else {
1316 		/*
1317 		 * Just set default values to some of the important ones.
1318 		 */
1319 		if (nap != NULL) {
1320 			nap->na_type = VREG;
1321 			nap->na_mode = 0;
1322 			nap->na_rdev = (NFSDEV_T)0;
1323 			nap->na_mtime.tv_sec = 0;
1324 			nap->na_mtime.tv_nsec = 0;
1325 			nap->na_btime.tv_sec = -1;
1326 			nap->na_btime.tv_nsec = 0;
1327 			nap->na_gen = 0;
1328 			nap->na_flags = 0;
1329 			nap->na_blocksize = NFS_FABLKSIZE;
1330 		}
1331 		if (sbp != NULL) {
1332 			sbp->f_bsize = NFS_FABLKSIZE;
1333 			sbp->f_blocks = 0;
1334 			sbp->f_bfree = 0;
1335 			sbp->f_bavail = 0;
1336 			sbp->f_files = 0;
1337 			sbp->f_ffree = 0;
1338 		}
1339 		if (fsp != NULL) {
1340 			fsp->fs_rtmax = 8192;
1341 			fsp->fs_rtpref = 8192;
1342 			fsp->fs_maxname = NFS_MAXNAMLEN;
1343 			fsp->fs_wtmax = 8192;
1344 			fsp->fs_wtpref = 8192;
1345 			fsp->fs_wtmult = NFS_FABLKSIZE;
1346 			fsp->fs_dtpref = 8192;
1347 			fsp->fs_maxfilesize = 0xffffffffffffffffull;
1348 			fsp->fs_timedelta.tv_sec = 0;
1349 			fsp->fs_timedelta.tv_nsec = 1;
1350 			fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1351 				NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1352 		}
1353 		if (pc != NULL) {
1354 			pc->pc_linkmax = NFS_LINK_MAX;
1355 			pc->pc_namemax = NAME_MAX;
1356 			pc->pc_notrunc = 0;
1357 			pc->pc_chownrestricted = 0;
1358 			pc->pc_caseinsensitive = 0;
1359 			pc->pc_casepreserving = 1;
1360 		}
1361 		if (sfp != NULL) {
1362 			sfp->sf_ffiles = UINT64_MAX;
1363 			sfp->sf_tfiles = UINT64_MAX;
1364 			sfp->sf_afiles = UINT64_MAX;
1365 			sfp->sf_fbytes = UINT64_MAX;
1366 			sfp->sf_tbytes = UINT64_MAX;
1367 			sfp->sf_abytes = UINT64_MAX;
1368 		}
1369 	}
1370 
1371 	/*
1372 	 * Loop around getting the attributes.
1373 	 */
1374 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1375 	attrsize = fxdr_unsigned(int, *tl);
1376 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1377 	    if (attrsum > attrsize) {
1378 		error = NFSERR_BADXDR;
1379 		goto nfsmout;
1380 	    }
1381 	    if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1382 		switch (bitpos) {
1383 		case NFSATTRBIT_SUPPORTEDATTRS:
1384 			retnotsup = 0;
1385 			if (compare || nap == NULL)
1386 			    error = nfsrv_getattrbits(nd, &retattrbits,
1387 				&cnt, &retnotsup);
1388 			else
1389 			    error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1390 				&cnt, &retnotsup);
1391 			if (error)
1392 			    goto nfsmout;
1393 			if (compare && !(*retcmpp)) {
1394 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1395 
1396 			   /* Some filesystem do not support NFSv4ACL   */
1397 			   if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1398 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1399 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1400 		   	   }
1401 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1402 			       || retnotsup)
1403 				*retcmpp = NFSERR_NOTSAME;
1404 			}
1405 			attrsum += cnt;
1406 			break;
1407 		case NFSATTRBIT_TYPE:
1408 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1409 			if (compare) {
1410 				if (!(*retcmpp)) {
1411 				    if (nap->na_type != nfsv34tov_type(*tl))
1412 					*retcmpp = NFSERR_NOTSAME;
1413 				}
1414 			} else if (nap != NULL) {
1415 				nap->na_type = nfsv34tov_type(*tl);
1416 			}
1417 			attrsum += NFSX_UNSIGNED;
1418 			break;
1419 		case NFSATTRBIT_FHEXPIRETYPE:
1420 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1421 			if (compare && !(*retcmpp)) {
1422 				if (fxdr_unsigned(int, *tl) !=
1423 					NFSV4FHTYPE_PERSISTENT)
1424 					*retcmpp = NFSERR_NOTSAME;
1425 			}
1426 			attrsum += NFSX_UNSIGNED;
1427 			break;
1428 		case NFSATTRBIT_CHANGE:
1429 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1430 			if (compare) {
1431 				if (!(*retcmpp)) {
1432 				    if (nap->na_filerev != fxdr_hyper(tl))
1433 					*retcmpp = NFSERR_NOTSAME;
1434 				}
1435 			} else if (nap != NULL) {
1436 				nap->na_filerev = fxdr_hyper(tl);
1437 			}
1438 			attrsum += NFSX_HYPER;
1439 			break;
1440 		case NFSATTRBIT_SIZE:
1441 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1442 			if (compare) {
1443 				if (!(*retcmpp)) {
1444 				    if (nap->na_size != fxdr_hyper(tl))
1445 					*retcmpp = NFSERR_NOTSAME;
1446 				}
1447 			} else if (nap != NULL) {
1448 				nap->na_size = fxdr_hyper(tl);
1449 			}
1450 			attrsum += NFSX_HYPER;
1451 			break;
1452 		case NFSATTRBIT_LINKSUPPORT:
1453 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1454 			if (compare) {
1455 				if (!(*retcmpp)) {
1456 				    if (fsp->fs_properties & NFSV3_FSFLINK) {
1457 					if (*tl == newnfs_false)
1458 						*retcmpp = NFSERR_NOTSAME;
1459 				    } else {
1460 					if (*tl == newnfs_true)
1461 						*retcmpp = NFSERR_NOTSAME;
1462 				    }
1463 				}
1464 			} else if (fsp != NULL) {
1465 				if (*tl == newnfs_true)
1466 					fsp->fs_properties |= NFSV3_FSFLINK;
1467 				else
1468 					fsp->fs_properties &= ~NFSV3_FSFLINK;
1469 			}
1470 			attrsum += NFSX_UNSIGNED;
1471 			break;
1472 		case NFSATTRBIT_SYMLINKSUPPORT:
1473 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1474 			if (compare) {
1475 				if (!(*retcmpp)) {
1476 				    if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1477 					if (*tl == newnfs_false)
1478 						*retcmpp = NFSERR_NOTSAME;
1479 				    } else {
1480 					if (*tl == newnfs_true)
1481 						*retcmpp = NFSERR_NOTSAME;
1482 				    }
1483 				}
1484 			} else if (fsp != NULL) {
1485 				if (*tl == newnfs_true)
1486 					fsp->fs_properties |= NFSV3_FSFSYMLINK;
1487 				else
1488 					fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1489 			}
1490 			attrsum += NFSX_UNSIGNED;
1491 			break;
1492 		case NFSATTRBIT_NAMEDATTR:
1493 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1494 			if (compare && !(*retcmpp)) {
1495 				if (*tl != newnfs_false)
1496 					*retcmpp = NFSERR_NOTSAME;
1497 			}
1498 			attrsum += NFSX_UNSIGNED;
1499 			break;
1500 		case NFSATTRBIT_FSID:
1501 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1502 			thyp = fxdr_hyper(tl);
1503 			tl += 2;
1504 			thyp2 = fxdr_hyper(tl);
1505 			if (compare) {
1506 			    if (*retcmpp == 0) {
1507 				if (thyp != (u_int64_t)
1508 				    vp->v_mount->mnt_stat.f_fsid.val[0] ||
1509 				    thyp2 != (u_int64_t)
1510 				    vp->v_mount->mnt_stat.f_fsid.val[1])
1511 					*retcmpp = NFSERR_NOTSAME;
1512 			    }
1513 			} else if (nap != NULL) {
1514 				nap->na_filesid[0] = thyp;
1515 				nap->na_filesid[1] = thyp2;
1516 			}
1517 			attrsum += (4 * NFSX_UNSIGNED);
1518 			break;
1519 		case NFSATTRBIT_UNIQUEHANDLES:
1520 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1521 			if (compare && !(*retcmpp)) {
1522 				if (*tl != newnfs_true)
1523 					*retcmpp = NFSERR_NOTSAME;
1524 			}
1525 			attrsum += NFSX_UNSIGNED;
1526 			break;
1527 		case NFSATTRBIT_LEASETIME:
1528 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1529 			if (compare) {
1530 				if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1531 				    !(*retcmpp))
1532 					*retcmpp = NFSERR_NOTSAME;
1533 			} else if (leasep != NULL) {
1534 				*leasep = fxdr_unsigned(u_int32_t, *tl);
1535 			}
1536 			attrsum += NFSX_UNSIGNED;
1537 			break;
1538 		case NFSATTRBIT_RDATTRERROR:
1539 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1540 			if (compare) {
1541 				 if (!(*retcmpp))
1542 					*retcmpp = NFSERR_INVAL;
1543 			} else if (rderrp != NULL) {
1544 				*rderrp = fxdr_unsigned(u_int32_t, *tl);
1545 			}
1546 			attrsum += NFSX_UNSIGNED;
1547 			break;
1548 		case NFSATTRBIT_ACL:
1549 			if (compare) {
1550 			  if (!(*retcmpp)) {
1551 			    if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1552 				NFSACL_T *naclp;
1553 
1554 				naclp = acl_alloc(M_WAITOK);
1555 				error = nfsrv_dissectacl(nd, naclp, true,
1556 				    &aceerr, &cnt, p);
1557 				if (error) {
1558 				    acl_free(naclp);
1559 				    goto nfsmout;
1560 				}
1561 				if (aceerr || aclp == NULL ||
1562 				    nfsrv_compareacl(aclp, naclp))
1563 				    *retcmpp = NFSERR_NOTSAME;
1564 				acl_free(naclp);
1565 			    } else {
1566 				error = nfsrv_dissectacl(nd, NULL, true,
1567 				    &aceerr, &cnt, p);
1568 				if (error)
1569 				    goto nfsmout;
1570 				*retcmpp = NFSERR_ATTRNOTSUPP;
1571 			    }
1572 			  }
1573 			} else {
1574 				if (vp != NULL && aclp != NULL)
1575 				    error = nfsrv_dissectacl(nd, aclp, false,
1576 					&aceerr, &cnt, p);
1577 				else
1578 				    error = nfsrv_dissectacl(nd, NULL, false,
1579 					&aceerr, &cnt, p);
1580 				if (error)
1581 				    goto nfsmout;
1582 			}
1583 
1584 			attrsum += cnt;
1585 			break;
1586 		case NFSATTRBIT_ACLSUPPORT:
1587 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1588 			if (compare && !(*retcmpp)) {
1589 				if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1590 					if (fxdr_unsigned(u_int32_t, *tl) !=
1591 					    NFSV4ACE_SUPTYPES)
1592 						*retcmpp = NFSERR_NOTSAME;
1593 				} else {
1594 					*retcmpp = NFSERR_ATTRNOTSUPP;
1595 				}
1596 			}
1597 			attrsum += NFSX_UNSIGNED;
1598 			break;
1599 		case NFSATTRBIT_ARCHIVE:
1600 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1601 			if (compare && !(*retcmpp))
1602 				*retcmpp = NFSERR_ATTRNOTSUPP;
1603 			attrsum += NFSX_UNSIGNED;
1604 			break;
1605 		case NFSATTRBIT_CANSETTIME:
1606 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1607 			if (compare) {
1608 				if (!(*retcmpp)) {
1609 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1610 					if (*tl == newnfs_false)
1611 						*retcmpp = NFSERR_NOTSAME;
1612 				    } else {
1613 					if (*tl == newnfs_true)
1614 						*retcmpp = NFSERR_NOTSAME;
1615 				    }
1616 				}
1617 			} else if (fsp != NULL) {
1618 				if (*tl == newnfs_true)
1619 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1620 				else
1621 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1622 			}
1623 			attrsum += NFSX_UNSIGNED;
1624 			break;
1625 		case NFSATTRBIT_CASEINSENSITIVE:
1626 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1627 			if (compare) {
1628 				if (!(*retcmpp)) {
1629 				    if (*tl != newnfs_false)
1630 					*retcmpp = NFSERR_NOTSAME;
1631 				}
1632 			} else if (pc != NULL) {
1633 				pc->pc_caseinsensitive =
1634 				    fxdr_unsigned(u_int32_t, *tl);
1635 			}
1636 			attrsum += NFSX_UNSIGNED;
1637 			break;
1638 		case NFSATTRBIT_CASEPRESERVING:
1639 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1640 			if (compare) {
1641 				if (!(*retcmpp)) {
1642 				    if (*tl != newnfs_true)
1643 					*retcmpp = NFSERR_NOTSAME;
1644 				}
1645 			} else if (pc != NULL) {
1646 				pc->pc_casepreserving =
1647 				    fxdr_unsigned(u_int32_t, *tl);
1648 			}
1649 			attrsum += NFSX_UNSIGNED;
1650 			break;
1651 		case NFSATTRBIT_CHOWNRESTRICTED:
1652 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1653 			if (compare) {
1654 				if (!(*retcmpp)) {
1655 				    if (*tl != newnfs_true)
1656 					*retcmpp = NFSERR_NOTSAME;
1657 				}
1658 			} else if (pc != NULL) {
1659 				pc->pc_chownrestricted =
1660 				    fxdr_unsigned(u_int32_t, *tl);
1661 			}
1662 			attrsum += NFSX_UNSIGNED;
1663 			break;
1664 		case NFSATTRBIT_FILEHANDLE:
1665 			error = nfsm_getfh(nd, &tnfhp);
1666 			if (error)
1667 				goto nfsmout;
1668 			tfhsize = tnfhp->nfh_len;
1669 			if (compare) {
1670 				if (!(*retcmpp) &&
1671 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1672 				     fhp, fhsize))
1673 					*retcmpp = NFSERR_NOTSAME;
1674 				free(tnfhp, M_NFSFH);
1675 			} else if (nfhpp != NULL) {
1676 				*nfhpp = tnfhp;
1677 			} else {
1678 				free(tnfhp, M_NFSFH);
1679 			}
1680 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1681 			break;
1682 		case NFSATTRBIT_FILEID:
1683 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1684 			thyp = fxdr_hyper(tl);
1685 			if (compare) {
1686 				if (!(*retcmpp)) {
1687 					if (nap->na_fileid != thyp)
1688 						*retcmpp = NFSERR_NOTSAME;
1689 				}
1690 			} else if (nap != NULL)
1691 				nap->na_fileid = thyp;
1692 			attrsum += NFSX_HYPER;
1693 			break;
1694 		case NFSATTRBIT_FILESAVAIL:
1695 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1696 			if (compare) {
1697 				uquad = nfsv4_filesavail(sbp, vp->v_mount);
1698 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1699 					*retcmpp = NFSERR_NOTSAME;
1700 			} else if (sfp != NULL) {
1701 				sfp->sf_afiles = fxdr_hyper(tl);
1702 			}
1703 			attrsum += NFSX_HYPER;
1704 			break;
1705 		case NFSATTRBIT_FILESFREE:
1706 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1707 			if (compare) {
1708 				uquad = (uint64_t)sbp->f_ffree;
1709 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1710 					*retcmpp = NFSERR_NOTSAME;
1711 			} else if (sfp != NULL) {
1712 				sfp->sf_ffiles = fxdr_hyper(tl);
1713 			}
1714 			attrsum += NFSX_HYPER;
1715 			break;
1716 		case NFSATTRBIT_FILESTOTAL:
1717 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1718 			if (compare) {
1719 				uquad = sbp->f_files;
1720 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1721 					*retcmpp = NFSERR_NOTSAME;
1722 			} else if (sfp != NULL) {
1723 				sfp->sf_tfiles = fxdr_hyper(tl);
1724 			}
1725 			attrsum += NFSX_HYPER;
1726 			break;
1727 		case NFSATTRBIT_FSLOCATIONS:
1728 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1729 			if (error)
1730 				goto nfsmout;
1731 			attrsum += l;
1732 			if (compare && !(*retcmpp)) {
1733 				refp = nfsv4root_getreferral(vp, NULL, 0);
1734 				if (refp != NULL) {
1735 					if (cp == NULL || cp2 == NULL ||
1736 					    strcmp(cp, "/") ||
1737 					    strcmp(cp2, refp->nfr_srvlist))
1738 						*retcmpp = NFSERR_NOTSAME;
1739 				} else if (m == 0) {
1740 					*retcmpp = NFSERR_NOTSAME;
1741 				}
1742 			}
1743 			if (cp != NULL)
1744 				free(cp, M_NFSSTRING);
1745 			if (cp2 != NULL)
1746 				free(cp2, M_NFSSTRING);
1747 			break;
1748 		case NFSATTRBIT_HIDDEN:
1749 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1750 			if (compare && !(*retcmpp))
1751 				*retcmpp = NFSERR_ATTRNOTSUPP;
1752 			attrsum += NFSX_UNSIGNED;
1753 			break;
1754 		case NFSATTRBIT_HOMOGENEOUS:
1755 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1756 			if (compare) {
1757 				if (!(*retcmpp)) {
1758 				    if (fsp->fs_properties &
1759 					NFSV3_FSFHOMOGENEOUS) {
1760 					if (*tl == newnfs_false)
1761 						*retcmpp = NFSERR_NOTSAME;
1762 				    } else {
1763 					if (*tl == newnfs_true)
1764 						*retcmpp = NFSERR_NOTSAME;
1765 				    }
1766 				}
1767 			} else if (fsp != NULL) {
1768 				if (*tl == newnfs_true)
1769 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1770 				else
1771 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1772 			}
1773 			attrsum += NFSX_UNSIGNED;
1774 			break;
1775 		case NFSATTRBIT_MAXFILESIZE:
1776 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1777 			tnfsquad.qval = fxdr_hyper(tl);
1778 			if (compare) {
1779 				if (!(*retcmpp)) {
1780 					tquad = NFSRV_MAXFILESIZE;
1781 					if (tquad != tnfsquad.qval)
1782 						*retcmpp = NFSERR_NOTSAME;
1783 				}
1784 			} else if (fsp != NULL) {
1785 				fsp->fs_maxfilesize = tnfsquad.qval;
1786 			}
1787 			attrsum += NFSX_HYPER;
1788 			break;
1789 		case NFSATTRBIT_MAXLINK:
1790 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1791 			if (compare) {
1792 				if (!(*retcmpp)) {
1793 				    if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1794 					*retcmpp = NFSERR_NOTSAME;
1795 				}
1796 			} else if (pc != NULL) {
1797 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1798 			}
1799 			attrsum += NFSX_UNSIGNED;
1800 			break;
1801 		case NFSATTRBIT_MAXNAME:
1802 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1803 			if (compare) {
1804 				if (!(*retcmpp)) {
1805 				    if (fsp->fs_maxname !=
1806 					fxdr_unsigned(u_int32_t, *tl))
1807 						*retcmpp = NFSERR_NOTSAME;
1808 				}
1809 			} else {
1810 				tuint = fxdr_unsigned(u_int32_t, *tl);
1811 				/*
1812 				 * Some Linux NFSv4 servers report this
1813 				 * as 0 or 4billion, so I'll set it to
1814 				 * NFS_MAXNAMLEN. If a server actually creates
1815 				 * a name longer than NFS_MAXNAMLEN, it will
1816 				 * get an error back.
1817 				 */
1818 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1819 					tuint = NFS_MAXNAMLEN;
1820 				if (fsp != NULL)
1821 					fsp->fs_maxname = tuint;
1822 				if (pc != NULL)
1823 					pc->pc_namemax = tuint;
1824 			}
1825 			attrsum += NFSX_UNSIGNED;
1826 			break;
1827 		case NFSATTRBIT_MAXREAD:
1828 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1829 			if (compare) {
1830 				if (!(*retcmpp)) {
1831 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1832 					*(tl + 1)) || *tl != 0)
1833 					*retcmpp = NFSERR_NOTSAME;
1834 				}
1835 			} else if (fsp != NULL) {
1836 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1837 				fsp->fs_rtpref = fsp->fs_rtmax;
1838 				fsp->fs_dtpref = fsp->fs_rtpref;
1839 			}
1840 			attrsum += NFSX_HYPER;
1841 			break;
1842 		case NFSATTRBIT_MAXWRITE:
1843 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1844 			if (compare) {
1845 				if (!(*retcmpp)) {
1846 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1847 					*(tl + 1)) || *tl != 0)
1848 					*retcmpp = NFSERR_NOTSAME;
1849 				}
1850 			} else if (fsp != NULL) {
1851 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1852 				fsp->fs_wtpref = fsp->fs_wtmax;
1853 			}
1854 			attrsum += NFSX_HYPER;
1855 			break;
1856 		case NFSATTRBIT_MIMETYPE:
1857 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1858 			i = fxdr_unsigned(int, *tl);
1859 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1860 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1861 			if (error)
1862 				goto nfsmout;
1863 			if (compare && !(*retcmpp))
1864 				*retcmpp = NFSERR_ATTRNOTSUPP;
1865 			break;
1866 		case NFSATTRBIT_MODE:
1867 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1868 			if (compare) {
1869 				if (!(*retcmpp)) {
1870 				    if (nap->na_mode != nfstov_mode(*tl))
1871 					*retcmpp = NFSERR_NOTSAME;
1872 				}
1873 			} else if (nap != NULL) {
1874 				nap->na_mode = nfstov_mode(*tl);
1875 			}
1876 			attrsum += NFSX_UNSIGNED;
1877 			break;
1878 		case NFSATTRBIT_NOTRUNC:
1879 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1880 			if (compare) {
1881 				if (!(*retcmpp)) {
1882 				    if (*tl != newnfs_true)
1883 					*retcmpp = NFSERR_NOTSAME;
1884 				}
1885 			} else if (pc != NULL) {
1886 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1887 			}
1888 			attrsum += NFSX_UNSIGNED;
1889 			break;
1890 		case NFSATTRBIT_NUMLINKS:
1891 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1892 			tuint = fxdr_unsigned(u_int32_t, *tl);
1893 			if (compare) {
1894 			    if (!(*retcmpp)) {
1895 				if ((u_int32_t)nap->na_nlink != tuint)
1896 					*retcmpp = NFSERR_NOTSAME;
1897 			    }
1898 			} else if (nap != NULL) {
1899 				nap->na_nlink = tuint;
1900 			}
1901 			attrsum += NFSX_UNSIGNED;
1902 			break;
1903 		case NFSATTRBIT_OWNER:
1904 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1905 			j = fxdr_unsigned(int, *tl);
1906 			if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
1907 				error = NFSERR_BADXDR;
1908 				goto nfsmout;
1909 			}
1910 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1911 			if (j > NFSV4_SMALLSTR)
1912 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1913 			else
1914 				cp = namestr;
1915 			error = nfsrv_mtostr(nd, cp, j);
1916 			if (error) {
1917 				if (j > NFSV4_SMALLSTR)
1918 					free(cp, M_NFSSTRING);
1919 				goto nfsmout;
1920 			}
1921 			if (compare) {
1922 			    if (!(*retcmpp)) {
1923 				if (nfsv4_strtouid(nd, cp, j, &uid) ||
1924 				    nap->na_uid != uid)
1925 				    *retcmpp = NFSERR_NOTSAME;
1926 			    }
1927 			} else if (nap != NULL) {
1928 				if (nfsv4_strtouid(nd, cp, j, &uid))
1929 					nap->na_uid =
1930 					    NFSD_VNET(nfsrv_defaultuid);
1931 				else
1932 					nap->na_uid = uid;
1933 			}
1934 			if (j > NFSV4_SMALLSTR)
1935 				free(cp, M_NFSSTRING);
1936 			break;
1937 		case NFSATTRBIT_OWNERGROUP:
1938 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1939 			j = fxdr_unsigned(int, *tl);
1940 			if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
1941 				error =  NFSERR_BADXDR;
1942 				goto nfsmout;
1943 			}
1944 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1945 			if (j > NFSV4_SMALLSTR)
1946 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1947 			else
1948 				cp = namestr;
1949 			error = nfsrv_mtostr(nd, cp, j);
1950 			if (error) {
1951 				if (j > NFSV4_SMALLSTR)
1952 					free(cp, M_NFSSTRING);
1953 				goto nfsmout;
1954 			}
1955 			if (compare) {
1956 			    if (!(*retcmpp)) {
1957 				if (nfsv4_strtogid(nd, cp, j, &gid) ||
1958 				    nap->na_gid != gid)
1959 				    *retcmpp = NFSERR_NOTSAME;
1960 			    }
1961 			} else if (nap != NULL) {
1962 				if (nfsv4_strtogid(nd, cp, j, &gid))
1963 					nap->na_gid =
1964 					    NFSD_VNET(nfsrv_defaultgid);
1965 				else
1966 					nap->na_gid = gid;
1967 			}
1968 			if (j > NFSV4_SMALLSTR)
1969 				free(cp, M_NFSSTRING);
1970 			break;
1971 		case NFSATTRBIT_QUOTAHARD:
1972 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1973 			if (sbp != NULL) {
1974 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1975 				freenum = sbp->f_bfree;
1976 			    else
1977 				freenum = sbp->f_bavail;
1978 #ifdef QUOTA
1979 			    /*
1980 			     * ufs_quotactl() insists that the uid argument
1981 			     * equal p_ruid for non-root quota access, so
1982 			     * we'll just make sure that's the case.
1983 			     */
1984 			    savuid = p->p_cred->p_ruid;
1985 			    p->p_cred->p_ruid = cred->cr_uid;
1986 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1987 				USRQUOTA), cred->cr_uid, &dqb))
1988 				freenum = min(dqb.dqb_bhardlimit, freenum);
1989 			    p->p_cred->p_ruid = savuid;
1990 #endif	/* QUOTA */
1991 			    uquad = (u_int64_t)freenum;
1992 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1993 			}
1994 			if (compare && !(*retcmpp)) {
1995 				if (uquad != fxdr_hyper(tl))
1996 					*retcmpp = NFSERR_NOTSAME;
1997 			}
1998 			attrsum += NFSX_HYPER;
1999 			break;
2000 		case NFSATTRBIT_QUOTASOFT:
2001 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2002 			if (sbp != NULL) {
2003 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2004 				freenum = sbp->f_bfree;
2005 			    else
2006 				freenum = sbp->f_bavail;
2007 #ifdef QUOTA
2008 			    /*
2009 			     * ufs_quotactl() insists that the uid argument
2010 			     * equal p_ruid for non-root quota access, so
2011 			     * we'll just make sure that's the case.
2012 			     */
2013 			    savuid = p->p_cred->p_ruid;
2014 			    p->p_cred->p_ruid = cred->cr_uid;
2015 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2016 				USRQUOTA), cred->cr_uid, &dqb))
2017 				freenum = min(dqb.dqb_bsoftlimit, freenum);
2018 			    p->p_cred->p_ruid = savuid;
2019 #endif	/* QUOTA */
2020 			    uquad = (u_int64_t)freenum;
2021 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2022 			}
2023 			if (compare && !(*retcmpp)) {
2024 				if (uquad != fxdr_hyper(tl))
2025 					*retcmpp = NFSERR_NOTSAME;
2026 			}
2027 			attrsum += NFSX_HYPER;
2028 			break;
2029 		case NFSATTRBIT_QUOTAUSED:
2030 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2031 			if (sbp != NULL) {
2032 			    freenum = 0;
2033 #ifdef QUOTA
2034 			    /*
2035 			     * ufs_quotactl() insists that the uid argument
2036 			     * equal p_ruid for non-root quota access, so
2037 			     * we'll just make sure that's the case.
2038 			     */
2039 			    savuid = p->p_cred->p_ruid;
2040 			    p->p_cred->p_ruid = cred->cr_uid;
2041 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2042 				USRQUOTA), cred->cr_uid, &dqb))
2043 				freenum = dqb.dqb_curblocks;
2044 			    p->p_cred->p_ruid = savuid;
2045 #endif	/* QUOTA */
2046 			    uquad = (u_int64_t)freenum;
2047 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2048 			}
2049 			if (compare && !(*retcmpp)) {
2050 				if (uquad != fxdr_hyper(tl))
2051 					*retcmpp = NFSERR_NOTSAME;
2052 			}
2053 			attrsum += NFSX_HYPER;
2054 			break;
2055 		case NFSATTRBIT_RAWDEV:
2056 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
2057 			j = fxdr_unsigned(int, *tl++);
2058 			k = fxdr_unsigned(int, *tl);
2059 			if (compare) {
2060 			    if (!(*retcmpp)) {
2061 				if (nap->na_rdev != NFSMAKEDEV(j, k))
2062 					*retcmpp = NFSERR_NOTSAME;
2063 			    }
2064 			} else if (nap != NULL) {
2065 				nap->na_rdev = NFSMAKEDEV(j, k);
2066 			}
2067 			attrsum += NFSX_V4SPECDATA;
2068 			break;
2069 		case NFSATTRBIT_SPACEAVAIL:
2070 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2071 			if (compare) {
2072 				if (priv_check_cred(cred,
2073 				    PRIV_VFS_BLOCKRESERVE))
2074 					uquad = sbp->f_bfree;
2075 				else
2076 					uquad = (uint64_t)sbp->f_bavail;
2077 				uquad *= sbp->f_bsize;
2078 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2079 					*retcmpp = NFSERR_NOTSAME;
2080 			} else if (sfp != NULL) {
2081 				sfp->sf_abytes = fxdr_hyper(tl);
2082 			}
2083 			attrsum += NFSX_HYPER;
2084 			break;
2085 		case NFSATTRBIT_SPACEFREE:
2086 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2087 			if (compare) {
2088 				uquad = sbp->f_bfree;
2089 				uquad *= sbp->f_bsize;
2090 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2091 					*retcmpp = NFSERR_NOTSAME;
2092 			} else if (sfp != NULL) {
2093 				sfp->sf_fbytes = fxdr_hyper(tl);
2094 			}
2095 			attrsum += NFSX_HYPER;
2096 			break;
2097 		case NFSATTRBIT_SPACETOTAL:
2098 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2099 			if (compare) {
2100 				uquad = sbp->f_blocks;
2101 				uquad *= sbp->f_bsize;
2102 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2103 					*retcmpp = NFSERR_NOTSAME;
2104 			} else if (sfp != NULL) {
2105 				sfp->sf_tbytes = fxdr_hyper(tl);
2106 			}
2107 			attrsum += NFSX_HYPER;
2108 			break;
2109 		case NFSATTRBIT_SPACEUSED:
2110 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2111 			thyp = fxdr_hyper(tl);
2112 			if (compare) {
2113 			    if (!(*retcmpp)) {
2114 				if ((u_int64_t)nap->na_bytes != thyp)
2115 					*retcmpp = NFSERR_NOTSAME;
2116 			    }
2117 			} else if (nap != NULL) {
2118 				nap->na_bytes = thyp;
2119 			}
2120 			attrsum += NFSX_HYPER;
2121 			break;
2122 		case NFSATTRBIT_SYSTEM:
2123 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2124 			if (compare && !(*retcmpp))
2125 				*retcmpp = NFSERR_ATTRNOTSUPP;
2126 			attrsum += NFSX_UNSIGNED;
2127 			break;
2128 		case NFSATTRBIT_TIMEACCESS:
2129 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2130 			fxdr_nfsv4time(tl, &temptime);
2131 			if (compare) {
2132 			    if (!(*retcmpp)) {
2133 				if (!NFS_CMPTIME(temptime, nap->na_atime))
2134 					*retcmpp = NFSERR_NOTSAME;
2135 			    }
2136 			} else if (nap != NULL) {
2137 				nap->na_atime = temptime;
2138 			}
2139 			attrsum += NFSX_V4TIME;
2140 			break;
2141 		case NFSATTRBIT_TIMEACCESSSET:
2142 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2143 			attrsum += NFSX_UNSIGNED;
2144 			i = fxdr_unsigned(int, *tl);
2145 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2146 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2147 				attrsum += NFSX_V4TIME;
2148 			}
2149 			if (compare && !(*retcmpp))
2150 				*retcmpp = NFSERR_INVAL;
2151 			break;
2152 		case NFSATTRBIT_TIMEBACKUP:
2153 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2154 			if (compare && !(*retcmpp))
2155 				*retcmpp = NFSERR_ATTRNOTSUPP;
2156 			attrsum += NFSX_V4TIME;
2157 			break;
2158 		case NFSATTRBIT_TIMECREATE:
2159 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2160 			fxdr_nfsv4time(tl, &temptime);
2161 			if (compare) {
2162 			    if (!(*retcmpp)) {
2163 				if (!NFS_CMPTIME(temptime, nap->na_btime))
2164 					*retcmpp = NFSERR_NOTSAME;
2165 			    }
2166 			} else if (nap != NULL) {
2167 				nap->na_btime = temptime;
2168 			}
2169 			attrsum += NFSX_V4TIME;
2170 			break;
2171 		case NFSATTRBIT_TIMEDELTA:
2172 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2173 			if (fsp != NULL) {
2174 			    if (compare) {
2175 				if (!(*retcmpp)) {
2176 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2177 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2178 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2179 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
2180 					 1000000000) ||
2181 					*tl != 0)
2182 					    *retcmpp = NFSERR_NOTSAME;
2183 				}
2184 			    } else {
2185 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2186 			    }
2187 			}
2188 			attrsum += NFSX_V4TIME;
2189 			break;
2190 		case NFSATTRBIT_TIMEMETADATA:
2191 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2192 			fxdr_nfsv4time(tl, &temptime);
2193 			if (compare) {
2194 			    if (!(*retcmpp)) {
2195 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
2196 					*retcmpp = NFSERR_NOTSAME;
2197 			    }
2198 			} else if (nap != NULL) {
2199 				nap->na_ctime = temptime;
2200 			}
2201 			attrsum += NFSX_V4TIME;
2202 			break;
2203 		case NFSATTRBIT_TIMEMODIFY:
2204 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2205 			fxdr_nfsv4time(tl, &temptime);
2206 			if (compare) {
2207 			    if (!(*retcmpp)) {
2208 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
2209 					*retcmpp = NFSERR_NOTSAME;
2210 			    }
2211 			} else if (nap != NULL) {
2212 				nap->na_mtime = temptime;
2213 			}
2214 			attrsum += NFSX_V4TIME;
2215 			break;
2216 		case NFSATTRBIT_TIMEMODIFYSET:
2217 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2218 			attrsum += NFSX_UNSIGNED;
2219 			i = fxdr_unsigned(int, *tl);
2220 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2221 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2222 				attrsum += NFSX_V4TIME;
2223 			}
2224 			if (compare && !(*retcmpp))
2225 				*retcmpp = NFSERR_INVAL;
2226 			break;
2227 		case NFSATTRBIT_MOUNTEDONFILEID:
2228 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2229 			thyp = fxdr_hyper(tl);
2230 			if (compare) {
2231 				if (!(*retcmpp)) {
2232 					if (!vp || !nfsrv_atroot(vp, &thyp2))
2233 						thyp2 = nap->na_fileid;
2234 					if (thyp2 != thyp)
2235 						*retcmpp = NFSERR_NOTSAME;
2236 				}
2237 			} else if (nap != NULL)
2238 				nap->na_mntonfileno = thyp;
2239 			attrsum += NFSX_HYPER;
2240 			break;
2241 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2242 			retnotsup = 0;
2243 			error = nfsrv_getattrbits(nd, &retattrbits,
2244 			    &cnt, &retnotsup);
2245 			if (error)
2246 			    goto nfsmout;
2247 			if (compare && !(*retcmpp)) {
2248 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2249 			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2250 			   NFSCLRBIT_ATTRBIT(&checkattrbits,
2251 				NFSATTRBIT_TIMEACCESSSET);
2252 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2253 			       || retnotsup)
2254 				*retcmpp = NFSERR_NOTSAME;
2255 			}
2256 			attrsum += cnt;
2257 			break;
2258 		case NFSATTRBIT_FSLAYOUTTYPE:
2259 		case NFSATTRBIT_LAYOUTTYPE:
2260 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2261 			attrsum += NFSX_UNSIGNED;
2262 			i = fxdr_unsigned(int, *tl);
2263 			/*
2264 			 * The RFCs do not define an upper limit for the
2265 			 * number of layout types, but 32 should be more
2266 			 * than enough.
2267 			 */
2268 			if (i < 0 || i > 32) {
2269 				error = NFSERR_BADXDR;
2270 				goto nfsmout;
2271 			}
2272 			if (i > 0) {
2273 				NFSM_DISSECT(tl, u_int32_t *, i *
2274 				    NFSX_UNSIGNED);
2275 				attrsum += i * NFSX_UNSIGNED;
2276 				j = fxdr_unsigned(int, *tl);
2277 				if (i == 1 && compare && !(*retcmpp) &&
2278 				    (((nfsrv_doflexfile != 0 ||
2279 				       nfsrv_maxpnfsmirror > 1) &&
2280 				      j != NFSLAYOUT_FLEXFILE) ||
2281 				    (nfsrv_doflexfile == 0 &&
2282 				     j != NFSLAYOUT_NFSV4_1_FILES)))
2283 					*retcmpp = NFSERR_NOTSAME;
2284 			}
2285 			if (nfsrv_devidcnt == 0) {
2286 				if (compare && !(*retcmpp) && i > 0)
2287 					*retcmpp = NFSERR_NOTSAME;
2288 			} else {
2289 				if (compare && !(*retcmpp) && i != 1)
2290 					*retcmpp = NFSERR_NOTSAME;
2291 			}
2292 			break;
2293 		case NFSATTRBIT_LAYOUTALIGNMENT:
2294 		case NFSATTRBIT_LAYOUTBLKSIZE:
2295 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2296 			attrsum += NFSX_UNSIGNED;
2297 			i = fxdr_unsigned(int, *tl);
2298 			if (compare && !(*retcmpp) && i != nfs_srvmaxio)
2299 				*retcmpp = NFSERR_NOTSAME;
2300 			break;
2301 		default:
2302 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2303 				bitpos);
2304 			if (compare && !(*retcmpp))
2305 				*retcmpp = NFSERR_ATTRNOTSUPP;
2306 			/*
2307 			 * and get out of the loop, since we can't parse
2308 			 * the unknown attribute data.
2309 			 */
2310 			bitpos = NFSATTRBIT_MAX;
2311 			break;
2312 		}
2313 	}
2314 
2315 	/*
2316 	 * some clients pad the attrlist, so we need to skip over the
2317 	 * padding.
2318 	 */
2319 	if (attrsum > attrsize) {
2320 		error = NFSERR_BADXDR;
2321 	} else {
2322 		attrsize = NFSM_RNDUP(attrsize);
2323 		if (attrsum < attrsize)
2324 			error = nfsm_advance(nd, attrsize - attrsum, -1);
2325 	}
2326 nfsmout:
2327 	NFSD_CURVNET_RESTORE();
2328 	NFSEXITCODE2(error, nd);
2329 	return (error);
2330 }
2331 
2332 /*
2333  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2334  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2335  * The first argument is a pointer to an nfsv4lock structure.
2336  * The second argument is 1 iff a blocking lock is wanted.
2337  * If this argument is 0, the call waits until no thread either wants nor
2338  * holds an exclusive lock.
2339  * It returns 1 if the lock was acquired, 0 otherwise.
2340  * If several processes call this function concurrently wanting the exclusive
2341  * lock, one will get the lock and the rest will return without getting the
2342  * lock. (If the caller must have the lock, it simply calls this function in a
2343  *  loop until the function returns 1 to indicate the lock was acquired.)
2344  * Any usecnt must be decremented by calling nfsv4_relref() before
2345  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2346  * be called in a loop.
2347  * The isleptp argument is set to indicate if the call slept, iff not NULL
2348  * and the mp argument indicates to check for a forced dismount, iff not
2349  * NULL.
2350  */
2351 int
2352 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2353     struct mtx *mutex, struct mount *mp)
2354 {
2355 
2356 	if (isleptp)
2357 		*isleptp = 0;
2358 	/*
2359 	 * If a lock is wanted, loop around until the lock is acquired by
2360 	 * someone and then released. If I want the lock, try to acquire it.
2361 	 * For a lock to be issued, no lock must be in force and the usecnt
2362 	 * must be zero.
2363 	 */
2364 	if (iwantlock) {
2365 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2366 		lp->nfslock_usecnt == 0) {
2367 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2368 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
2369 		return (1);
2370 	    }
2371 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2372 	}
2373 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2374 		if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2375 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2376 			return (0);
2377 		}
2378 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2379 		if (isleptp)
2380 			*isleptp = 1;
2381 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
2382 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2383 		    lp->nfslock_usecnt == 0) {
2384 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2385 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
2386 			return (1);
2387 		}
2388 	}
2389 	return (0);
2390 }
2391 
2392 /*
2393  * Release the lock acquired by nfsv4_lock().
2394  * The second argument is set to 1 to indicate the nfslock_usecnt should be
2395  * incremented, as well.
2396  */
2397 void
2398 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2399 {
2400 
2401 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2402 	if (incref)
2403 		lp->nfslock_usecnt++;
2404 	nfsv4_wanted(lp);
2405 }
2406 
2407 /*
2408  * Release a reference cnt.
2409  */
2410 void
2411 nfsv4_relref(struct nfsv4lock *lp)
2412 {
2413 
2414 	if (lp->nfslock_usecnt <= 0)
2415 		panic("nfsv4root ref cnt");
2416 	lp->nfslock_usecnt--;
2417 	if (lp->nfslock_usecnt == 0)
2418 		nfsv4_wanted(lp);
2419 }
2420 
2421 /*
2422  * Get a reference cnt.
2423  * This function will wait for any exclusive lock to be released, but will
2424  * not wait for threads that want the exclusive lock. If priority needs
2425  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2426  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2427  * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2428  * return without getting a refcnt for that case.
2429  */
2430 void
2431 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
2432     struct mount *mp)
2433 {
2434 
2435 	if (isleptp)
2436 		*isleptp = 0;
2437 
2438 	/*
2439 	 * Wait for a lock held.
2440 	 */
2441 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2442 		if (mp != NULL && NFSCL_FORCEDISM(mp))
2443 			return;
2444 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2445 		if (isleptp)
2446 			*isleptp = 1;
2447 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
2448 	}
2449 	if (mp != NULL && NFSCL_FORCEDISM(mp))
2450 		return;
2451 
2452 	lp->nfslock_usecnt++;
2453 }
2454 
2455 /*
2456  * Get a reference as above, but return failure instead of sleeping if
2457  * an exclusive lock is held.
2458  */
2459 int
2460 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2461 {
2462 
2463 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2464 		return (0);
2465 
2466 	lp->nfslock_usecnt++;
2467 	return (1);
2468 }
2469 
2470 /*
2471  * Test for a lock. Return 1 if locked, 0 otherwise.
2472  */
2473 int
2474 nfsv4_testlock(struct nfsv4lock *lp)
2475 {
2476 
2477 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2478 	    lp->nfslock_usecnt == 0)
2479 		return (0);
2480 	return (1);
2481 }
2482 
2483 /*
2484  * Wake up anyone sleeping, waiting for this lock.
2485  */
2486 static void
2487 nfsv4_wanted(struct nfsv4lock *lp)
2488 {
2489 
2490 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2491 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2492 		wakeup((caddr_t)&lp->nfslock_lock);
2493 	}
2494 }
2495 
2496 /*
2497  * Copy a string from an mbuf list into a character array.
2498  * Return EBADRPC if there is an mbuf error,
2499  * 0 otherwise.
2500  */
2501 int
2502 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2503 {
2504 	char *cp;
2505 	int xfer, len;
2506 	struct mbuf *mp;
2507 	int rem, error = 0;
2508 
2509 	mp = nd->nd_md;
2510 	cp = nd->nd_dpos;
2511 	len = mtod(mp, caddr_t) + mp->m_len - cp;
2512 	rem = NFSM_RNDUP(siz) - siz;
2513 	while (siz > 0) {
2514 		if (len > siz)
2515 			xfer = siz;
2516 		else
2517 			xfer = len;
2518 		NFSBCOPY(cp, str, xfer);
2519 		str += xfer;
2520 		siz -= xfer;
2521 		if (siz > 0) {
2522 			mp = mp->m_next;
2523 			if (mp == NULL) {
2524 				error = EBADRPC;
2525 				goto out;
2526 			}
2527 			cp = mtod(mp, caddr_t);
2528 			len = mp->m_len;
2529 		} else {
2530 			cp += xfer;
2531 			len -= xfer;
2532 		}
2533 	}
2534 	*str = '\0';
2535 	nd->nd_dpos = cp;
2536 	nd->nd_md = mp;
2537 	if (rem > 0) {
2538 		if (len < rem)
2539 			error = nfsm_advance(nd, rem, len);
2540 		else
2541 			nd->nd_dpos += rem;
2542 	}
2543 
2544 out:
2545 	NFSEXITCODE2(error, nd);
2546 	return (error);
2547 }
2548 
2549 /*
2550  * Fill in the attributes as marked by the bitmap (V4).
2551  */
2552 int
2553 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2554     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2555     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2556     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2557     struct statfs *pnfssf)
2558 {
2559 	int bitpos, retnum = 0;
2560 	u_int32_t *tl;
2561 	int siz, prefixnum, error;
2562 	u_char *cp, namestr[NFSV4_SMALLSTR];
2563 	nfsattrbit_t attrbits, retbits;
2564 	nfsattrbit_t *retbitp = &retbits;
2565 	u_int32_t freenum, *retnump;
2566 	u_int64_t uquad;
2567 	struct statfs *fs;
2568 	struct nfsfsinfo fsinf;
2569 	struct timespec temptime;
2570 	NFSACL_T *aclp, *naclp = NULL;
2571 	size_t atsiz;
2572 	bool xattrsupp;
2573 #ifdef QUOTA
2574 	struct dqblk dqb;
2575 	uid_t savuid;
2576 #endif
2577 
2578 	/*
2579 	 * First, set the bits that can be filled and get fsinfo.
2580 	 */
2581 	NFSSET_ATTRBIT(retbitp, attrbitp);
2582 	/*
2583 	 * If both p and cred are NULL, it is a client side setattr call.
2584 	 * If both p and cred are not NULL, it is a server side reply call.
2585 	 * If p is not NULL and cred is NULL, it is a client side callback
2586 	 * reply call.
2587 	 */
2588 	if (p == NULL && cred == NULL) {
2589 		NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2590 		aclp = saclp;
2591 	} else {
2592 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2593 		naclp = acl_alloc(M_WAITOK);
2594 		aclp = naclp;
2595 	}
2596 	nfsvno_getfs(&fsinf, isdgram);
2597 	/*
2598 	 * Get the VFS_STATFS(), since some attributes need them.
2599 	 */
2600 	fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2601 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2602 		error = VFS_STATFS(mp, fs);
2603 		if (error != 0) {
2604 			if (reterr) {
2605 				nd->nd_repstat = NFSERR_ACCES;
2606 				free(fs, M_STATFS);
2607 				return (0);
2608 			}
2609 			NFSCLRSTATFS_ATTRBIT(retbitp);
2610 		}
2611 		/*
2612 		 * Since NFS handles these values as unsigned on the
2613 		 * wire, there is no way to represent negative values,
2614 		 * so set them to 0. Without this, they will appear
2615 		 * to be very large positive values for clients like
2616 		 * Solaris10.
2617 		 */
2618 		if (fs->f_bavail < 0)
2619 			fs->f_bavail = 0;
2620 		if (fs->f_ffree < 0)
2621 			fs->f_ffree = 0;
2622 	}
2623 
2624 	/*
2625 	 * And the NFSv4 ACL...
2626 	 */
2627 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2628 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2629 		supports_nfsv4acls == 0))) {
2630 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2631 	}
2632 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2633 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2634 		    supports_nfsv4acls == 0)) {
2635 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2636 		} else if (naclp != NULL) {
2637 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2638 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2639 				if (error == 0)
2640 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2641 					    naclp, cred, p);
2642 				NFSVOPUNLOCK(vp);
2643 			} else
2644 				error = NFSERR_PERM;
2645 			if (error != 0) {
2646 				if (reterr) {
2647 					nd->nd_repstat = NFSERR_ACCES;
2648 					free(fs, M_STATFS);
2649 					return (0);
2650 				}
2651 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2652 			}
2653 		}
2654 	}
2655 
2656 	/* Check to see if Extended Attributes are supported. */
2657 	xattrsupp = false;
2658 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2659 		if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2660 			error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2661 			    "xxx", NULL, &atsiz, cred, p);
2662 			NFSVOPUNLOCK(vp);
2663 			if (error != EOPNOTSUPP)
2664 				xattrsupp = true;
2665 		}
2666 	}
2667 
2668 	/*
2669 	 * Put out the attribute bitmap for the ones being filled in
2670 	 * and get the field for the number of attributes returned.
2671 	 */
2672 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2673 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2674 	prefixnum += NFSX_UNSIGNED;
2675 
2676 	/*
2677 	 * Now, loop around filling in the attributes for each bit set.
2678 	 */
2679 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2680 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2681 		switch (bitpos) {
2682 		case NFSATTRBIT_SUPPORTEDATTRS:
2683 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2684 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2685 			    && supports_nfsv4acls == 0)) {
2686 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2687 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2688 			}
2689 			retnum += nfsrv_putattrbit(nd, &attrbits);
2690 			break;
2691 		case NFSATTRBIT_TYPE:
2692 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2693 			*tl = vtonfsv34_type(vap->va_type);
2694 			retnum += NFSX_UNSIGNED;
2695 			break;
2696 		case NFSATTRBIT_FHEXPIRETYPE:
2697 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2698 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2699 			retnum += NFSX_UNSIGNED;
2700 			break;
2701 		case NFSATTRBIT_CHANGE:
2702 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2703 			txdr_hyper(vap->va_filerev, tl);
2704 			retnum += NFSX_HYPER;
2705 			break;
2706 		case NFSATTRBIT_SIZE:
2707 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2708 			txdr_hyper(vap->va_size, tl);
2709 			retnum += NFSX_HYPER;
2710 			break;
2711 		case NFSATTRBIT_LINKSUPPORT:
2712 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2713 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2714 				*tl = newnfs_true;
2715 			else
2716 				*tl = newnfs_false;
2717 			retnum += NFSX_UNSIGNED;
2718 			break;
2719 		case NFSATTRBIT_SYMLINKSUPPORT:
2720 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2721 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2722 				*tl = newnfs_true;
2723 			else
2724 				*tl = newnfs_false;
2725 			retnum += NFSX_UNSIGNED;
2726 			break;
2727 		case NFSATTRBIT_NAMEDATTR:
2728 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2729 			*tl = newnfs_false;
2730 			retnum += NFSX_UNSIGNED;
2731 			break;
2732 		case NFSATTRBIT_FSID:
2733 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2734 			*tl++ = 0;
2735 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2736 			*tl++ = 0;
2737 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2738 			retnum += NFSX_V4FSID;
2739 			break;
2740 		case NFSATTRBIT_UNIQUEHANDLES:
2741 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2742 			*tl = newnfs_true;
2743 			retnum += NFSX_UNSIGNED;
2744 			break;
2745 		case NFSATTRBIT_LEASETIME:
2746 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2747 			*tl = txdr_unsigned(nfsrv_lease);
2748 			retnum += NFSX_UNSIGNED;
2749 			break;
2750 		case NFSATTRBIT_RDATTRERROR:
2751 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2752 			*tl = txdr_unsigned(rderror);
2753 			retnum += NFSX_UNSIGNED;
2754 			break;
2755 		/*
2756 		 * Recommended Attributes. (Only the supported ones.)
2757 		 */
2758 		case NFSATTRBIT_ACL:
2759 			retnum += nfsrv_buildacl(nd, aclp, vp->v_type, p);
2760 			break;
2761 		case NFSATTRBIT_ACLSUPPORT:
2762 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2763 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2764 			retnum += NFSX_UNSIGNED;
2765 			break;
2766 		case NFSATTRBIT_CANSETTIME:
2767 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2768 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2769 				*tl = newnfs_true;
2770 			else
2771 				*tl = newnfs_false;
2772 			retnum += NFSX_UNSIGNED;
2773 			break;
2774 		case NFSATTRBIT_CASEINSENSITIVE:
2775 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2776 			*tl = newnfs_false;
2777 			retnum += NFSX_UNSIGNED;
2778 			break;
2779 		case NFSATTRBIT_CASEPRESERVING:
2780 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2781 			*tl = newnfs_true;
2782 			retnum += NFSX_UNSIGNED;
2783 			break;
2784 		case NFSATTRBIT_CHOWNRESTRICTED:
2785 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2786 			*tl = newnfs_true;
2787 			retnum += NFSX_UNSIGNED;
2788 			break;
2789 		case NFSATTRBIT_FILEHANDLE:
2790 			retnum += nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
2791 			break;
2792 		case NFSATTRBIT_FILEID:
2793 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2794 			uquad = vap->va_fileid;
2795 			txdr_hyper(uquad, tl);
2796 			retnum += NFSX_HYPER;
2797 			break;
2798 		case NFSATTRBIT_FILESAVAIL:
2799 			freenum = nfsv4_filesavail(fs, mp);
2800 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2801 			*tl++ = 0;
2802 			*tl = txdr_unsigned(freenum);
2803 			retnum += NFSX_HYPER;
2804 			break;
2805 		case NFSATTRBIT_FILESFREE:
2806 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2807 			*tl++ = 0;
2808 			*tl = txdr_unsigned(fs->f_ffree);
2809 			retnum += NFSX_HYPER;
2810 			break;
2811 		case NFSATTRBIT_FILESTOTAL:
2812 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2813 			*tl++ = 0;
2814 			*tl = txdr_unsigned(fs->f_files);
2815 			retnum += NFSX_HYPER;
2816 			break;
2817 		case NFSATTRBIT_FSLOCATIONS:
2818 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2819 			*tl++ = 0;
2820 			*tl = 0;
2821 			retnum += 2 * NFSX_UNSIGNED;
2822 			break;
2823 		case NFSATTRBIT_HOMOGENEOUS:
2824 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2825 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2826 				*tl = newnfs_true;
2827 			else
2828 				*tl = newnfs_false;
2829 			retnum += NFSX_UNSIGNED;
2830 			break;
2831 		case NFSATTRBIT_MAXFILESIZE:
2832 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2833 			uquad = NFSRV_MAXFILESIZE;
2834 			txdr_hyper(uquad, tl);
2835 			retnum += NFSX_HYPER;
2836 			break;
2837 		case NFSATTRBIT_MAXLINK:
2838 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2839 			*tl = txdr_unsigned(NFS_LINK_MAX);
2840 			retnum += NFSX_UNSIGNED;
2841 			break;
2842 		case NFSATTRBIT_MAXNAME:
2843 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2844 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
2845 			retnum += NFSX_UNSIGNED;
2846 			break;
2847 		case NFSATTRBIT_MAXREAD:
2848 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2849 			*tl++ = 0;
2850 			*tl = txdr_unsigned(fsinf.fs_rtmax);
2851 			retnum += NFSX_HYPER;
2852 			break;
2853 		case NFSATTRBIT_MAXWRITE:
2854 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2855 			*tl++ = 0;
2856 			*tl = txdr_unsigned(fsinf.fs_wtmax);
2857 			retnum += NFSX_HYPER;
2858 			break;
2859 		case NFSATTRBIT_MODE:
2860 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2861 			*tl = vtonfsv34_mode(vap->va_mode);
2862 			retnum += NFSX_UNSIGNED;
2863 			break;
2864 		case NFSATTRBIT_NOTRUNC:
2865 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2866 			*tl = newnfs_true;
2867 			retnum += NFSX_UNSIGNED;
2868 			break;
2869 		case NFSATTRBIT_NUMLINKS:
2870 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2871 			*tl = txdr_unsigned(vap->va_nlink);
2872 			retnum += NFSX_UNSIGNED;
2873 			break;
2874 		case NFSATTRBIT_OWNER:
2875 			cp = namestr;
2876 			nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2877 			retnum += nfsm_strtom(nd, cp, siz);
2878 			if (cp != namestr)
2879 				free(cp, M_NFSSTRING);
2880 			break;
2881 		case NFSATTRBIT_OWNERGROUP:
2882 			cp = namestr;
2883 			nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2884 			retnum += nfsm_strtom(nd, cp, siz);
2885 			if (cp != namestr)
2886 				free(cp, M_NFSSTRING);
2887 			break;
2888 		case NFSATTRBIT_QUOTAHARD:
2889 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2890 				freenum = fs->f_bfree;
2891 			else
2892 				freenum = fs->f_bavail;
2893 #ifdef QUOTA
2894 			/*
2895 			 * ufs_quotactl() insists that the uid argument
2896 			 * equal p_ruid for non-root quota access, so
2897 			 * we'll just make sure that's the case.
2898 			 */
2899 			savuid = p->p_cred->p_ruid;
2900 			p->p_cred->p_ruid = cred->cr_uid;
2901 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2902 			    cred->cr_uid, &dqb))
2903 			    freenum = min(dqb.dqb_bhardlimit, freenum);
2904 			p->p_cred->p_ruid = savuid;
2905 #endif	/* QUOTA */
2906 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2907 			uquad = (u_int64_t)freenum;
2908 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2909 			txdr_hyper(uquad, tl);
2910 			retnum += NFSX_HYPER;
2911 			break;
2912 		case NFSATTRBIT_QUOTASOFT:
2913 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2914 				freenum = fs->f_bfree;
2915 			else
2916 				freenum = fs->f_bavail;
2917 #ifdef QUOTA
2918 			/*
2919 			 * ufs_quotactl() insists that the uid argument
2920 			 * equal p_ruid for non-root quota access, so
2921 			 * we'll just make sure that's the case.
2922 			 */
2923 			savuid = p->p_cred->p_ruid;
2924 			p->p_cred->p_ruid = cred->cr_uid;
2925 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2926 			    cred->cr_uid, &dqb))
2927 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
2928 			p->p_cred->p_ruid = savuid;
2929 #endif	/* QUOTA */
2930 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2931 			uquad = (u_int64_t)freenum;
2932 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2933 			txdr_hyper(uquad, tl);
2934 			retnum += NFSX_HYPER;
2935 			break;
2936 		case NFSATTRBIT_QUOTAUSED:
2937 			freenum = 0;
2938 #ifdef QUOTA
2939 			/*
2940 			 * ufs_quotactl() insists that the uid argument
2941 			 * equal p_ruid for non-root quota access, so
2942 			 * we'll just make sure that's the case.
2943 			 */
2944 			savuid = p->p_cred->p_ruid;
2945 			p->p_cred->p_ruid = cred->cr_uid;
2946 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2947 			    cred->cr_uid, &dqb))
2948 			    freenum = dqb.dqb_curblocks;
2949 			p->p_cred->p_ruid = savuid;
2950 #endif	/* QUOTA */
2951 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2952 			uquad = (u_int64_t)freenum;
2953 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2954 			txdr_hyper(uquad, tl);
2955 			retnum += NFSX_HYPER;
2956 			break;
2957 		case NFSATTRBIT_RAWDEV:
2958 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2959 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2960 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2961 			retnum += NFSX_V4SPECDATA;
2962 			break;
2963 		case NFSATTRBIT_SPACEAVAIL:
2964 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2965 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2966 				if (pnfssf != NULL)
2967 					uquad = (u_int64_t)pnfssf->f_bfree;
2968 				else
2969 					uquad = (u_int64_t)fs->f_bfree;
2970 			} else {
2971 				if (pnfssf != NULL)
2972 					uquad = (u_int64_t)pnfssf->f_bavail;
2973 				else
2974 					uquad = (u_int64_t)fs->f_bavail;
2975 			}
2976 			if (pnfssf != NULL)
2977 				uquad *= pnfssf->f_bsize;
2978 			else
2979 				uquad *= fs->f_bsize;
2980 			txdr_hyper(uquad, tl);
2981 			retnum += NFSX_HYPER;
2982 			break;
2983 		case NFSATTRBIT_SPACEFREE:
2984 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2985 			if (pnfssf != NULL) {
2986 				uquad = (u_int64_t)pnfssf->f_bfree;
2987 				uquad *= pnfssf->f_bsize;
2988 			} else {
2989 				uquad = (u_int64_t)fs->f_bfree;
2990 				uquad *= fs->f_bsize;
2991 			}
2992 			txdr_hyper(uquad, tl);
2993 			retnum += NFSX_HYPER;
2994 			break;
2995 		case NFSATTRBIT_SPACETOTAL:
2996 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2997 			if (pnfssf != NULL) {
2998 				uquad = (u_int64_t)pnfssf->f_blocks;
2999 				uquad *= pnfssf->f_bsize;
3000 			} else {
3001 				uquad = (u_int64_t)fs->f_blocks;
3002 				uquad *= fs->f_bsize;
3003 			}
3004 			txdr_hyper(uquad, tl);
3005 			retnum += NFSX_HYPER;
3006 			break;
3007 		case NFSATTRBIT_SPACEUSED:
3008 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3009 			txdr_hyper(vap->va_bytes, tl);
3010 			retnum += NFSX_HYPER;
3011 			break;
3012 		case NFSATTRBIT_TIMEACCESS:
3013 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3014 			txdr_nfsv4time(&vap->va_atime, tl);
3015 			retnum += NFSX_V4TIME;
3016 			break;
3017 		case NFSATTRBIT_TIMEACCESSSET:
3018 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
3019 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
3020 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
3021 				txdr_nfsv4time(&vap->va_atime, tl);
3022 				retnum += NFSX_V4SETTIME;
3023 			} else {
3024 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3025 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
3026 				retnum += NFSX_UNSIGNED;
3027 			}
3028 			break;
3029 		case NFSATTRBIT_TIMEDELTA:
3030 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3031 			temptime.tv_sec = 0;
3032 			temptime.tv_nsec = 1000000000 / hz;
3033 			txdr_nfsv4time(&temptime, tl);
3034 			retnum += NFSX_V4TIME;
3035 			break;
3036 		case NFSATTRBIT_TIMEMETADATA:
3037 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3038 			txdr_nfsv4time(&vap->va_ctime, tl);
3039 			retnum += NFSX_V4TIME;
3040 			break;
3041 		case NFSATTRBIT_TIMEMODIFY:
3042 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3043 			txdr_nfsv4time(&vap->va_mtime, tl);
3044 			retnum += NFSX_V4TIME;
3045 			break;
3046 		case NFSATTRBIT_TIMECREATE:
3047 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3048 			txdr_nfsv4time(&vap->va_birthtime, tl);
3049 			retnum += NFSX_V4TIME;
3050 			break;
3051 		case NFSATTRBIT_TIMEMODIFYSET:
3052 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
3053 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
3054 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
3055 				txdr_nfsv4time(&vap->va_mtime, tl);
3056 				retnum += NFSX_V4SETTIME;
3057 			} else {
3058 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3059 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
3060 				retnum += NFSX_UNSIGNED;
3061 			}
3062 			break;
3063 		case NFSATTRBIT_MOUNTEDONFILEID:
3064 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3065 			if (at_root != 0)
3066 				uquad = mounted_on_fileno;
3067 			else
3068 				uquad = vap->va_fileid;
3069 			txdr_hyper(uquad, tl);
3070 			retnum += NFSX_HYPER;
3071 			break;
3072 		case NFSATTRBIT_SUPPATTREXCLCREAT:
3073 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
3074 			NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
3075 			NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
3076 			retnum += nfsrv_putattrbit(nd, &attrbits);
3077 			break;
3078 		case NFSATTRBIT_FSLAYOUTTYPE:
3079 		case NFSATTRBIT_LAYOUTTYPE:
3080 			if (nfsrv_devidcnt == 0)
3081 				siz = 1;
3082 			else
3083 				siz = 2;
3084 			if (siz == 2) {
3085 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3086 				*tl++ = txdr_unsigned(1);	/* One entry. */
3087 				if (nfsrv_doflexfile != 0 ||
3088 				    nfsrv_maxpnfsmirror > 1)
3089 					*tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3090 				else
3091 					*tl = txdr_unsigned(
3092 					    NFSLAYOUT_NFSV4_1_FILES);
3093 			} else {
3094 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3095 				*tl = 0;
3096 			}
3097 			retnum += siz * NFSX_UNSIGNED;
3098 			break;
3099 		case NFSATTRBIT_LAYOUTALIGNMENT:
3100 		case NFSATTRBIT_LAYOUTBLKSIZE:
3101 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3102 			*tl = txdr_unsigned(nfs_srvmaxio);
3103 			retnum += NFSX_UNSIGNED;
3104 			break;
3105 		case NFSATTRBIT_XATTRSUPPORT:
3106 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3107 			if (xattrsupp)
3108 				*tl = newnfs_true;
3109 			else
3110 				*tl = newnfs_false;
3111 			retnum += NFSX_UNSIGNED;
3112 			break;
3113 		default:
3114 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3115 		}
3116 	    }
3117 	}
3118 	if (naclp != NULL)
3119 		acl_free(naclp);
3120 	free(fs, M_STATFS);
3121 	*retnump = txdr_unsigned(retnum);
3122 	return (retnum + prefixnum);
3123 }
3124 
3125 /*
3126  * Calculate the files available attribute value.
3127  */
3128 static uint32_t
3129 nfsv4_filesavail(struct statfs *fs, struct mount *mp)
3130 {
3131 	uint32_t freenum;
3132 #ifdef QUOTA
3133 	struct dqblk dqb;
3134 	uid_t savuid;
3135 	NFSPROC_T *p;
3136 #endif
3137 
3138 	/*
3139 	 * Check quota and use min(quota, f_ffree).
3140 	 */
3141 	freenum = fs->f_ffree;
3142 #ifdef QUOTA
3143 	/*
3144 	 * This is old OpenBSD code that does not build
3145 	 * for FreeBSD.  I do not know if doing this is
3146 	 * useful, so I will just leave the code here.
3147 	 */
3148 	p = curthread();
3149 	/*
3150 	 * ufs_quotactl() insists that the uid argument
3151 	 * equal p_ruid for non-root quota access, so
3152 	 * we'll just make sure that's the case.
3153 	 */
3154 	savuid = p->p_cred->p_ruid;
3155 	p->p_cred->p_ruid = cred->cr_uid;
3156 	if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3157 	    cred->cr_uid, &dqb))
3158 	    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
3159 		freenum);
3160 	p->p_cred->p_ruid = savuid;
3161 #endif	/* QUOTA */
3162 	return (freenum);
3163 }
3164 
3165 /*
3166  * Put the attribute bits onto an mbuf list.
3167  * Return the number of bytes of output generated.
3168  */
3169 int
3170 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3171 {
3172 	u_int32_t *tl;
3173 	int cnt, i, bytesize;
3174 
3175 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3176 		if (attrbitp->bits[cnt - 1])
3177 			break;
3178 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3179 	NFSM_BUILD(tl, u_int32_t *, bytesize);
3180 	*tl++ = txdr_unsigned(cnt);
3181 	for (i = 0; i < cnt; i++)
3182 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
3183 	return (bytesize);
3184 }
3185 
3186 /*
3187  * Put the operation bits onto an mbuf list.
3188  * Return the number of bytes of output generated.
3189  */
3190 int
3191 nfsrv_putopbit(struct nfsrv_descript *nd, nfsopbit_t *opbitp)
3192 {
3193 	uint32_t *tl;
3194 	int cnt, i, bytesize;
3195 
3196 	for (cnt = NFSOPBIT_MAXWORDS; cnt > 0; cnt--)
3197 		if (opbitp->bits[cnt - 1])
3198 			break;
3199 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3200 	NFSM_BUILD(tl, uint32_t *, bytesize);
3201 	*tl++ = txdr_unsigned(cnt);
3202 	for (i = 0; i < cnt; i++)
3203 		*tl++ = txdr_unsigned(opbitp->bits[i]);
3204 	return (bytesize);
3205 }
3206 
3207 /*
3208  * Convert a uid to a string.
3209  * If the lookup fails, just output the digits.
3210  * uid - the user id
3211  * cpp - points to a buffer of size NFSV4_SMALLSTR
3212  *       (malloc a larger one, as required)
3213  * retlenp - pointer to length to be returned
3214  */
3215 void
3216 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3217 {
3218 	int i;
3219 	struct nfsusrgrp *usrp;
3220 	u_char *cp = *cpp;
3221 	uid_t tmp;
3222 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3223 	struct nfsrv_lughash *hp;
3224 
3225 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3226 	cnt = 0;
3227 tryagain:
3228 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3229 	    !NFSD_VNET(nfs_enable_uidtostring)) {
3230 		/*
3231 		 * Always map nfsrv_defaultuid to "nobody".
3232 		 */
3233 		if (uid == NFSD_VNET(nfsrv_defaultuid)) {
3234 			i = NFSD_VNET(nfsrv_dnsnamelen) + 7;
3235 			if (i > len) {
3236 				if (len > NFSV4_SMALLSTR)
3237 					free(cp, M_NFSSTRING);
3238 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3239 				*cpp = cp;
3240 				len = i;
3241 				goto tryagain;
3242 			}
3243 			*retlenp = i;
3244 			NFSBCOPY("nobody@", cp, 7);
3245 			cp += 7;
3246 			NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3247 			    NFSD_VNET(nfsrv_dnsnamelen));
3248 			NFSD_CURVNET_RESTORE();
3249 			return;
3250 		}
3251 		hasampersand = 0;
3252 		hp = NFSUSERHASH(uid);
3253 		mtx_lock(&hp->mtx);
3254 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3255 			if (usrp->lug_uid == uid) {
3256 				if (usrp->lug_expiry < NFSD_MONOSEC)
3257 					break;
3258 				/*
3259 				 * If the name doesn't already have an '@'
3260 				 * in it, append @domainname to it.
3261 				 */
3262 				for (i = 0; i < usrp->lug_namelen; i++) {
3263 					if (usrp->lug_name[i] == '@') {
3264 						hasampersand = 1;
3265 						break;
3266 					}
3267 				}
3268 				if (hasampersand)
3269 					i = usrp->lug_namelen;
3270 				else
3271 					i = usrp->lug_namelen +
3272 					    NFSD_VNET(nfsrv_dnsnamelen) + 1;
3273 				if (i > len) {
3274 					mtx_unlock(&hp->mtx);
3275 					if (len > NFSV4_SMALLSTR)
3276 						free(cp, M_NFSSTRING);
3277 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3278 					*cpp = cp;
3279 					len = i;
3280 					goto tryagain;
3281 				}
3282 				*retlenp = i;
3283 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3284 				if (!hasampersand) {
3285 					cp += usrp->lug_namelen;
3286 					*cp++ = '@';
3287 					NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3288 					    NFSD_VNET(nfsrv_dnsnamelen));
3289 				}
3290 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3291 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3292 				    lug_numhash);
3293 				mtx_unlock(&hp->mtx);
3294 				NFSD_CURVNET_RESTORE();
3295 				return;
3296 			}
3297 		}
3298 		mtx_unlock(&hp->mtx);
3299 		cnt++;
3300 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3301 		if (ret == 0 && cnt < 2)
3302 			goto tryagain;
3303 	}
3304 
3305 	/*
3306 	 * No match, just return a string of digits.
3307 	 */
3308 	tmp = uid;
3309 	i = 0;
3310 	while (tmp || i == 0) {
3311 		tmp /= 10;
3312 		i++;
3313 	}
3314 	len = (i > len) ? len : i;
3315 	*retlenp = len;
3316 	cp += (len - 1);
3317 	tmp = uid;
3318 	for (i = 0; i < len; i++) {
3319 		*cp-- = '0' + (tmp % 10);
3320 		tmp /= 10;
3321 	}
3322 	NFSD_CURVNET_RESTORE();
3323 	return;
3324 }
3325 
3326 /*
3327  * Get a credential for the uid with the server's group list.
3328  * If none is found, just return the credential passed in after
3329  * logging a warning message.
3330  */
3331 struct ucred *
3332 nfsrv_getgrpscred(struct ucred *oldcred)
3333 {
3334 	struct nfsusrgrp *usrp;
3335 	struct ucred *newcred;
3336 	int cnt, ret;
3337 	uid_t uid;
3338 	struct nfsrv_lughash *hp;
3339 
3340 	cnt = 0;
3341 	uid = oldcred->cr_uid;
3342 tryagain:
3343 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3344 		hp = NFSUSERHASH(uid);
3345 		mtx_lock(&hp->mtx);
3346 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3347 			if (usrp->lug_uid == uid) {
3348 				if (usrp->lug_expiry < NFSD_MONOSEC)
3349 					break;
3350 				if (usrp->lug_cred != NULL) {
3351 					newcred = crhold(usrp->lug_cred);
3352 					crfree(oldcred);
3353 				} else
3354 					newcred = oldcred;
3355 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3356 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3357 				    lug_numhash);
3358 				mtx_unlock(&hp->mtx);
3359 				return (newcred);
3360 			}
3361 		}
3362 		mtx_unlock(&hp->mtx);
3363 		cnt++;
3364 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3365 		if (ret == 0 && cnt < 2)
3366 			goto tryagain;
3367 	}
3368 	return (oldcred);
3369 }
3370 
3371 /*
3372  * Convert a string to a uid.
3373  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3374  * return 0.
3375  * If this is called from a client side mount using AUTH_SYS and the
3376  * string is made up entirely of digits, just convert the string to
3377  * a number.
3378  */
3379 int
3380 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3381 {
3382 	int i;
3383 	char *cp, *endstr, *str0;
3384 	struct nfsusrgrp *usrp;
3385 	int cnt, ret;
3386 	int error = 0;
3387 	uid_t tuid;
3388 	struct nfsrv_lughash *hp, *hp2;
3389 
3390 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3391 	if (len == 0) {
3392 		error = NFSERR_BADOWNER;
3393 		goto out;
3394 	}
3395 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3396 	str0 = str;
3397 	tuid = (uid_t)strtoul(str0, &endstr, 10);
3398 	if ((endstr - str0) == len) {
3399 		/* A numeric string. */
3400 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3401 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3402 		      NFSD_VNET(nfsd_enable_stringtouid) != 0))
3403 			*uidp = tuid;
3404 		else
3405 			error = NFSERR_BADOWNER;
3406 		goto out;
3407 	}
3408 	/*
3409 	 * Look for an '@'.
3410 	 */
3411 	cp = strchr(str0, '@');
3412 	if (cp != NULL)
3413 		i = (int)(cp++ - str0);
3414 	else
3415 		i = len;
3416 
3417 	cnt = 0;
3418 tryagain:
3419 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3420 		/*
3421 		 * If an '@' is found and the domain name matches, search for
3422 		 * the name with dns stripped off.
3423 		 * Mixed case alpahbetics will match for the domain name, but
3424 		 * all upper case will not.
3425 		 */
3426 		if (cnt == 0 && i < len && i > 0 &&
3427 		    (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
3428 		    !nfsrv_cmpmixedcase(cp,
3429 		     NFSD_VNET(nfsrv_dnsname), NFSD_VNET(nfsrv_dnsnamelen))) {
3430 			len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
3431 			*(cp - 1) = '\0';
3432 		}
3433 
3434 		/*
3435 		 * Check for the special case of "nobody".
3436 		 */
3437 		if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3438 			*uidp = NFSD_VNET(nfsrv_defaultuid);
3439 			error = 0;
3440 			goto out;
3441 		}
3442 
3443 		hp = NFSUSERNAMEHASH(str, len);
3444 		mtx_lock(&hp->mtx);
3445 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3446 			if (usrp->lug_namelen == len &&
3447 			    !NFSBCMP(usrp->lug_name, str, len)) {
3448 				if (usrp->lug_expiry < NFSD_MONOSEC)
3449 					break;
3450 				hp2 = NFSUSERHASH(usrp->lug_uid);
3451 				mtx_lock(&hp2->mtx);
3452 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3453 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3454 				    lug_numhash);
3455 				*uidp = usrp->lug_uid;
3456 				mtx_unlock(&hp2->mtx);
3457 				mtx_unlock(&hp->mtx);
3458 				error = 0;
3459 				goto out;
3460 			}
3461 		}
3462 		mtx_unlock(&hp->mtx);
3463 		cnt++;
3464 		ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3465 		    str);
3466 		if (ret == 0 && cnt < 2)
3467 			goto tryagain;
3468 	}
3469 	error = NFSERR_BADOWNER;
3470 
3471 out:
3472 	NFSD_CURVNET_RESTORE();
3473 	NFSEXITCODE(error);
3474 	return (error);
3475 }
3476 
3477 /*
3478  * Convert a gid to a string.
3479  * gid - the group id
3480  * cpp - points to a buffer of size NFSV4_SMALLSTR
3481  *       (malloc a larger one, as required)
3482  * retlenp - pointer to length to be returned
3483  */
3484 void
3485 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3486 {
3487 	int i;
3488 	struct nfsusrgrp *usrp;
3489 	u_char *cp = *cpp;
3490 	gid_t tmp;
3491 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3492 	struct nfsrv_lughash *hp;
3493 
3494 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3495 	cnt = 0;
3496 tryagain:
3497 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3498 	    !NFSD_VNET(nfs_enable_uidtostring)) {
3499 		/*
3500 		 * Always map nfsrv_defaultgid to "nogroup".
3501 		 */
3502 		if (gid == NFSD_VNET(nfsrv_defaultgid)) {
3503 			i = NFSD_VNET(nfsrv_dnsnamelen) + 8;
3504 			if (i > len) {
3505 				if (len > NFSV4_SMALLSTR)
3506 					free(cp, M_NFSSTRING);
3507 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3508 				*cpp = cp;
3509 				len = i;
3510 				goto tryagain;
3511 			}
3512 			*retlenp = i;
3513 			NFSBCOPY("nogroup@", cp, 8);
3514 			cp += 8;
3515 			NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3516 			    NFSD_VNET(nfsrv_dnsnamelen));
3517 			NFSD_CURVNET_RESTORE();
3518 			return;
3519 		}
3520 		hasampersand = 0;
3521 		hp = NFSGROUPHASH(gid);
3522 		mtx_lock(&hp->mtx);
3523 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3524 			if (usrp->lug_gid == gid) {
3525 				if (usrp->lug_expiry < NFSD_MONOSEC)
3526 					break;
3527 				/*
3528 				 * If the name doesn't already have an '@'
3529 				 * in it, append @domainname to it.
3530 				 */
3531 				for (i = 0; i < usrp->lug_namelen; i++) {
3532 					if (usrp->lug_name[i] == '@') {
3533 						hasampersand = 1;
3534 						break;
3535 					}
3536 				}
3537 				if (hasampersand)
3538 					i = usrp->lug_namelen;
3539 				else
3540 					i = usrp->lug_namelen +
3541 					    NFSD_VNET(nfsrv_dnsnamelen) + 1;
3542 				if (i > len) {
3543 					mtx_unlock(&hp->mtx);
3544 					if (len > NFSV4_SMALLSTR)
3545 						free(cp, M_NFSSTRING);
3546 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3547 					*cpp = cp;
3548 					len = i;
3549 					goto tryagain;
3550 				}
3551 				*retlenp = i;
3552 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3553 				if (!hasampersand) {
3554 					cp += usrp->lug_namelen;
3555 					*cp++ = '@';
3556 					NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3557 					    NFSD_VNET(nfsrv_dnsnamelen));
3558 				}
3559 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3560 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3561 				    lug_numhash);
3562 				mtx_unlock(&hp->mtx);
3563 				NFSD_CURVNET_RESTORE();
3564 				return;
3565 			}
3566 		}
3567 		mtx_unlock(&hp->mtx);
3568 		cnt++;
3569 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3570 		if (ret == 0 && cnt < 2)
3571 			goto tryagain;
3572 	}
3573 
3574 	/*
3575 	 * No match, just return a string of digits.
3576 	 */
3577 	tmp = gid;
3578 	i = 0;
3579 	while (tmp || i == 0) {
3580 		tmp /= 10;
3581 		i++;
3582 	}
3583 	len = (i > len) ? len : i;
3584 	*retlenp = len;
3585 	cp += (len - 1);
3586 	tmp = gid;
3587 	for (i = 0; i < len; i++) {
3588 		*cp-- = '0' + (tmp % 10);
3589 		tmp /= 10;
3590 	}
3591 	NFSD_CURVNET_RESTORE();
3592 	return;
3593 }
3594 
3595 /*
3596  * Convert a string to a gid.
3597  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3598  * return 0.
3599  * If this is called from a client side mount using AUTH_SYS and the
3600  * string is made up entirely of digits, just convert the string to
3601  * a number.
3602  */
3603 int
3604 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3605 {
3606 	int i;
3607 	char *cp, *endstr, *str0;
3608 	struct nfsusrgrp *usrp;
3609 	int cnt, ret;
3610 	int error = 0;
3611 	gid_t tgid;
3612 	struct nfsrv_lughash *hp, *hp2;
3613 
3614 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3615 	if (len == 0) {
3616 		error =  NFSERR_BADOWNER;
3617 		goto out;
3618 	}
3619 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3620 	str0 = str;
3621 	tgid = (gid_t)strtoul(str0, &endstr, 10);
3622 	if ((endstr - str0) == len) {
3623 		/* A numeric string. */
3624 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3625 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3626 		      NFSD_VNET(nfsd_enable_stringtouid) != 0))
3627 			*gidp = tgid;
3628 		else
3629 			error = NFSERR_BADOWNER;
3630 		goto out;
3631 	}
3632 	/*
3633 	 * Look for an '@'.
3634 	 */
3635 	cp = strchr(str0, '@');
3636 	if (cp != NULL)
3637 		i = (int)(cp++ - str0);
3638 	else
3639 		i = len;
3640 
3641 	cnt = 0;
3642 tryagain:
3643 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3644 		/*
3645 		 * If an '@' is found and the dns name matches, search for the
3646 		 * name with the dns stripped off.
3647 		 */
3648 		if (cnt == 0 && i < len && i > 0 &&
3649 		    (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
3650 		    !nfsrv_cmpmixedcase(cp,
3651 		     NFSD_VNET(nfsrv_dnsname), NFSD_VNET(nfsrv_dnsnamelen))) {
3652 			len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
3653 			*(cp - 1) = '\0';
3654 		}
3655 
3656 		/*
3657 		 * Check for the special case of "nogroup".
3658 		 */
3659 		if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3660 			*gidp = NFSD_VNET(nfsrv_defaultgid);
3661 			error = 0;
3662 			goto out;
3663 		}
3664 
3665 		hp = NFSGROUPNAMEHASH(str, len);
3666 		mtx_lock(&hp->mtx);
3667 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3668 			if (usrp->lug_namelen == len &&
3669 			    !NFSBCMP(usrp->lug_name, str, len)) {
3670 				if (usrp->lug_expiry < NFSD_MONOSEC)
3671 					break;
3672 				hp2 = NFSGROUPHASH(usrp->lug_gid);
3673 				mtx_lock(&hp2->mtx);
3674 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3675 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3676 				    lug_numhash);
3677 				*gidp = usrp->lug_gid;
3678 				mtx_unlock(&hp2->mtx);
3679 				mtx_unlock(&hp->mtx);
3680 				error = 0;
3681 				goto out;
3682 			}
3683 		}
3684 		mtx_unlock(&hp->mtx);
3685 		cnt++;
3686 		ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3687 		    str);
3688 		if (ret == 0 && cnt < 2)
3689 			goto tryagain;
3690 	}
3691 	error = NFSERR_BADOWNER;
3692 
3693 out:
3694 	NFSD_CURVNET_RESTORE();
3695 	NFSEXITCODE(error);
3696 	return (error);
3697 }
3698 
3699 /*
3700  * Cmp len chars, allowing mixed case in the first argument to match lower
3701  * case in the second, but not if the first argument is all upper case.
3702  * Return 0 for a match, 1 otherwise.
3703  */
3704 static int
3705 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3706 {
3707 	int i;
3708 	u_char tmp;
3709 	int fndlower = 0;
3710 
3711 	for (i = 0; i < len; i++) {
3712 		if (*cp >= 'A' && *cp <= 'Z') {
3713 			tmp = *cp++ + ('a' - 'A');
3714 		} else {
3715 			tmp = *cp++;
3716 			if (tmp >= 'a' && tmp <= 'z')
3717 				fndlower = 1;
3718 		}
3719 		if (tmp != *cp2++)
3720 			return (1);
3721 	}
3722 	if (fndlower)
3723 		return (0);
3724 	else
3725 		return (1);
3726 }
3727 
3728 /*
3729  * Set the port for the nfsuserd.
3730  */
3731 int
3732 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3733 {
3734 	struct nfssockreq *rp;
3735 #ifdef INET
3736 	struct sockaddr_in *ad;
3737 #endif
3738 #ifdef INET6
3739 	struct sockaddr_in6 *ad6;
3740 	const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3741 #endif
3742 	int error;
3743 
3744 	NFSLOCKNAMEID();
3745 	if (NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING) {
3746 		NFSUNLOCKNAMEID();
3747 		error = EPERM;
3748 		goto out;
3749 	}
3750 	NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
3751 	/*
3752 	 * Set up the socket record and connect.
3753 	 * Set nr_client NULL before unlocking, just to ensure that no other
3754 	 * process/thread/core will use a bogus old value.  This could only
3755 	 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3756 	 * broken.
3757 	 */
3758 	rp = &NFSD_VNET(nfsrv_nfsuserdsock);
3759 	rp->nr_client = NULL;
3760 	NFSUNLOCKNAMEID();
3761 	rp->nr_sotype = SOCK_DGRAM;
3762 	rp->nr_soproto = IPPROTO_UDP;
3763 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3764 	rp->nr_cred = NULL;
3765 	rp->nr_prog = RPCPROG_NFSUSERD;
3766 	error = 0;
3767 	switch (nargs->nuserd_family) {
3768 #ifdef INET
3769 	case AF_INET:
3770 		rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3771 		    M_WAITOK | M_ZERO);
3772  		ad = (struct sockaddr_in *)rp->nr_nam;
3773 		ad->sin_len = sizeof(struct sockaddr_in);
3774  		ad->sin_family = AF_INET;
3775 		ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3776 		ad->sin_port = nargs->nuserd_port;
3777 		break;
3778 #endif
3779 #ifdef INET6
3780 	case AF_INET6:
3781 		rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3782 		    M_WAITOK | M_ZERO);
3783 		ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3784 		ad6->sin6_len = sizeof(struct sockaddr_in6);
3785 		ad6->sin6_family = AF_INET6;
3786 		ad6->sin6_addr = in6loopback;
3787 		ad6->sin6_port = nargs->nuserd_port;
3788 		break;
3789 #endif
3790 	default:
3791 		error = ENXIO;
3792  	}
3793 	rp->nr_vers = RPCNFSUSERD_VERS;
3794 	if (error == 0)
3795 		error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false,
3796 		    &rp->nr_client);
3797 	if (error == 0) {
3798 		NFSLOCKNAMEID();
3799 		NFSD_VNET(nfsrv_nfsuserd) = RUNNING;
3800 		NFSUNLOCKNAMEID();
3801 	} else {
3802 		free(rp->nr_nam, M_SONAME);
3803 		NFSLOCKNAMEID();
3804 		NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
3805 		NFSUNLOCKNAMEID();
3806 	}
3807 out:
3808 	NFSEXITCODE(error);
3809 	return (error);
3810 }
3811 
3812 /*
3813  * Delete the nfsuserd port.
3814  */
3815 void
3816 nfsrv_nfsuserddelport(void)
3817 {
3818 
3819 	NFSLOCKNAMEID();
3820 	if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
3821 		NFSUNLOCKNAMEID();
3822 		return;
3823 	}
3824 	NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
3825 	/* Wait for all upcalls to complete. */
3826 	while (NFSD_VNET(nfsrv_userdupcalls) > 0)
3827 		msleep(&NFSD_VNET(nfsrv_userdupcalls), NFSNAMEIDMUTEXPTR, PVFS,
3828 		    "nfsupcalls", 0);
3829 	NFSUNLOCKNAMEID();
3830 	newnfs_disconnect(NULL, &NFSD_VNET(nfsrv_nfsuserdsock));
3831 	free(NFSD_VNET(nfsrv_nfsuserdsock).nr_nam, M_SONAME);
3832 	NFSLOCKNAMEID();
3833 	NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
3834 	NFSUNLOCKNAMEID();
3835 }
3836 
3837 /*
3838  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3839  * name<-->id cache.
3840  * Returns 0 upon success, non-zero otherwise.
3841  */
3842 static int
3843 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3844 {
3845 	u_int32_t *tl;
3846 	struct nfsrv_descript *nd;
3847 	int len;
3848 	struct nfsrv_descript nfsd;
3849 	struct ucred *cred;
3850 	int error;
3851 
3852 	NFSLOCKNAMEID();
3853 	if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
3854 		NFSUNLOCKNAMEID();
3855 		error = EPERM;
3856 		goto out;
3857 	}
3858 	/*
3859 	 * Maintain a count of upcalls in progress, so that nfsrv_X()
3860 	 * can wait until no upcalls are in progress.
3861 	 */
3862 	NFSD_VNET(nfsrv_userdupcalls)++;
3863 	NFSUNLOCKNAMEID();
3864 	KASSERT(NFSD_VNET(nfsrv_userdupcalls) > 0,
3865 	    ("nfsrv_getuser: non-positive upcalls"));
3866 	nd = &nfsd;
3867 	cred = newnfs_getcred();
3868 	nd->nd_flag = ND_GSSINITREPLY;
3869 	nfsrvd_rephead(nd);
3870 
3871 	nd->nd_procnum = procnum;
3872 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3873 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3874 		if (procnum == RPCNFSUSERD_GETUID)
3875 			*tl = txdr_unsigned(uid);
3876 		else
3877 			*tl = txdr_unsigned(gid);
3878 	} else {
3879 		len = strlen(name);
3880 		(void) nfsm_strtom(nd, name, len);
3881 	}
3882 	error = newnfs_request(nd, NULL, NULL, &NFSD_VNET(nfsrv_nfsuserdsock),
3883 	    NULL, NULL, cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0,
3884 	    NULL, NULL);
3885 	NFSLOCKNAMEID();
3886 	if (--NFSD_VNET(nfsrv_userdupcalls) == 0 &&
3887 	    NFSD_VNET(nfsrv_nfsuserd) == STARTSTOP)
3888 		wakeup(&NFSD_VNET(nfsrv_userdupcalls));
3889 	NFSUNLOCKNAMEID();
3890 	NFSFREECRED(cred);
3891 	if (!error) {
3892 		m_freem(nd->nd_mrep);
3893 		error = nd->nd_repstat;
3894 	}
3895 out:
3896 	NFSEXITCODE(error);
3897 	return (error);
3898 }
3899 
3900 /*
3901  * This function is called from the nfssvc(2) system call, to update the
3902  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3903  */
3904 int
3905 nfssvc_idname(struct nfsd_idargs *nidp)
3906 {
3907 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
3908 	struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3909 	int i, group_locked, groupname_locked, user_locked, username_locked;
3910 	int error = 0;
3911 	u_char *cp;
3912 	gid_t *grps;
3913 	struct ucred *cr;
3914 	static int onethread = 0;
3915 	static time_t lasttime = 0;
3916 
3917 	if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3918 		error = EINVAL;
3919 		goto out;
3920 	}
3921 	if (nidp->nid_flag & NFSID_INITIALIZE) {
3922 		cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3923 		error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3924 		if (error != 0) {
3925 			free(cp, M_NFSSTRING);
3926 			goto out;
3927 		}
3928 		if (atomic_cmpset_acq_int(&NFSD_VNET(nfsrv_dnsnamelen), 0, 0) ==
3929 		    0) {
3930 			/*
3931 			 * Free up all the old stuff and reinitialize hash
3932 			 * lists.  All mutexes for both lists must be locked,
3933 			 * with the user/group name ones before the uid/gid
3934 			 * ones, to avoid a LOR.
3935 			 */
3936 			for (i = 0; i < nfsrv_lughashsize; i++)
3937 				mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
3938 			for (i = 0; i < nfsrv_lughashsize; i++)
3939 				mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
3940 			for (i = 0; i < nfsrv_lughashsize; i++)
3941 				TAILQ_FOREACH_SAFE(usrp,
3942 				    &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, nusrp)
3943 					nfsrv_removeuser(usrp, 1);
3944 			for (i = 0; i < nfsrv_lughashsize; i++)
3945 				mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
3946 			for (i = 0; i < nfsrv_lughashsize; i++)
3947 				mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
3948 			for (i = 0; i < nfsrv_lughashsize; i++)
3949 				mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
3950 			for (i = 0; i < nfsrv_lughashsize; i++)
3951 				mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
3952 			for (i = 0; i < nfsrv_lughashsize; i++)
3953 				TAILQ_FOREACH_SAFE(usrp,
3954 				    &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
3955 				    nusrp)
3956 					nfsrv_removeuser(usrp, 0);
3957 			for (i = 0; i < nfsrv_lughashsize; i++)
3958 				mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
3959 			for (i = 0; i < nfsrv_lughashsize; i++)
3960 				mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
3961 			free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
3962 			NFSD_VNET(nfsrv_dnsname) = NULL;
3963 		}
3964 		if (NFSD_VNET(nfsuserhash) == NULL) {
3965 			/* Allocate the hash tables. */
3966 			NFSD_VNET(nfsuserhash) = malloc(sizeof(struct nfsrv_lughash) *
3967 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3968 			    M_ZERO);
3969 			for (i = 0; i < nfsrv_lughashsize; i++)
3970 				mtx_init(&NFSD_VNET(nfsuserhash)[i].mtx, "nfsuidhash",
3971 				    NULL, MTX_DEF | MTX_DUPOK);
3972 			NFSD_VNET(nfsusernamehash) = malloc(sizeof(struct nfsrv_lughash) *
3973 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3974 			    M_ZERO);
3975 			for (i = 0; i < nfsrv_lughashsize; i++)
3976 				mtx_init(&NFSD_VNET(nfsusernamehash)[i].mtx,
3977 				    "nfsusrhash", NULL, MTX_DEF |
3978 				    MTX_DUPOK);
3979 			NFSD_VNET(nfsgrouphash) = malloc(sizeof(struct nfsrv_lughash) *
3980 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3981 			    M_ZERO);
3982 			for (i = 0; i < nfsrv_lughashsize; i++)
3983 				mtx_init(&NFSD_VNET(nfsgrouphash)[i].mtx, "nfsgidhash",
3984 				    NULL, MTX_DEF | MTX_DUPOK);
3985 			NFSD_VNET(nfsgroupnamehash) = malloc(sizeof(struct nfsrv_lughash) *
3986 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3987 			    M_ZERO);
3988 			for (i = 0; i < nfsrv_lughashsize; i++)
3989 			    mtx_init(&NFSD_VNET(nfsgroupnamehash)[i].mtx,
3990 			    "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3991 		}
3992 		/* (Re)initialize the list heads. */
3993 		for (i = 0; i < nfsrv_lughashsize; i++)
3994 			TAILQ_INIT(&NFSD_VNET(nfsuserhash)[i].lughead);
3995 		for (i = 0; i < nfsrv_lughashsize; i++)
3996 			TAILQ_INIT(&NFSD_VNET(nfsusernamehash)[i].lughead);
3997 		for (i = 0; i < nfsrv_lughashsize; i++)
3998 			TAILQ_INIT(&NFSD_VNET(nfsgrouphash)[i].lughead);
3999 		for (i = 0; i < nfsrv_lughashsize; i++)
4000 			TAILQ_INIT(&NFSD_VNET(nfsgroupnamehash)[i].lughead);
4001 
4002 		/*
4003 		 * Put name in "DNS" string.
4004 		 */
4005 		NFSD_VNET(nfsrv_dnsname) = cp;
4006 		NFSD_VNET(nfsrv_defaultuid) = nidp->nid_uid;
4007 		NFSD_VNET(nfsrv_defaultgid) = nidp->nid_gid;
4008 		NFSD_VNET(nfsrv_usercnt) = 0;
4009 		NFSD_VNET(nfsrv_usermax) = nidp->nid_usermax;
4010 		atomic_store_rel_int(&NFSD_VNET(nfsrv_dnsnamelen),
4011 		    nidp->nid_namelen);
4012 		goto out;
4013 	}
4014 
4015 	/*
4016 	 * malloc the new one now, so any potential sleep occurs before
4017 	 * manipulation of the lists.
4018 	 */
4019 	newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
4020 	    M_NFSUSERGROUP, M_WAITOK | M_ZERO);
4021 	error = copyin(nidp->nid_name, newusrp->lug_name,
4022 	    nidp->nid_namelen);
4023 	if (error == 0 && nidp->nid_ngroup > 0 &&
4024 	    (nidp->nid_flag & NFSID_ADDUID) != 0) {
4025 		grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
4026 		    M_WAITOK);
4027 		error = copyin(nidp->nid_grps, grps,
4028 		    sizeof(gid_t) * nidp->nid_ngroup);
4029 		if (error == 0) {
4030 			/*
4031 			 * Create a credential just like svc_getcred(),
4032 			 * but using the group list provided.
4033 			 */
4034 			cr = crget();
4035 			cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
4036 			crsetgroups(cr, nidp->nid_ngroup, grps);
4037 			cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
4038 			cr->cr_prison = curthread->td_ucred->cr_prison;
4039 			prison_hold(cr->cr_prison);
4040 #ifdef MAC
4041 			mac_cred_associate_nfsd(cr);
4042 #endif
4043 			newusrp->lug_cred = cr;
4044 		}
4045 		free(grps, M_TEMP);
4046 	}
4047 	if (error) {
4048 		free(newusrp, M_NFSUSERGROUP);
4049 		goto out;
4050 	}
4051 	newusrp->lug_namelen = nidp->nid_namelen;
4052 
4053 	/*
4054 	 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
4055 	 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
4056 	 * The flags user_locked, username_locked, group_locked and
4057 	 * groupname_locked are set to indicate all of those hash lists are
4058 	 * locked. hp_name != NULL  and hp_idnum != NULL indicates that
4059 	 * the respective one mutex is locked.
4060 	 */
4061 	user_locked = username_locked = group_locked = groupname_locked = 0;
4062 	hp_name = hp_idnum = NULL;
4063 
4064 	/*
4065 	 * Delete old entries, as required.
4066 	 */
4067 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
4068 		/* Must lock all username hash lists first, to avoid a LOR. */
4069 		for (i = 0; i < nfsrv_lughashsize; i++)
4070 			mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4071 		username_locked = 1;
4072 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
4073 		mtx_lock(&hp_idnum->mtx);
4074 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
4075 		    nusrp) {
4076 			if (usrp->lug_uid == nidp->nid_uid)
4077 				nfsrv_removeuser(usrp, 1);
4078 		}
4079 	} else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
4080 		hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
4081 		    newusrp->lug_namelen);
4082 		mtx_lock(&hp_name->mtx);
4083 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
4084 		    nusrp) {
4085 			if (usrp->lug_namelen == newusrp->lug_namelen &&
4086 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
4087 			    usrp->lug_namelen)) {
4088 				thp = NFSUSERHASH(usrp->lug_uid);
4089 				mtx_lock(&thp->mtx);
4090 				nfsrv_removeuser(usrp, 1);
4091 				mtx_unlock(&thp->mtx);
4092 			}
4093 		}
4094 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
4095 		mtx_lock(&hp_idnum->mtx);
4096 	} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
4097 		/* Must lock all groupname hash lists first, to avoid a LOR. */
4098 		for (i = 0; i < nfsrv_lughashsize; i++)
4099 			mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4100 		groupname_locked = 1;
4101 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4102 		mtx_lock(&hp_idnum->mtx);
4103 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
4104 		    nusrp) {
4105 			if (usrp->lug_gid == nidp->nid_gid)
4106 				nfsrv_removeuser(usrp, 0);
4107 		}
4108 	} else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
4109 		hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
4110 		    newusrp->lug_namelen);
4111 		mtx_lock(&hp_name->mtx);
4112 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
4113 		    nusrp) {
4114 			if (usrp->lug_namelen == newusrp->lug_namelen &&
4115 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
4116 			    usrp->lug_namelen)) {
4117 				thp = NFSGROUPHASH(usrp->lug_gid);
4118 				mtx_lock(&thp->mtx);
4119 				nfsrv_removeuser(usrp, 0);
4120 				mtx_unlock(&thp->mtx);
4121 			}
4122 		}
4123 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4124 		mtx_lock(&hp_idnum->mtx);
4125 	}
4126 
4127 	/*
4128 	 * Now, we can add the new one.
4129 	 */
4130 	if (nidp->nid_usertimeout)
4131 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
4132 	else
4133 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
4134 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
4135 		newusrp->lug_uid = nidp->nid_uid;
4136 		thp = NFSUSERHASH(newusrp->lug_uid);
4137 		mtx_assert(&thp->mtx, MA_OWNED);
4138 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4139 		thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4140 		mtx_assert(&thp->mtx, MA_OWNED);
4141 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4142 		atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
4143 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
4144 		newusrp->lug_gid = nidp->nid_gid;
4145 		thp = NFSGROUPHASH(newusrp->lug_gid);
4146 		mtx_assert(&thp->mtx, MA_OWNED);
4147 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4148 		thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4149 		mtx_assert(&thp->mtx, MA_OWNED);
4150 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4151 		atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
4152 	} else {
4153 		if (newusrp->lug_cred != NULL)
4154 			crfree(newusrp->lug_cred);
4155 		free(newusrp, M_NFSUSERGROUP);
4156 	}
4157 
4158 	/*
4159 	 * Once per second, allow one thread to trim the cache.
4160 	 */
4161 	if (lasttime < NFSD_MONOSEC &&
4162 	    atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4163 		/*
4164 		 * First, unlock the single mutexes, so that all entries
4165 		 * can be locked and any LOR is avoided.
4166 		 */
4167 		if (hp_name != NULL) {
4168 			mtx_unlock(&hp_name->mtx);
4169 			hp_name = NULL;
4170 		}
4171 		if (hp_idnum != NULL) {
4172 			mtx_unlock(&hp_idnum->mtx);
4173 			hp_idnum = NULL;
4174 		}
4175 
4176 		if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4177 		    NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4178 			if (username_locked == 0) {
4179 				for (i = 0; i < nfsrv_lughashsize; i++)
4180 					mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4181 				username_locked = 1;
4182 			}
4183 			KASSERT(user_locked == 0,
4184 			    ("nfssvc_idname: user_locked"));
4185 			for (i = 0; i < nfsrv_lughashsize; i++)
4186 				mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
4187 			user_locked = 1;
4188 			for (i = 0; i < nfsrv_lughashsize; i++) {
4189 				TAILQ_FOREACH_SAFE(usrp,
4190 				    &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash,
4191 				    nusrp)
4192 					if (usrp->lug_expiry < NFSD_MONOSEC)
4193 						nfsrv_removeuser(usrp, 1);
4194 			}
4195 			for (i = 0; i < nfsrv_lughashsize; i++) {
4196 				/*
4197 				 * Trim the cache using an approximate LRU
4198 				 * algorithm.  This code deletes the least
4199 				 * recently used entry on each hash list.
4200 				 */
4201 				if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
4202 					break;
4203 				usrp = TAILQ_FIRST(&NFSD_VNET(nfsuserhash)[i].lughead);
4204 				if (usrp != NULL)
4205 					nfsrv_removeuser(usrp, 1);
4206 			}
4207 		} else {
4208 			if (groupname_locked == 0) {
4209 				for (i = 0; i < nfsrv_lughashsize; i++)
4210 					mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4211 				groupname_locked = 1;
4212 			}
4213 			KASSERT(group_locked == 0,
4214 			    ("nfssvc_idname: group_locked"));
4215 			for (i = 0; i < nfsrv_lughashsize; i++)
4216 				mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4217 			group_locked = 1;
4218 			for (i = 0; i < nfsrv_lughashsize; i++) {
4219 				TAILQ_FOREACH_SAFE(usrp,
4220 				    &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
4221 				    nusrp)
4222 					if (usrp->lug_expiry < NFSD_MONOSEC)
4223 						nfsrv_removeuser(usrp, 0);
4224 			}
4225 			for (i = 0; i < nfsrv_lughashsize; i++) {
4226 				/*
4227 				 * Trim the cache using an approximate LRU
4228 				 * algorithm.  This code deletes the least
4229 				 * recently user entry on each hash list.
4230 				 */
4231 				if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
4232 					break;
4233 				usrp = TAILQ_FIRST(&NFSD_VNET(nfsgrouphash)[i].lughead);
4234 				if (usrp != NULL)
4235 					nfsrv_removeuser(usrp, 0);
4236 			}
4237 		}
4238 		lasttime = NFSD_MONOSEC;
4239 		atomic_store_rel_int(&onethread, 0);
4240 	}
4241 
4242 	/* Now, unlock all locked mutexes. */
4243 	if (hp_idnum != NULL)
4244 		mtx_unlock(&hp_idnum->mtx);
4245 	if (hp_name != NULL)
4246 		mtx_unlock(&hp_name->mtx);
4247 	if (user_locked != 0)
4248 		for (i = 0; i < nfsrv_lughashsize; i++)
4249 			mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
4250 	if (username_locked != 0)
4251 		for (i = 0; i < nfsrv_lughashsize; i++)
4252 			mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4253 	if (group_locked != 0)
4254 		for (i = 0; i < nfsrv_lughashsize; i++)
4255 			mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4256 	if (groupname_locked != 0)
4257 		for (i = 0; i < nfsrv_lughashsize; i++)
4258 			mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4259 out:
4260 	NFSEXITCODE(error);
4261 	return (error);
4262 }
4263 
4264 /*
4265  * Remove a user/group name element.
4266  */
4267 static void
4268 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4269 {
4270 	struct nfsrv_lughash *hp;
4271 
4272 	if (isuser != 0) {
4273 		hp = NFSUSERHASH(usrp->lug_uid);
4274 		mtx_assert(&hp->mtx, MA_OWNED);
4275 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4276 		hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4277 		mtx_assert(&hp->mtx, MA_OWNED);
4278 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4279 	} else {
4280 		hp = NFSGROUPHASH(usrp->lug_gid);
4281 		mtx_assert(&hp->mtx, MA_OWNED);
4282 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4283 		hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4284 		mtx_assert(&hp->mtx, MA_OWNED);
4285 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4286 	}
4287 	atomic_add_int(&NFSD_VNET(nfsrv_usercnt), -1);
4288 	if (usrp->lug_cred != NULL)
4289 		crfree(usrp->lug_cred);
4290 	free(usrp, M_NFSUSERGROUP);
4291 }
4292 
4293 /*
4294  * Free up all the allocations related to the name<-->id cache.
4295  * This function should only be called when the nfsuserd daemon isn't
4296  * running, since it doesn't do any locking.
4297  * This function is meant to be called when a vnet jail is destroyed.
4298  */
4299 void
4300 nfsrv_cleanusergroup(void)
4301 {
4302 	struct nfsrv_lughash *hp, *hp2;
4303 	struct nfsusrgrp *nusrp, *usrp;
4304 	int i;
4305 
4306 	if (NFSD_VNET(nfsuserhash) == NULL)
4307 		return;
4308 
4309 	for (i = 0; i < nfsrv_lughashsize; i++) {
4310 		hp = &NFSD_VNET(nfsuserhash)[i];
4311 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4312 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4313 			hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4314 			    usrp->lug_namelen);
4315 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4316 			if (usrp->lug_cred != NULL)
4317 				crfree(usrp->lug_cred);
4318 			free(usrp, M_NFSUSERGROUP);
4319 		}
4320 		hp = &NFSD_VNET(nfsgrouphash)[i];
4321 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4322 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4323 			hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4324 			    usrp->lug_namelen);
4325 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4326 			if (usrp->lug_cred != NULL)
4327 				crfree(usrp->lug_cred);
4328 			free(usrp, M_NFSUSERGROUP);
4329 		}
4330 		mtx_destroy(&NFSD_VNET(nfsuserhash)[i].mtx);
4331 		mtx_destroy(&NFSD_VNET(nfsusernamehash)[i].mtx);
4332 		mtx_destroy(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4333 		mtx_destroy(&NFSD_VNET(nfsgrouphash)[i].mtx);
4334 	}
4335 	free(NFSD_VNET(nfsuserhash), M_NFSUSERGROUP);
4336 	free(NFSD_VNET(nfsusernamehash), M_NFSUSERGROUP);
4337 	free(NFSD_VNET(nfsgrouphash), M_NFSUSERGROUP);
4338 	free(NFSD_VNET(nfsgroupnamehash), M_NFSUSERGROUP);
4339 	free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
4340 }
4341 
4342 /*
4343  * This function scans a byte string and checks for UTF-8 compliance.
4344  * It returns 0 if it conforms and NFSERR_INVAL if not.
4345  */
4346 int
4347 nfsrv_checkutf8(u_int8_t *cp, int len)
4348 {
4349 	u_int32_t val = 0x0;
4350 	int cnt = 0, gotd = 0, shift = 0;
4351 	u_int8_t byte;
4352 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4353 	int error = 0;
4354 
4355 	/*
4356 	 * Here are what the variables are used for:
4357 	 * val - the calculated value of a multibyte char, used to check
4358 	 *       that it was coded with the correct range
4359 	 * cnt - the number of 10xxxxxx bytes to follow
4360 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4361 	 * shift - lower order bits of range (ie. "val >> shift" should
4362 	 *       not be 0, in other words, dividing by the lower bound
4363 	 *       of the range should get a non-zero value)
4364 	 * byte - used to calculate cnt
4365 	 */
4366 	while (len > 0) {
4367 		if (cnt > 0) {
4368 			/* This handles the 10xxxxxx bytes */
4369 			if ((*cp & 0xc0) != 0x80 ||
4370 			    (gotd && (*cp & 0x20))) {
4371 				error = NFSERR_INVAL;
4372 				goto out;
4373 			}
4374 			gotd = 0;
4375 			val <<= 6;
4376 			val |= (*cp & 0x3f);
4377 			cnt--;
4378 			if (cnt == 0 && (val >> shift) == 0x0) {
4379 				error = NFSERR_INVAL;
4380 				goto out;
4381 			}
4382 		} else if (*cp & 0x80) {
4383 			/* first byte of multi byte char */
4384 			byte = *cp;
4385 			while ((byte & 0x40) && cnt < 6) {
4386 				cnt++;
4387 				byte <<= 1;
4388 			}
4389 			if (cnt == 0 || cnt == 6) {
4390 				error = NFSERR_INVAL;
4391 				goto out;
4392 			}
4393 			val = (*cp & (0x3f >> cnt));
4394 			shift = utf8_shift[cnt - 1];
4395 			if (cnt == 2 && val == 0xd)
4396 				/* Check for the 0xd800-0xdfff case */
4397 				gotd = 1;
4398 		}
4399 		cp++;
4400 		len--;
4401 	}
4402 	if (cnt > 0)
4403 		error = NFSERR_INVAL;
4404 
4405 out:
4406 	NFSEXITCODE(error);
4407 	return (error);
4408 }
4409 
4410 /*
4411  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4412  * strings, one with the root path in it and the other with the list of
4413  * locations. The list is in the same format as is found in nfr_refs.
4414  * It is a "," separated list of entries, where each of them is of the
4415  * form <server>:<rootpath>. For example
4416  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4417  * The nilp argument is set to 1 for the special case of a null fs_root
4418  * and an empty server list.
4419  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4420  * number of xdr bytes parsed in sump.
4421  */
4422 static int
4423 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4424     int *sump, int *nilp)
4425 {
4426 	u_int32_t *tl;
4427 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4428 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4429 	struct list {
4430 		SLIST_ENTRY(list) next;
4431 		int len;
4432 		u_char host[1];
4433 	} *lsp, *nlsp;
4434 	SLIST_HEAD(, list) head;
4435 
4436 	*fsrootp = NULL;
4437 	*srvp = NULL;
4438 	*nilp = 0;
4439 
4440 	/*
4441 	 * Get the fs_root path and check for the special case of null path
4442 	 * and 0 length server list.
4443 	 */
4444 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4445 	len = fxdr_unsigned(int, *tl);
4446 	if (len < 0 || len > 10240) {
4447 		error = NFSERR_BADXDR;
4448 		goto nfsmout;
4449 	}
4450 	if (len == 0) {
4451 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4452 		if (*tl != 0) {
4453 			error = NFSERR_BADXDR;
4454 			goto nfsmout;
4455 		}
4456 		*nilp = 1;
4457 		*sump = 2 * NFSX_UNSIGNED;
4458 		error = 0;
4459 		goto nfsmout;
4460 	}
4461 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4462 	error = nfsrv_mtostr(nd, cp, len);
4463 	if (!error) {
4464 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4465 		cnt = fxdr_unsigned(int, *tl);
4466 		if (cnt <= 0)
4467 			error = NFSERR_BADXDR;
4468 	}
4469 	if (error)
4470 		goto nfsmout;
4471 
4472 	/*
4473 	 * Now, loop through the location list and make up the srvlist.
4474 	 */
4475 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4476 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4477 	slen = 1024;
4478 	siz = 0;
4479 	for (i = 0; i < cnt; i++) {
4480 		SLIST_INIT(&head);
4481 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4482 		nsrv = fxdr_unsigned(int, *tl);
4483 		if (nsrv <= 0) {
4484 			error = NFSERR_BADXDR;
4485 			goto nfsmout;
4486 		}
4487 
4488 		/*
4489 		 * Handle the first server by putting it in the srvstr.
4490 		 */
4491 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4492 		len = fxdr_unsigned(int, *tl);
4493 		if (len <= 0 || len > 1024) {
4494 			error = NFSERR_BADXDR;
4495 			goto nfsmout;
4496 		}
4497 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4498 		if (cp3 != cp2) {
4499 			*cp3++ = ',';
4500 			siz++;
4501 		}
4502 		error = nfsrv_mtostr(nd, cp3, len);
4503 		if (error)
4504 			goto nfsmout;
4505 		cp3 += len;
4506 		*cp3++ = ':';
4507 		siz += (len + 1);
4508 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4509 		for (j = 1; j < nsrv; j++) {
4510 			/*
4511 			 * Yuck, put them in an slist and process them later.
4512 			 */
4513 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4514 			len = fxdr_unsigned(int, *tl);
4515 			if (len <= 0 || len > 1024) {
4516 				error = NFSERR_BADXDR;
4517 				goto nfsmout;
4518 			}
4519 			lsp = (struct list *)malloc(sizeof (struct list)
4520 			    + len, M_TEMP, M_WAITOK);
4521 			error = nfsrv_mtostr(nd, lsp->host, len);
4522 			if (error)
4523 				goto nfsmout;
4524 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4525 			lsp->len = len;
4526 			SLIST_INSERT_HEAD(&head, lsp, next);
4527 		}
4528 
4529 		/*
4530 		 * Finally, we can get the path.
4531 		 */
4532 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4533 		len = fxdr_unsigned(int, *tl);
4534 		if (len <= 0 || len > 1024) {
4535 			error = NFSERR_BADXDR;
4536 			goto nfsmout;
4537 		}
4538 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4539 		error = nfsrv_mtostr(nd, cp3, len);
4540 		if (error)
4541 			goto nfsmout;
4542 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4543 		str = cp3;
4544 		stringlen = len;
4545 		cp3 += len;
4546 		siz += len;
4547 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4548 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4549 			    &cp2, &cp3, &slen);
4550 			*cp3++ = ',';
4551 			NFSBCOPY(lsp->host, cp3, lsp->len);
4552 			cp3 += lsp->len;
4553 			*cp3++ = ':';
4554 			NFSBCOPY(str, cp3, stringlen);
4555 			cp3 += stringlen;
4556 			*cp3 = '\0';
4557 			siz += (lsp->len + stringlen + 2);
4558 			free(lsp, M_TEMP);
4559 		}
4560 	}
4561 	*fsrootp = cp;
4562 	*srvp = cp2;
4563 	*sump = xdrsum;
4564 	NFSEXITCODE2(0, nd);
4565 	return (0);
4566 nfsmout:
4567 	if (cp != NULL)
4568 		free(cp, M_NFSSTRING);
4569 	if (cp2 != NULL)
4570 		free(cp2, M_NFSSTRING);
4571 	NFSEXITCODE2(error, nd);
4572 	return (error);
4573 }
4574 
4575 /*
4576  * Make the malloc'd space large enough. This is a pain, but the xdr
4577  * doesn't set an upper bound on the side, so...
4578  */
4579 static void
4580 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4581 {
4582 	u_char *cp;
4583 	int i;
4584 
4585 	if (siz <= *slenp)
4586 		return;
4587 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4588 	NFSBCOPY(*cpp, cp, *slenp);
4589 	free(*cpp, M_NFSSTRING);
4590 	i = *cpp2 - *cpp;
4591 	*cpp = cp;
4592 	*cpp2 = cp + i;
4593 	*slenp = siz + 1024;
4594 }
4595 
4596 /*
4597  * Initialize the reply header data structures.
4598  */
4599 void
4600 nfsrvd_rephead(struct nfsrv_descript *nd)
4601 {
4602 	struct mbuf *mreq;
4603 
4604 	if ((nd->nd_flag & ND_EXTPG) != 0) {
4605 		mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4606 		nd->nd_mreq = nd->nd_mb = mreq;
4607 		nd->nd_bpos = (char *)(void *)
4608 		    PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4609 		nd->nd_bextpg = 0;
4610 		nd->nd_bextpgsiz = PAGE_SIZE;
4611 	} else {
4612 		/*
4613 		 * If this is a big reply, use a cluster.
4614 		 */
4615 		if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4616 		    nfs_bigreply[nd->nd_procnum]) {
4617 			NFSMCLGET(mreq, M_WAITOK);
4618 			nd->nd_mreq = mreq;
4619 			nd->nd_mb = mreq;
4620 		} else {
4621 			NFSMGET(mreq);
4622 			nd->nd_mreq = mreq;
4623 			nd->nd_mb = mreq;
4624 		}
4625 		nd->nd_bpos = mtod(mreq, char *);
4626 		mreq->m_len = 0;
4627 	}
4628 
4629 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4630 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4631 }
4632 
4633 /*
4634  * Lock a socket against others.
4635  * Currently used to serialize connect/disconnect attempts.
4636  */
4637 int
4638 newnfs_sndlock(int *flagp)
4639 {
4640 	struct timespec ts;
4641 
4642 	NFSLOCKSOCK();
4643 	while (*flagp & NFSR_SNDLOCK) {
4644 		*flagp |= NFSR_WANTSND;
4645 		ts.tv_sec = 0;
4646 		ts.tv_nsec = 0;
4647 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4648 		    PZERO - 1, "nfsndlck", &ts);
4649 	}
4650 	*flagp |= NFSR_SNDLOCK;
4651 	NFSUNLOCKSOCK();
4652 	return (0);
4653 }
4654 
4655 /*
4656  * Unlock the stream socket for others.
4657  */
4658 void
4659 newnfs_sndunlock(int *flagp)
4660 {
4661 
4662 	NFSLOCKSOCK();
4663 	if ((*flagp & NFSR_SNDLOCK) == 0)
4664 		panic("nfs sndunlock");
4665 	*flagp &= ~NFSR_SNDLOCK;
4666 	if (*flagp & NFSR_WANTSND) {
4667 		*flagp &= ~NFSR_WANTSND;
4668 		wakeup((caddr_t)flagp);
4669 	}
4670 	NFSUNLOCKSOCK();
4671 }
4672 
4673 int
4674 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4675     struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4676 {
4677 	struct in_addr saddr;
4678 	uint32_t portnum, *tl;
4679 	int i, j, k;
4680 	sa_family_t af = AF_UNSPEC;
4681 	char addr[64], protocol[5], *cp;
4682 	int cantparse = 0, error = 0;
4683 	uint16_t portv;
4684 
4685 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4686 	i = fxdr_unsigned(int, *tl);
4687 	if (i >= 3 && i <= 4) {
4688 		error = nfsrv_mtostr(nd, protocol, i);
4689 		if (error)
4690 			goto nfsmout;
4691 		if (strcmp(protocol, "tcp") == 0) {
4692 			af = AF_INET;
4693 			*isudp = 0;
4694 		} else if (strcmp(protocol, "udp") == 0) {
4695 			af = AF_INET;
4696 			*isudp = 1;
4697 		} else if (strcmp(protocol, "tcp6") == 0) {
4698 			af = AF_INET6;
4699 			*isudp = 0;
4700 		} else if (strcmp(protocol, "udp6") == 0) {
4701 			af = AF_INET6;
4702 			*isudp = 1;
4703 		} else
4704 			cantparse = 1;
4705 	} else {
4706 		cantparse = 1;
4707 		if (i > 0) {
4708 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4709 			if (error)
4710 				goto nfsmout;
4711 		}
4712 	}
4713 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4714 	i = fxdr_unsigned(int, *tl);
4715 	if (i < 0) {
4716 		error = NFSERR_BADXDR;
4717 		goto nfsmout;
4718 	} else if (cantparse == 0 && i >= 11 && i < 64) {
4719 		/*
4720 		 * The shortest address is 11chars and the longest is < 64.
4721 		 */
4722 		error = nfsrv_mtostr(nd, addr, i);
4723 		if (error)
4724 			goto nfsmout;
4725 
4726 		/* Find the port# at the end and extract that. */
4727 		i = strlen(addr);
4728 		k = 0;
4729 		cp = &addr[i - 1];
4730 		/* Count back two '.'s from end to get port# field. */
4731 		for (j = 0; j < i; j++) {
4732 			if (*cp == '.') {
4733 				k++;
4734 				if (k == 2)
4735 					break;
4736 			}
4737 			cp--;
4738 		}
4739 		if (k == 2) {
4740 			/*
4741 			 * The NFSv4 port# is appended as .N.N, where N is
4742 			 * a decimal # in the range 0-255, just like an inet4
4743 			 * address. Cheat and use inet_aton(), which will
4744 			 * return a Class A address and then shift the high
4745 			 * order 8bits over to convert it to the port#.
4746 			 */
4747 			*cp++ = '\0';
4748 			if (inet_aton(cp, &saddr) == 1) {
4749 				portnum = ntohl(saddr.s_addr);
4750 				portv = (uint16_t)((portnum >> 16) |
4751 				    (portnum & 0xff));
4752 			} else
4753 				cantparse = 1;
4754 		} else
4755 			cantparse = 1;
4756 		if (cantparse == 0) {
4757 			if (af == AF_INET) {
4758 				if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4759 					sin->sin_len = sizeof(*sin);
4760 					sin->sin_family = AF_INET;
4761 					sin->sin_port = htons(portv);
4762 					*saf = af;
4763 					return (0);
4764 				}
4765 			} else {
4766 				if (inet_pton(af, addr, &sin6->sin6_addr)
4767 				    == 1) {
4768 					sin6->sin6_len = sizeof(*sin6);
4769 					sin6->sin6_family = AF_INET6;
4770 					sin6->sin6_port = htons(portv);
4771 					*saf = af;
4772 					return (0);
4773 				}
4774 			}
4775 		}
4776 	} else {
4777 		if (i > 0) {
4778 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4779 			if (error)
4780 				goto nfsmout;
4781 		}
4782 	}
4783 	error = EPERM;
4784 nfsmout:
4785 	return (error);
4786 }
4787 
4788 /*
4789  * Handle an NFSv4.1 Sequence request for the session.
4790  * If reply != NULL, use it to return the cached reply, as required.
4791  * The client gets a cached reply via this call for callbacks, however the
4792  * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
4793  */
4794 int
4795 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4796     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4797 {
4798 	struct mbuf *m;
4799 	int error;
4800 
4801 	error = 0;
4802 	if (reply != NULL)
4803 		*reply = NULL;
4804 	if (slotid > maxslot)
4805 		return (NFSERR_BADSLOT);
4806 	if (seqid == slots[slotid].nfssl_seq) {
4807 		/* A retry. */
4808 		if (slots[slotid].nfssl_inprog != 0)
4809 			error = NFSERR_DELAY;
4810 		else if (slots[slotid].nfssl_reply != NULL) {
4811 			if (reply != NULL) {
4812 				m = m_copym(slots[slotid].nfssl_reply, 0,
4813 				    M_COPYALL, M_NOWAIT);
4814 				if (m != NULL)
4815 					*reply = m;
4816 				else {
4817 					*reply = slots[slotid].nfssl_reply;
4818 					slots[slotid].nfssl_reply = NULL;
4819 				}
4820 			}
4821 			slots[slotid].nfssl_inprog = 1;
4822 			error = NFSERR_REPLYFROMCACHE;
4823 		} else
4824 			/* No reply cached, so just do it. */
4825 			slots[slotid].nfssl_inprog = 1;
4826 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4827 		if (slots[slotid].nfssl_reply != NULL)
4828 			m_freem(slots[slotid].nfssl_reply);
4829 		slots[slotid].nfssl_reply = NULL;
4830 		slots[slotid].nfssl_inprog = 1;
4831 		slots[slotid].nfssl_seq++;
4832 	} else
4833 		error = NFSERR_SEQMISORDERED;
4834 	return (error);
4835 }
4836 
4837 /*
4838  * Cache this reply for the slot.
4839  * Use the "rep" argument to return the cached reply if repstat is set to
4840  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4841  */
4842 void
4843 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4844    struct mbuf **rep)
4845 {
4846 	struct mbuf *m;
4847 
4848 	if (repstat == NFSERR_REPLYFROMCACHE) {
4849 		if (slots[slotid].nfssl_reply != NULL) {
4850 			/*
4851 			 * We cannot sleep here, but copy will usually
4852 			 * succeed.
4853 			 */
4854 			m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
4855 			    M_NOWAIT);
4856 			if (m != NULL)
4857 				*rep = m;
4858 			else {
4859 				/*
4860 				 * Multiple retries would be extremely rare,
4861 				 * so using the cached reply will likely
4862 				 * be ok.
4863 				 */
4864 				*rep = slots[slotid].nfssl_reply;
4865 				slots[slotid].nfssl_reply = NULL;
4866 			}
4867 		} else
4868 			*rep = NULL;
4869 	} else {
4870 		if (slots[slotid].nfssl_reply != NULL)
4871 			m_freem(slots[slotid].nfssl_reply);
4872 		slots[slotid].nfssl_reply = *rep;
4873 	}
4874 	slots[slotid].nfssl_inprog = 0;
4875 }
4876 
4877 /*
4878  * Generate the xdr for an NFSv4.1 Sequence Operation.
4879  */
4880 void
4881 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4882     struct nfsclsession *sep, int dont_replycache, struct ucred *cred)
4883 {
4884 	uint32_t *tl, slotseq = 0;
4885 	int error, maxslot, slotpos;
4886 	uint8_t sessionid[NFSX_V4SESSIONID];
4887 
4888 	if (cred != NULL) {
4889 		error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
4890 		    &slotseq, sessionid, false);
4891 		if (error == NFSERR_SEQMISORDERED) {
4892 			/* If all slots are bad, Destroy the session. */
4893 			nfsrpc_destroysession(nmp, sep, cred, curthread);
4894 		}
4895 	} else
4896 		error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
4897 		    &slotseq, sessionid, true);
4898 	nd->nd_maxreq = sep->nfsess_maxreq;
4899 	nd->nd_maxresp = sep->nfsess_maxresp;
4900 
4901 	/* Build the Sequence arguments. */
4902 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4903 	nd->nd_sequence = tl;
4904 	bcopy(sessionid, tl, NFSX_V4SESSIONID);
4905 	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4906 	nd->nd_slotseq = tl;
4907 	if (error == 0) {
4908 		nd->nd_flag |= ND_HASSLOTID;
4909 		nd->nd_slotid = slotpos;
4910 		*tl++ = txdr_unsigned(slotseq);
4911 		*tl++ = txdr_unsigned(slotpos);
4912 		*tl++ = txdr_unsigned(maxslot);
4913 		if (dont_replycache == 0)
4914 			*tl = newnfs_true;
4915 		else
4916 			*tl = newnfs_false;
4917 	} else {
4918 		/*
4919 		 * There are two errors and the rest of the session can
4920 		 * just be zeros.
4921 		 * NFSERR_BADSESSION: This bad session should just generate
4922 		 *    the same error again when the RPC is retried.
4923 		 * ESTALE: A forced dismount is in progress and will cause the
4924 		 *    RPC to fail later.
4925 		 */
4926 		*tl++ = 0;
4927 		*tl++ = 0;
4928 		*tl++ = 0;
4929 		*tl = 0;
4930 	}
4931 	nd->nd_flag |= ND_HASSEQUENCE;
4932 }
4933 
4934 /*
4935  * If fnd_init is true, ignore the badslots.
4936  * If fnd_init is false, return NFSERR_SEQMISORDERED if all slots are bad.
4937  */
4938 int
4939 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4940     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid,
4941     bool fnd_init)
4942 {
4943 	int i, maxslot, slotpos;
4944 	uint64_t bitval;
4945 	bool fnd_ok;
4946 
4947 	/* Find an unused slot. */
4948 	slotpos = -1;
4949 	maxslot = -1;
4950 	mtx_lock(&sep->nfsess_mtx);
4951 	do {
4952 		if (nmp != NULL && sep->nfsess_defunct != 0) {
4953 			/* Just return the bad session. */
4954 			bcopy(sep->nfsess_sessionid, sessionid,
4955 			    NFSX_V4SESSIONID);
4956 			mtx_unlock(&sep->nfsess_mtx);
4957 			return (NFSERR_BADSESSION);
4958 		}
4959 		fnd_ok = fnd_init;
4960 		bitval = 1;
4961 		for (i = 0; i < sep->nfsess_foreslots; i++) {
4962 			if ((bitval & sep->nfsess_badslots) == 0 || fnd_init) {
4963 				fnd_ok = true;
4964 				if ((bitval & sep->nfsess_slots) == 0) {
4965 					slotpos = i;
4966 					sep->nfsess_slots |= bitval;
4967 					sep->nfsess_slotseq[i]++;
4968 					*slotseqp = sep->nfsess_slotseq[i];
4969 					break;
4970 				}
4971 			}
4972 			bitval <<= 1;
4973 		}
4974 		if (slotpos == -1) {
4975 			/*
4976 			 * If a forced dismount is in progress, just return.
4977 			 * This RPC attempt will fail when it calls
4978 			 * newnfs_request().
4979 			 */
4980 			if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4981 				mtx_unlock(&sep->nfsess_mtx);
4982 				return (ESTALE);
4983 			}
4984 			/* Wake up once/sec, to check for a forced dismount. */
4985 			if (fnd_ok)
4986 				mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4987 				    PZERO, "nfsclseq", hz);
4988 		}
4989 	} while (slotpos == -1 && fnd_ok);
4990 	/*
4991 	 * If all slots are bad, just return slot 0 and NFSERR_SEQMISORDERED.
4992 	 * The caller will do a DestroySession, so that the session's use
4993 	 * will get a NFSERR_BADSESSION reply from the server.
4994 	 */
4995 	if (!fnd_ok)
4996 		slotpos = 0;
4997 
4998 	/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4999 	bitval = 1;
5000 	for (i = 0; i < 64; i++) {
5001 		if ((bitval & sep->nfsess_slots) != 0)
5002 			maxslot = i;
5003 		bitval <<= 1;
5004 	}
5005 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
5006 	mtx_unlock(&sep->nfsess_mtx);
5007 	*slotposp = slotpos;
5008 	*maxslotp = maxslot;
5009 
5010 	if (!fnd_ok)
5011 		return (NFSERR_SEQMISORDERED);
5012 	return (0);
5013 }
5014 
5015 /*
5016  * Free a session slot.
5017  */
5018 void
5019 nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
5020 {
5021 	uint64_t bitval;
5022 
5023 	bitval = 1;
5024 	if (slot > 0)
5025 		bitval <<= slot;
5026 	mtx_lock(&sep->nfsess_mtx);
5027 	if (resetseq)
5028 		sep->nfsess_slotseq[slot]--;
5029 	if ((bitval & sep->nfsess_slots) == 0)
5030 		printf("freeing free slot!!\n");
5031 	sep->nfsess_slots &= ~bitval;
5032 	wakeup(&sep->nfsess_slots);
5033 	mtx_unlock(&sep->nfsess_mtx);
5034 }
5035 
5036 /*
5037  * Search for a matching pnfsd DS, based on the nmp arg.
5038  * Return one if found, NULL otherwise.
5039  */
5040 struct nfsdevice *
5041 nfsv4_findmirror(struct nfsmount *nmp)
5042 {
5043 	struct nfsdevice *ds;
5044 
5045 	mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
5046 	/*
5047 	 * Search the DS server list for a match with nmp.
5048 	 */
5049 	if (nfsrv_devidcnt == 0)
5050 		return (NULL);
5051 	TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
5052 		if (ds->nfsdev_nmp == nmp) {
5053 			NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
5054 			break;
5055 		}
5056 	}
5057 	return (ds);
5058 }
5059 
5060 /*
5061  * Fill in the fields of "struct nfsrv_descript".
5062  */
5063 void
5064 nfsm_set(struct nfsrv_descript *nd, u_int offs)
5065 {
5066 	struct mbuf *m;
5067 	int rlen;
5068 
5069 	m = nd->nd_mb;
5070 	if ((m->m_flags & M_EXTPG) != 0) {
5071 		nd->nd_bextpg = 0;
5072 		while (offs > 0) {
5073 			if (nd->nd_bextpg == 0)
5074 				rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
5075 			else
5076 				rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
5077 			if (offs <= rlen)
5078 				break;
5079 			offs -= rlen;
5080 			nd->nd_bextpg++;
5081 			if (nd->nd_bextpg == m->m_epg_npgs) {
5082 				printf("nfsm_set: build offs "
5083 				    "out of range\n");
5084 				nd->nd_bextpg--;
5085 				break;
5086 			}
5087 		}
5088 		nd->nd_bpos = (char *)(void *)
5089 		    PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
5090 		if (nd->nd_bextpg == 0)
5091 			nd->nd_bpos += m->m_epg_1st_off;
5092 		if (offs > 0) {
5093 			nd->nd_bpos += offs;
5094 			nd->nd_bextpgsiz = rlen - offs;
5095 		} else if (nd->nd_bextpg == 0)
5096 			nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
5097 		else
5098 			nd->nd_bextpgsiz = PAGE_SIZE;
5099 	} else
5100 		nd->nd_bpos = mtod(m, char *) + offs;
5101 }
5102 
5103 /*
5104  * Grow a ext_pgs mbuf list.  Either allocate another page or add
5105  * an mbuf to the list.
5106  */
5107 struct mbuf *
5108 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
5109 {
5110 	struct mbuf *mp;
5111 	vm_page_t pg;
5112 
5113 	if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
5114 		mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
5115 		*bextpg = 0;
5116 		m->m_next = mp;
5117 	} else {
5118 		pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP |
5119 		    VM_ALLOC_WIRED);
5120 		m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
5121 		*bextpg = m->m_epg_npgs;
5122 		m->m_epg_npgs++;
5123 		m->m_epg_last_len = 0;
5124 		mp = m;
5125 	}
5126 	return (mp);
5127 }
5128 
5129 /*
5130  * Do the NFSv4.1 Destroy Session.
5131  */
5132 int
5133 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclsession *tsep,
5134     struct ucred *cred, NFSPROC_T *p)
5135 {
5136 	uint32_t *tl;
5137 	struct nfsrv_descript nfsd;
5138 	struct nfsrv_descript *nd = &nfsd;
5139 	int error;
5140 
5141 	nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0,
5142 	    0, NULL);
5143 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
5144 	if (tsep == NULL)
5145 		tsep = nfsmnt_mdssession(nmp);
5146 	bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
5147 	nd->nd_flag |= ND_USEGSSNAME;
5148 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5149 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5150 	if (error != 0)
5151 		return (error);
5152 	error = nd->nd_repstat;
5153 	m_freem(nd->nd_mrep);
5154 	return (error);
5155 }
5156