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