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