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