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