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