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