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