1/*	$OpenBSD: nfs_subs.c,v 1.149 2024/05/01 13:15:59 jsg Exp $	*/
2/*	$NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $	*/
3
4/*
5 * Copyright (c) 1989, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Rick Macklem at The University of Guelph.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *	@(#)nfs_subs.c	8.8 (Berkeley) 5/22/95
36 */
37
38
39/*
40 * These functions support the nfsm_subs.h inline functions and help fiddle
41 * mbuf chains for the nfs op functions. They do things such as creating the
42 * rpc header and copying data between mbuf chains and uio lists.
43 */
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/kernel.h>
47#include <sys/mount.h>
48#include <sys/vnode.h>
49#include <sys/namei.h>
50#include <sys/mbuf.h>
51#include <sys/socket.h>
52#include <sys/socketvar.h>
53#include <sys/stat.h>
54#include <sys/pool.h>
55#include <sys/time.h>
56
57#include <nfs/rpcv2.h>
58#include <nfs/nfsproto.h>
59#include <nfs/nfsnode.h>
60#include <nfs/nfs.h>
61#include <nfs/xdr_subs.h>
62#include <nfs/nfsmount.h>
63#include <nfs/nfs_var.h>
64#include <nfs/nfsm_subs.h>
65
66#include <netinet/in.h>
67
68#include <crypto/idgen.h>
69
70int	nfs_attrtimeo(struct nfsnode *np);
71u_int32_t nfs_get_xid(void);
72
73/*
74 * Data items converted to xdr at startup, since they are constant
75 * This is kinda hokey, but may save a little time doing byte swaps
76 */
77u_int32_t nfs_xdrneg1;
78u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
79	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
80u_int32_t nfs_prog, nfs_true, nfs_false;
81
82/* And other global data */
83const nfstype nfsv2_type[9] =
84    { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };
85const nfstype nfsv3_type[9] =
86    { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON };
87const enum vtype nv2tov_type[8] =
88    { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
89const enum vtype nv3tov_type[8]=
90    { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
91int nfs_ticks;
92struct nfsstats nfsstats;
93
94/*
95 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
96 */
97const int nfsv3_procid[NFS_NPROCS] = {
98	NFSPROC_NULL,
99	NFSPROC_GETATTR,
100	NFSPROC_SETATTR,
101	NFSPROC_NOOP,
102	NFSPROC_LOOKUP,
103	NFSPROC_READLINK,
104	NFSPROC_READ,
105	NFSPROC_NOOP,
106	NFSPROC_WRITE,
107	NFSPROC_CREATE,
108	NFSPROC_REMOVE,
109	NFSPROC_RENAME,
110	NFSPROC_LINK,
111	NFSPROC_SYMLINK,
112	NFSPROC_MKDIR,
113	NFSPROC_RMDIR,
114	NFSPROC_READDIR,
115	NFSPROC_FSSTAT,
116	NFSPROC_NOOP,
117	NFSPROC_NOOP,
118	NFSPROC_NOOP,
119	NFSPROC_NOOP,
120	NFSPROC_NOOP
121};
122
123/*
124 * and the reverse mapping from generic to Version 2 procedure numbers
125 */
126const int nfsv2_procid[NFS_NPROCS] = {
127	NFSV2PROC_NULL,
128	NFSV2PROC_GETATTR,
129	NFSV2PROC_SETATTR,
130	NFSV2PROC_LOOKUP,
131	NFSV2PROC_NOOP,
132	NFSV2PROC_READLINK,
133	NFSV2PROC_READ,
134	NFSV2PROC_WRITE,
135	NFSV2PROC_CREATE,
136	NFSV2PROC_MKDIR,
137	NFSV2PROC_SYMLINK,
138	NFSV2PROC_CREATE,
139	NFSV2PROC_REMOVE,
140	NFSV2PROC_RMDIR,
141	NFSV2PROC_RENAME,
142	NFSV2PROC_LINK,
143	NFSV2PROC_READDIR,
144	NFSV2PROC_NOOP,
145	NFSV2PROC_STATFS,
146	NFSV2PROC_NOOP,
147	NFSV2PROC_NOOP,
148	NFSV2PROC_NOOP,
149	NFSV2PROC_NOOP
150};
151
152/*
153 * Maps errno values to nfs error numbers.
154 * Use NFSERR_IO as the catch all for ones not specifically defined in
155 * RFC 1094.
156 */
157static const u_char nfsrv_v2errmap[] = {
158  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
159  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
160  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
161  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
162  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
163  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
164  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
165  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
166  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
167  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
168  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
169  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
170  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
171  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE
172  /* Everything after this maps to NFSERR_IO, so far */
173};
174
175/*
176 * Maps errno values to nfs error numbers.
177 * Although it is not obvious whether or not NFS clients really care if
178 * a returned error value is in the specified list for the procedure, the
179 * safest thing to do is filter them appropriately. For Version 2, the
180 * X/Open XNFS document is the only specification that defines error values
181 * for each RPC (The RFC simply lists all possible error values for all RPCs),
182 * so I have decided to not do this for Version 2.
183 * The first entry is the default error return and the rest are the valid
184 * errors for that RPC in increasing numeric order.
185 */
186static const short nfsv3err_null[] = {
187	0,
188	0,
189};
190
191static const short nfsv3err_getattr[] = {
192	NFSERR_IO,
193	NFSERR_IO,
194	NFSERR_STALE,
195	NFSERR_BADHANDLE,
196	NFSERR_SERVERFAULT,
197	0,
198};
199
200static const short nfsv3err_setattr[] = {
201	NFSERR_IO,
202	NFSERR_PERM,
203	NFSERR_IO,
204	NFSERR_ACCES,
205	NFSERR_INVAL,
206	NFSERR_NOSPC,
207	NFSERR_ROFS,
208	NFSERR_DQUOT,
209	NFSERR_STALE,
210	NFSERR_BADHANDLE,
211	NFSERR_NOT_SYNC,
212	NFSERR_SERVERFAULT,
213	0,
214};
215
216static const short nfsv3err_lookup[] = {
217	NFSERR_IO,
218	NFSERR_NOENT,
219	NFSERR_IO,
220	NFSERR_ACCES,
221	NFSERR_NOTDIR,
222	NFSERR_NAMETOL,
223	NFSERR_STALE,
224	NFSERR_BADHANDLE,
225	NFSERR_SERVERFAULT,
226	0,
227};
228
229static const short nfsv3err_access[] = {
230	NFSERR_IO,
231	NFSERR_IO,
232	NFSERR_STALE,
233	NFSERR_BADHANDLE,
234	NFSERR_SERVERFAULT,
235	0,
236};
237
238static const short nfsv3err_readlink[] = {
239	NFSERR_IO,
240	NFSERR_IO,
241	NFSERR_ACCES,
242	NFSERR_INVAL,
243	NFSERR_STALE,
244	NFSERR_BADHANDLE,
245	NFSERR_NOTSUPP,
246	NFSERR_SERVERFAULT,
247	0,
248};
249
250static const short nfsv3err_read[] = {
251	NFSERR_IO,
252	NFSERR_IO,
253	NFSERR_NXIO,
254	NFSERR_ACCES,
255	NFSERR_INVAL,
256	NFSERR_STALE,
257	NFSERR_BADHANDLE,
258	NFSERR_SERVERFAULT,
259	0,
260};
261
262static const short nfsv3err_write[] = {
263	NFSERR_IO,
264	NFSERR_IO,
265	NFSERR_ACCES,
266	NFSERR_INVAL,
267	NFSERR_FBIG,
268	NFSERR_NOSPC,
269	NFSERR_ROFS,
270	NFSERR_DQUOT,
271	NFSERR_STALE,
272	NFSERR_BADHANDLE,
273	NFSERR_SERVERFAULT,
274	0,
275};
276
277static const short nfsv3err_create[] = {
278	NFSERR_IO,
279	NFSERR_IO,
280	NFSERR_ACCES,
281	NFSERR_EXIST,
282	NFSERR_NOTDIR,
283	NFSERR_NOSPC,
284	NFSERR_ROFS,
285	NFSERR_NAMETOL,
286	NFSERR_DQUOT,
287	NFSERR_STALE,
288	NFSERR_BADHANDLE,
289	NFSERR_NOTSUPP,
290	NFSERR_SERVERFAULT,
291	0,
292};
293
294static const short nfsv3err_mkdir[] = {
295	NFSERR_IO,
296	NFSERR_IO,
297	NFSERR_ACCES,
298	NFSERR_EXIST,
299	NFSERR_NOTDIR,
300	NFSERR_NOSPC,
301	NFSERR_ROFS,
302	NFSERR_NAMETOL,
303	NFSERR_DQUOT,
304	NFSERR_STALE,
305	NFSERR_BADHANDLE,
306	NFSERR_NOTSUPP,
307	NFSERR_SERVERFAULT,
308	0,
309};
310
311static const short nfsv3err_symlink[] = {
312	NFSERR_IO,
313	NFSERR_IO,
314	NFSERR_ACCES,
315	NFSERR_EXIST,
316	NFSERR_NOTDIR,
317	NFSERR_NOSPC,
318	NFSERR_ROFS,
319	NFSERR_NAMETOL,
320	NFSERR_DQUOT,
321	NFSERR_STALE,
322	NFSERR_BADHANDLE,
323	NFSERR_NOTSUPP,
324	NFSERR_SERVERFAULT,
325	0,
326};
327
328static const short nfsv3err_mknod[] = {
329	NFSERR_IO,
330	NFSERR_IO,
331	NFSERR_ACCES,
332	NFSERR_EXIST,
333	NFSERR_NOTDIR,
334	NFSERR_NOSPC,
335	NFSERR_ROFS,
336	NFSERR_NAMETOL,
337	NFSERR_DQUOT,
338	NFSERR_STALE,
339	NFSERR_BADHANDLE,
340	NFSERR_NOTSUPP,
341	NFSERR_SERVERFAULT,
342	NFSERR_BADTYPE,
343	0,
344};
345
346static const short nfsv3err_remove[] = {
347	NFSERR_IO,
348	NFSERR_NOENT,
349	NFSERR_IO,
350	NFSERR_ACCES,
351	NFSERR_NOTDIR,
352	NFSERR_ROFS,
353	NFSERR_NAMETOL,
354	NFSERR_STALE,
355	NFSERR_BADHANDLE,
356	NFSERR_SERVERFAULT,
357	0,
358};
359
360static const short nfsv3err_rmdir[] = {
361	NFSERR_IO,
362	NFSERR_NOENT,
363	NFSERR_IO,
364	NFSERR_ACCES,
365	NFSERR_EXIST,
366	NFSERR_NOTDIR,
367	NFSERR_INVAL,
368	NFSERR_ROFS,
369	NFSERR_NAMETOL,
370	NFSERR_NOTEMPTY,
371	NFSERR_STALE,
372	NFSERR_BADHANDLE,
373	NFSERR_NOTSUPP,
374	NFSERR_SERVERFAULT,
375	0,
376};
377
378static const short nfsv3err_rename[] = {
379	NFSERR_IO,
380	NFSERR_NOENT,
381	NFSERR_IO,
382	NFSERR_ACCES,
383	NFSERR_EXIST,
384	NFSERR_XDEV,
385	NFSERR_NOTDIR,
386	NFSERR_ISDIR,
387	NFSERR_INVAL,
388	NFSERR_NOSPC,
389	NFSERR_ROFS,
390	NFSERR_MLINK,
391	NFSERR_NAMETOL,
392	NFSERR_NOTEMPTY,
393	NFSERR_DQUOT,
394	NFSERR_STALE,
395	NFSERR_BADHANDLE,
396	NFSERR_NOTSUPP,
397	NFSERR_SERVERFAULT,
398	0,
399};
400
401static const short nfsv3err_link[] = {
402	NFSERR_IO,
403	NFSERR_IO,
404	NFSERR_ACCES,
405	NFSERR_EXIST,
406	NFSERR_XDEV,
407	NFSERR_NOTDIR,
408	NFSERR_INVAL,
409	NFSERR_NOSPC,
410	NFSERR_ROFS,
411	NFSERR_MLINK,
412	NFSERR_NAMETOL,
413	NFSERR_DQUOT,
414	NFSERR_STALE,
415	NFSERR_BADHANDLE,
416	NFSERR_NOTSUPP,
417	NFSERR_SERVERFAULT,
418	0,
419};
420
421static const short nfsv3err_readdir[] = {
422	NFSERR_IO,
423	NFSERR_IO,
424	NFSERR_ACCES,
425	NFSERR_NOTDIR,
426	NFSERR_STALE,
427	NFSERR_BADHANDLE,
428	NFSERR_BAD_COOKIE,
429	NFSERR_TOOSMALL,
430	NFSERR_SERVERFAULT,
431	0,
432};
433
434static const short nfsv3err_readdirplus[] = {
435	NFSERR_IO,
436	NFSERR_IO,
437	NFSERR_ACCES,
438	NFSERR_NOTDIR,
439	NFSERR_STALE,
440	NFSERR_BADHANDLE,
441	NFSERR_BAD_COOKIE,
442	NFSERR_NOTSUPP,
443	NFSERR_TOOSMALL,
444	NFSERR_SERVERFAULT,
445	0,
446};
447
448static const short nfsv3err_fsstat[] = {
449	NFSERR_IO,
450	NFSERR_IO,
451	NFSERR_STALE,
452	NFSERR_BADHANDLE,
453	NFSERR_SERVERFAULT,
454	0,
455};
456
457static const short nfsv3err_fsinfo[] = {
458	NFSERR_STALE,
459	NFSERR_STALE,
460	NFSERR_BADHANDLE,
461	NFSERR_SERVERFAULT,
462	0,
463};
464
465static const short nfsv3err_pathconf[] = {
466	NFSERR_STALE,
467	NFSERR_STALE,
468	NFSERR_BADHANDLE,
469	NFSERR_SERVERFAULT,
470	0,
471};
472
473static const short nfsv3err_commit[] = {
474	NFSERR_IO,
475	NFSERR_IO,
476	NFSERR_STALE,
477	NFSERR_BADHANDLE,
478	NFSERR_SERVERFAULT,
479	0,
480};
481
482static const short *nfsrv_v3errmap[] = {
483	nfsv3err_null,
484	nfsv3err_getattr,
485	nfsv3err_setattr,
486	nfsv3err_lookup,
487	nfsv3err_access,
488	nfsv3err_readlink,
489	nfsv3err_read,
490	nfsv3err_write,
491	nfsv3err_create,
492	nfsv3err_mkdir,
493	nfsv3err_symlink,
494	nfsv3err_mknod,
495	nfsv3err_remove,
496	nfsv3err_rmdir,
497	nfsv3err_rename,
498	nfsv3err_link,
499	nfsv3err_readdir,
500	nfsv3err_readdirplus,
501	nfsv3err_fsstat,
502	nfsv3err_fsinfo,
503	nfsv3err_pathconf,
504	nfsv3err_commit,
505};
506
507struct pool nfsreqpl;
508
509/*
510 * Create the header for an rpc request packet
511 * The hsiz is the size of the rest of the nfs request header.
512 * (just used to decide if a cluster is a good idea)
513 */
514struct mbuf *
515nfsm_reqhead(int hsiz)
516{
517	struct mbuf *mb;
518
519	MGET(mb, M_WAIT, MT_DATA);
520	if (hsiz > MLEN)
521		MCLGET(mb, M_WAIT);
522	mb->m_len = 0;
523
524	/* Finally, return values */
525	return (mb);
526}
527
528/*
529 * Return an unpredictable XID in XDR form.
530 */
531u_int32_t
532nfs_get_xid(void)
533{
534	static struct idgen32_ctx nfs_xid_ctx;
535	static int called = 0;
536
537	if (!called) {
538		called = 1;
539		idgen32_init(&nfs_xid_ctx);
540	}
541	return (txdr_unsigned(idgen32(&nfs_xid_ctx)));
542}
543
544/*
545 * Build the RPC header and fill in the authorization info.
546 * Right now we are pretty centric around RPCAUTH_UNIX, in the
547 * future, this function will need some love to be able to handle
548 * other authorization methods, such as Kerberos.
549 */
550void
551nfsm_rpchead(struct nfsreq *req, struct ucred *cr, int auth_type)
552{
553	struct mbuf	*mb;
554	u_int32_t	*tl;
555	int		i, authsiz, auth_len, ngroups;
556
557	KASSERT(auth_type == RPCAUTH_UNIX);
558
559	/*
560	 * RPCAUTH_UNIX fits in an hdr mbuf, in the future other
561	 * authorization methods need to figure out their own sizes
562	 * and allocate and chain mbufs accordingly.
563	 */
564	mb = req->r_mreq;
565
566	/*
567	 * We need to start out by finding how big the authorization cred
568	 * and verifer are for the auth_type, to be able to correctly
569	 * align the mbuf header/chain.
570	 */
571	switch (auth_type) {
572	case RPCAUTH_UNIX:
573		/*
574		 * In the RPCAUTH_UNIX case, the size is the static
575		 * part as shown in RFC1831 + the number of groups,
576		 * RPCAUTH_UNIX has a zero verifer.
577		 */
578		if (cr->cr_ngroups > req->r_nmp->nm_numgrps)
579			ngroups = req->r_nmp->nm_numgrps;
580		else
581			ngroups = cr->cr_ngroups;
582
583		auth_len = (ngroups << 2) + 5 * NFSX_UNSIGNED;
584		authsiz = nfsm_rndup(auth_len);
585		/* The authorization size + the size of the static part */
586		m_align(mb, authsiz + 10 * NFSX_UNSIGNED);
587		break;
588	}
589
590	mb->m_len = 0;
591
592	/* First the RPC header. */
593	tl = nfsm_build(&mb, 6 * NFSX_UNSIGNED);
594
595	/* Get a new (non-zero) xid */
596	*tl++ = req->r_xid = nfs_get_xid();
597	*tl++ = rpc_call;
598	*tl++ = rpc_vers;
599	*tl++ = nfs_prog;
600	if (ISSET(req->r_nmp->nm_flag, NFSMNT_NFSV3)) {
601		*tl++ = txdr_unsigned(NFS_VER3);
602		*tl = txdr_unsigned(req->r_procnum);
603	} else {
604		*tl++ = txdr_unsigned(NFS_VER2);
605		*tl = txdr_unsigned(nfsv2_procid[req->r_procnum]);
606	}
607
608	/* The Authorization cred and its verifier */
609	switch (auth_type) {
610	case RPCAUTH_UNIX:
611		tl = nfsm_build(&mb, auth_len + 4 * NFSX_UNSIGNED);
612		*tl++ = txdr_unsigned(RPCAUTH_UNIX);
613		*tl++ = txdr_unsigned(authsiz);
614
615		/* The authorization cred */
616		*tl++ = 0;		/* stamp */
617		*tl++ = 0;		/* NULL hostname */
618		*tl++ = txdr_unsigned(cr->cr_uid);
619		*tl++ = txdr_unsigned(cr->cr_gid);
620		*tl++ = txdr_unsigned(ngroups);
621		for (i = 0; i < ngroups; i++)
622			*tl++ = txdr_unsigned(cr->cr_groups[i]);
623		/* The authorization verifier */
624		*tl++ = txdr_unsigned(RPCAUTH_NULL);
625		*tl = 0;
626		break;
627	}
628
629	mb->m_pkthdr.len += authsiz + 10 * NFSX_UNSIGNED;
630	mb->m_pkthdr.ph_ifidx = 0;
631}
632
633/*
634 * copies mbuf chain to the uio scatter/gather list
635 */
636int
637nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
638{
639	char *mbufcp, *uiocp;
640	int xfer, left, len;
641	struct mbuf *mp;
642	long uiosiz, rem;
643	int error = 0;
644
645	mp = *mrep;
646	mbufcp = *dpos;
647	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
648	rem = nfsm_padlen(siz);
649	while (siz > 0) {
650		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
651			return (EFBIG);
652		left = uiop->uio_iov->iov_len;
653		uiocp = uiop->uio_iov->iov_base;
654		if (left > siz)
655			left = siz;
656		uiosiz = left;
657		while (left > 0) {
658			while (len == 0) {
659				mp = mp->m_next;
660				if (mp == NULL)
661					return (EBADRPC);
662				mbufcp = mtod(mp, caddr_t);
663				len = mp->m_len;
664			}
665			xfer = (left > len) ? len : left;
666			if (uiop->uio_segflg == UIO_SYSSPACE)
667				memcpy(uiocp, mbufcp, xfer);
668			else
669				copyout(mbufcp, uiocp, xfer);
670			left -= xfer;
671			len -= xfer;
672			mbufcp += xfer;
673			uiocp += xfer;
674			uiop->uio_offset += xfer;
675			uiop->uio_resid -= xfer;
676		}
677		if (uiop->uio_iov->iov_len <= siz) {
678			uiop->uio_iovcnt--;
679			uiop->uio_iov++;
680		} else {
681			uiop->uio_iov->iov_base =
682			    (char *)uiop->uio_iov->iov_base + uiosiz;
683			uiop->uio_iov->iov_len -= uiosiz;
684		}
685		siz -= uiosiz;
686	}
687	*dpos = mbufcp;
688	*mrep = mp;
689	if (rem > 0) {
690		if (len < rem)
691			error = nfs_adv(mrep, dpos, rem, len);
692		else
693			*dpos += rem;
694	}
695	return (error);
696}
697
698/*
699 * Copy a uio scatter/gather list to an mbuf chain.
700 */
701void
702nfsm_uiotombuf(struct mbuf **mp, struct uio *uiop, size_t len)
703{
704	struct mbuf *mb, *mb2;
705	size_t xfer, pad;
706
707	mb = *mp;
708
709	pad = nfsm_padlen(len);
710
711	/* XXX -- the following should be done by the caller */
712	uiop->uio_resid = len;
713	uiop->uio_rw = UIO_WRITE;
714
715	while (len) {
716		xfer = ulmin(len, m_trailingspace(mb));
717		uiomove(mb_offset(mb), xfer, uiop);
718		mb->m_len += xfer;
719		len -= xfer;
720		if (len > 0) {
721			MGET(mb2, M_WAIT, MT_DATA);
722			if (len > MLEN)
723				MCLGET(mb2, M_WAIT);
724			mb2->m_len = 0;
725			mb->m_next = mb2;
726			mb = mb2;
727		}
728	}
729
730	if (pad > 0) {
731		if (pad > m_trailingspace(mb)) {
732			MGET(mb2, M_WAIT, MT_DATA);
733			mb2->m_len = 0;
734			mb->m_next = mb2;
735			mb = mb2;
736		}
737		memset(mb_offset(mb), 0, pad);
738		mb->m_len += pad;
739	}
740
741	*mp = mb;
742}
743
744/*
745 * Copy a buffer to an mbuf chain
746 */
747void
748nfsm_buftombuf(struct mbuf **mp, void *buf, size_t len)
749{
750	struct iovec iov;
751	struct uio io;
752
753	iov.iov_base = buf;
754	iov.iov_len = len;
755
756	io.uio_iov = &iov;
757	io.uio_iovcnt = 1;
758	io.uio_resid = len;
759	io.uio_segflg = UIO_SYSSPACE;
760	io.uio_rw = UIO_WRITE;
761
762	nfsm_uiotombuf(mp, &io, len);
763}
764
765/*
766 * Copy a string to an mbuf chain
767 */
768void
769nfsm_strtombuf(struct mbuf **mp, void *str, size_t len)
770{
771	struct iovec iov[2];
772	struct uio io;
773	uint32_t strlen;
774
775	strlen = txdr_unsigned(len);
776
777	iov[0].iov_base = &strlen;
778	iov[0].iov_len = sizeof(uint32_t);
779	iov[1].iov_base = str;
780	iov[1].iov_len = len;
781
782	io.uio_iov = iov;
783	io.uio_iovcnt = 2;
784	io.uio_resid = sizeof(uint32_t) + len;
785	io.uio_segflg = UIO_SYSSPACE;
786	io.uio_rw = UIO_WRITE;
787
788	nfsm_uiotombuf(mp, &io, io.uio_resid);
789}
790
791/*
792 * Help break down an mbuf chain by setting the first siz bytes contiguous
793 * pointed to by returned val.
794 * This is used by nfsm_dissect for tough cases.
795 */
796int
797nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
798{
799	struct mbuf *mp, *mp2;
800	int siz2, xfer;
801	caddr_t p;
802
803	mp = *mdp;
804	while (left == 0) {
805		*mdp = mp = mp->m_next;
806		if (mp == NULL)
807			return (EBADRPC);
808		left = mp->m_len;
809		*dposp = mtod(mp, caddr_t);
810	}
811	if (left >= siz) {
812		*cp2 = *dposp;
813		*dposp += siz;
814	} else if (mp->m_next == NULL) {
815		return (EBADRPC);
816	} else if (siz > MHLEN) {
817		panic("nfs S too big");
818	} else {
819		MGET(mp2, M_WAIT, MT_DATA);
820		mp2->m_next = mp->m_next;
821		mp->m_next = mp2;
822		mp->m_len -= left;
823		mp = mp2;
824		*cp2 = p = mtod(mp, caddr_t);
825		bcopy(*dposp, p, left);		/* Copy what was left */
826		siz2 = siz - left;
827		p += left;
828		mp2 = mp->m_next;
829		/* Loop around copying up the siz2 bytes */
830		while (siz2 > 0) {
831			if (mp2 == NULL)
832				return (EBADRPC);
833			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
834			if (xfer > 0) {
835				bcopy(mtod(mp2, caddr_t), p, xfer);
836				mp2->m_data += xfer;
837				mp2->m_len -= xfer;
838				p += xfer;
839				siz2 -= xfer;
840			}
841			if (siz2 > 0)
842				mp2 = mp2->m_next;
843		}
844		mp->m_len = siz;
845		*mdp = mp2;
846		*dposp = mtod(mp2, caddr_t);
847	}
848	return (0);
849}
850
851/*
852 * Advance the position in the mbuf chain.
853 */
854int
855nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
856{
857	struct mbuf *m;
858	int s;
859
860	m = *mdp;
861	s = left;
862	while (s < offs) {
863		offs -= s;
864		m = m->m_next;
865		if (m == NULL)
866			return (EBADRPC);
867		s = m->m_len;
868	}
869	*mdp = m;
870	*dposp = mtod(m, caddr_t)+offs;
871	return (0);
872}
873
874/*
875 * Called once to initialize data structures...
876 */
877void
878nfs_init(void)
879{
880	rpc_vers = txdr_unsigned(RPC_VER2);
881	rpc_call = txdr_unsigned(RPC_CALL);
882	rpc_reply = txdr_unsigned(RPC_REPLY);
883	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
884	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
885	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
886	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
887	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
888	nfs_prog = txdr_unsigned(NFS_PROG);
889	nfs_true = txdr_unsigned(1);
890	nfs_false = txdr_unsigned(0);
891	nfs_xdrneg1 = txdr_unsigned(-1);
892	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
893	if (nfs_ticks < 1)
894		nfs_ticks = 1;
895#ifdef NFSSERVER
896	nfsrv_init(0);			/* Init server data structures */
897	nfsrv_initcache();		/* Init the server request cache */
898#endif /* NFSSERVER */
899
900	pool_init(&nfsreqpl, sizeof(struct nfsreq), 0, IPL_NONE, PR_WAITOK,
901	    "nfsreqpl", NULL);
902}
903
904#ifdef NFSCLIENT
905int
906nfs_vfs_init(struct vfsconf *vfsp)
907{
908	extern struct pool nfs_node_pool;
909
910	TAILQ_INIT(&nfs_bufq);
911
912	pool_init(&nfs_node_pool, sizeof(struct nfsnode), 0, IPL_NONE,
913		  PR_WAITOK, "nfsnodepl", NULL);
914
915	return (0);
916}
917
918/*
919 * Attribute cache routines.
920 * nfs_loadattrcache() - loads or updates the cache contents from attributes
921 *	that are on the mbuf list
922 * nfs_getattrcache() - returns valid attributes if found in cache, returns
923 *	error otherwise
924 */
925
926/*
927 * Load the attribute cache (that lives in the nfsnode entry) with
928 * the values on the mbuf list and
929 * Iff vap not NULL
930 *    copy the attributes to *vaper
931 */
932int
933nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
934    struct vattr *vaper)
935{
936	struct vnode *vp = *vpp;
937	struct vattr *vap;
938	struct nfs_fattr *fp;
939	extern const struct vops nfs_specvops;
940	struct nfsnode *np;
941	int32_t avail;
942	int error = 0;
943	int32_t rdev;
944	struct mbuf *md;
945	enum vtype vtyp;
946	mode_t vmode;
947	struct timespec mtime;
948	struct vnode *nvp;
949	int v3 = NFS_ISV3(vp);
950	uid_t uid;
951	gid_t gid;
952
953	md = *mdp;
954	avail = (mtod(md, caddr_t) + md->m_len) - *dposp;
955	error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), avail, (caddr_t *)&fp);
956	if (error)
957		return (error);
958	if (v3) {
959		vtyp = nfsv3tov_type(fp->fa_type);
960		vmode = fxdr_unsigned(mode_t, fp->fa_mode);
961		rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
962			fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
963		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
964	} else {
965		vtyp = nfsv2tov_type(fp->fa_type);
966		vmode = fxdr_unsigned(mode_t, fp->fa_mode);
967		if (vtyp == VNON || vtyp == VREG)
968			vtyp = IFTOVT(vmode);
969		rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
970		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
971
972		/*
973		 * Really ugly NFSv2 kludge.
974		 */
975		if (vtyp == VCHR && rdev == 0xffffffff)
976			vtyp = VFIFO;
977	}
978
979	/*
980	 * If v_type == VNON it is a new node, so fill in the v_type,
981	 * n_mtime fields. Check to see if it represents a special
982	 * device, and if so, check for a possible alias. Once the
983	 * correct vnode has been obtained, fill in the rest of the
984	 * information.
985	 */
986	np = VTONFS(vp);
987	if (vp->v_type != vtyp) {
988		cache_purge(vp);
989		vp->v_type = vtyp;
990		if (vp->v_type == VFIFO) {
991#ifndef FIFO
992			return (EOPNOTSUPP);
993#else
994                        extern const struct vops nfs_fifovops;
995			vp->v_op = &nfs_fifovops;
996#endif /* FIFO */
997		}
998		if (vp->v_type == VCHR || vp->v_type == VBLK) {
999			vp->v_op = &nfs_specvops;
1000			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1001			if (nvp) {
1002				/*
1003				 * Discard unneeded vnode, but save its nfsnode.
1004				 * Since the nfsnode does not have a lock, its
1005				 * vnode lock has to be carried over.
1006				 */
1007
1008				nvp->v_data = vp->v_data;
1009				vp->v_data = NULL;
1010				vp->v_op = &spec_vops;
1011				vrele(vp);
1012				vgone(vp);
1013				/*
1014				 * Reinitialize aliased node.
1015				 */
1016				np->n_vnode = nvp;
1017				*vpp = vp = nvp;
1018			}
1019		}
1020		np->n_mtime = mtime;
1021	}
1022	vap = &np->n_vattr;
1023	vap->va_type = vtyp;
1024	vap->va_rdev = (dev_t)rdev;
1025	vap->va_mtime = mtime;
1026	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1027
1028	uid = fxdr_unsigned(uid_t, fp->fa_uid);
1029	gid = fxdr_unsigned(gid_t, fp->fa_gid);
1030	/* Invalidate access cache if uid, gid or mode changed. */
1031	if (np->n_accstamp != -1 &&
1032	    (gid != vap->va_gid || uid != vap->va_uid ||
1033	    (vmode & 07777) != vap->va_mode))
1034		np->n_accstamp = -1;
1035
1036	vap->va_mode = (vmode & 07777);
1037
1038	switch (vtyp) {
1039	case VBLK:
1040		vap->va_blocksize = BLKDEV_IOSIZE;
1041		break;
1042	case VCHR:
1043		vap->va_blocksize = MAXBSIZE;
1044		break;
1045	default:
1046		vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize :
1047		     fxdr_unsigned(int32_t, fp->fa2_blocksize);
1048		break;
1049	}
1050	vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
1051	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1052	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1053	if (v3) {
1054		vap->va_size = fxdr_hyper(&fp->fa3_size);
1055		vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1056		vap->va_fileid = fxdr_hyper(&fp->fa3_fileid);
1057		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1058		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1059	} else {
1060		vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1061		vap->va_bytes =
1062		    (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
1063		    NFS_FABLKSIZE;
1064		vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1065		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1066		vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
1067		    fp->fa2_ctime.nfsv2_sec);
1068		vap->va_ctime.tv_nsec = 0;
1069		vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1070	}
1071	vap->va_flags = 0;
1072	vap->va_filerev = 0;
1073
1074	if (vap->va_size != np->n_size) {
1075		if (vap->va_type == VREG) {
1076			if (np->n_flag & NMODIFIED) {
1077				if (vap->va_size < np->n_size)
1078					vap->va_size = np->n_size;
1079				else
1080					np->n_size = vap->va_size;
1081			} else
1082				np->n_size = vap->va_size;
1083			uvm_vnp_setsize(vp, np->n_size);
1084		} else
1085			np->n_size = vap->va_size;
1086	}
1087	np->n_attrstamp = gettime();
1088	if (vaper != NULL) {
1089		bcopy(vap, vaper, sizeof(*vap));
1090		if (np->n_flag & NCHG) {
1091			if (np->n_flag & NACC)
1092				vaper->va_atime = np->n_atim;
1093			if (np->n_flag & NUPD)
1094				vaper->va_mtime = np->n_mtim;
1095		}
1096	}
1097	return (0);
1098}
1099
1100int
1101nfs_attrtimeo(struct nfsnode *np)
1102{
1103	struct vnode *vp = np->n_vnode;
1104	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1105	int tenthage = (gettime() - np->n_mtime.tv_sec) / 10;
1106	int minto, maxto;
1107
1108	if (vp->v_type == VDIR) {
1109		maxto = nmp->nm_acdirmax;
1110		minto = nmp->nm_acdirmin;
1111	} else {
1112		maxto = nmp->nm_acregmax;
1113		minto = nmp->nm_acregmin;
1114	}
1115
1116	if (np->n_flag & NMODIFIED || tenthage < minto)
1117		return minto;
1118	else if (tenthage < maxto)
1119		return tenthage;
1120	else
1121		return maxto;
1122}
1123
1124/*
1125 * Check the time stamp
1126 * If the cache is valid, copy contents to *vap and return 0
1127 * otherwise return an error
1128 */
1129int
1130nfs_getattrcache(struct vnode *vp, struct vattr *vaper)
1131{
1132	struct nfsnode *np = VTONFS(vp);
1133	struct vattr *vap;
1134
1135	if (np->n_attrstamp == 0 ||
1136	    (gettime() - np->n_attrstamp) >= nfs_attrtimeo(np)) {
1137		nfsstats.attrcache_misses++;
1138		return (ENOENT);
1139	}
1140	nfsstats.attrcache_hits++;
1141	vap = &np->n_vattr;
1142	if (vap->va_size != np->n_size) {
1143		if (vap->va_type == VREG) {
1144			if (np->n_flag & NMODIFIED) {
1145				if (vap->va_size < np->n_size)
1146					vap->va_size = np->n_size;
1147				else
1148					np->n_size = vap->va_size;
1149			} else
1150				np->n_size = vap->va_size;
1151			uvm_vnp_setsize(vp, np->n_size);
1152		} else
1153			np->n_size = vap->va_size;
1154	}
1155	bcopy(vap, vaper, sizeof(struct vattr));
1156	if (np->n_flag & NCHG) {
1157		if (np->n_flag & NACC)
1158			vaper->va_atime = np->n_atim;
1159		if (np->n_flag & NUPD)
1160			vaper->va_mtime = np->n_mtim;
1161	}
1162	return (0);
1163}
1164#endif /* NFSCLIENT */
1165
1166/*
1167 * Set up nameidata for a lookup() call and do it
1168 */
1169int
1170nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
1171    struct nfssvc_sock *slp, struct mbuf *nam, struct mbuf **mdp,
1172    caddr_t *dposp, struct vnode **retdirp, struct proc *p)
1173{
1174	int i, rem;
1175	struct mbuf *md;
1176	char *fromcp, *tocp;
1177	struct vnode *dp;
1178	int error, rdonly;
1179	struct componentname *cnp = &ndp->ni_cnd;
1180
1181	*retdirp = NULL;
1182	cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
1183	/*
1184	 * Copy the name from the mbuf list to ndp->ni_pnbuf
1185	 * and set the various ndp fields appropriately.
1186	 */
1187	fromcp = *dposp;
1188	tocp = cnp->cn_pnbuf;
1189	md = *mdp;
1190	rem = mtod(md, caddr_t) + md->m_len - fromcp;
1191	for (i = 0; i < len; i++) {
1192		while (rem == 0) {
1193			md = md->m_next;
1194			if (md == NULL) {
1195				error = EBADRPC;
1196				goto out;
1197			}
1198			fromcp = mtod(md, caddr_t);
1199			rem = md->m_len;
1200		}
1201		if (*fromcp == '\0' || *fromcp == '/') {
1202			error = EACCES;
1203			goto out;
1204		}
1205		*tocp++ = *fromcp++;
1206		rem--;
1207	}
1208	*tocp = '\0';
1209	*mdp = md;
1210	*dposp = fromcp;
1211	len = nfsm_padlen(len);
1212	if (len > 0) {
1213		if (rem >= len)
1214			*dposp += len;
1215		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1216			goto out;
1217	}
1218	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
1219	cnp->cn_nameptr = cnp->cn_pnbuf;
1220	/*
1221	 * Extract and set starting directory.
1222	 */
1223	error = nfsrv_fhtovp(fhp, 0, &dp, ndp->ni_cnd.cn_cred, slp,
1224	    nam, &rdonly);
1225	if (error)
1226		goto out;
1227	if (dp->v_type != VDIR) {
1228		vrele(dp);
1229		error = ENOTDIR;
1230		goto out;
1231	}
1232	vref(dp);
1233	*retdirp = dp;
1234	ndp->ni_startdir = dp;
1235	if (rdonly)
1236		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
1237	else
1238		cnp->cn_flags |= NOCROSSMOUNT;
1239
1240	/*
1241	 * And call lookup() to do the real work
1242	 */
1243	cnp->cn_proc = p;
1244	error = vfs_lookup(ndp);
1245	if (error)
1246		goto out;
1247	/*
1248	 * Check for encountering a symbolic link
1249	 */
1250	if (cnp->cn_flags & ISSYMLINK) {
1251		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1252			vput(ndp->ni_dvp);
1253		else
1254			vrele(ndp->ni_dvp);
1255		vput(ndp->ni_vp);
1256		ndp->ni_vp = NULL;
1257		error = EINVAL;
1258		goto out;
1259	}
1260	/*
1261	 * Check for saved name request
1262	 */
1263	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
1264		cnp->cn_flags |= HASBUF;
1265		return (0);
1266	}
1267out:
1268	pool_put(&namei_pool, cnp->cn_pnbuf);
1269	return (error);
1270}
1271
1272/*
1273 * A fiddled version of m_adj() that ensures null fill to a long
1274 * boundary and only trims off the back end
1275 */
1276void
1277nfsm_adj(struct mbuf *mp, int len, int nul)
1278{
1279	struct mbuf *m;
1280	int count, i;
1281	char *cp;
1282
1283	/*
1284	 * Trim from tail.  Scan the mbuf chain,
1285	 * calculating its length and finding the last mbuf.
1286	 * If the adjustment only affects this mbuf, then just
1287	 * adjust and return.  Otherwise, rescan and truncate
1288	 * after the remaining size.
1289	 */
1290	count = 0;
1291	m = mp;
1292	for (;;) {
1293		count += m->m_len;
1294		if (m->m_next == NULL)
1295			break;
1296		m = m->m_next;
1297	}
1298	if (m->m_len > len) {
1299		m->m_len -= len;
1300		if (nul > 0) {
1301			cp = mtod(m, caddr_t)+m->m_len-nul;
1302			for (i = 0; i < nul; i++)
1303				*cp++ = '\0';
1304		}
1305		return;
1306	}
1307	count -= len;
1308	if (count < 0)
1309		count = 0;
1310	/*
1311	 * Correct length for chain is "count".
1312	 * Find the mbuf with last data, adjust its length,
1313	 * and toss data from remaining mbufs on chain.
1314	 */
1315	for (m = mp; m; m = m->m_next) {
1316		if (m->m_len >= count) {
1317			m->m_len = count;
1318			if (nul > 0) {
1319				cp = mtod(m, caddr_t)+m->m_len-nul;
1320				for (i = 0; i < nul; i++)
1321					*cp++ = '\0';
1322			}
1323			break;
1324		}
1325		count -= m->m_len;
1326	}
1327	for (m = m->m_next;m;m = m->m_next)
1328		m->m_len = 0;
1329}
1330
1331/*
1332 * Make these non-inline functions, so that the kernel text size
1333 * doesn't get too big...
1334 */
1335void
1336nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
1337    struct vattr *before_vap, int after_ret, struct vattr *after_vap,
1338    struct nfsm_info *info)
1339{
1340	u_int32_t *tl;
1341
1342	if (before_ret) {
1343		tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED);
1344		*tl = nfs_false;
1345	} else {
1346		tl = nfsm_build(&info->nmi_mb, 7 * NFSX_UNSIGNED);
1347		*tl++ = nfs_true;
1348		txdr_hyper(before_vap->va_size, tl);
1349		tl += 2;
1350		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1351		tl += 2;
1352		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1353	}
1354	nfsm_srvpostop_attr(nfsd, after_ret, after_vap, info);
1355}
1356
1357void
1358nfsm_srvpostop_attr(struct nfsrv_descript *nfsd, int after_ret,
1359    struct vattr *after_vap, struct nfsm_info *info)
1360{
1361	u_int32_t *tl;
1362	struct nfs_fattr *fp;
1363
1364	if (after_ret) {
1365		tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED);
1366		*tl = nfs_false;
1367	} else {
1368		tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED + NFSX_V3FATTR);
1369		*tl++ = nfs_true;
1370		fp = (struct nfs_fattr *)tl;
1371		nfsm_srvfattr(nfsd, after_vap, fp);
1372	}
1373}
1374
1375void
1376nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1377    struct nfs_fattr *fp)
1378{
1379
1380	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1381	fp->fa_uid = txdr_unsigned(vap->va_uid);
1382	fp->fa_gid = txdr_unsigned(vap->va_gid);
1383	if (nfsd->nd_flag & ND_NFSV3) {
1384		fp->fa_type = vtonfsv3_type(vap->va_type);
1385		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1386		txdr_hyper(vap->va_size, &fp->fa3_size);
1387		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1388		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1389		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1390		fp->fa3_fsid.nfsuquad[0] = 0;
1391		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1392		txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1393		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1394		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1395		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1396	} else {
1397		fp->fa_type = vtonfsv2_type(vap->va_type);
1398		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1399		fp->fa2_size = txdr_unsigned(vap->va_size);
1400		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1401		if (vap->va_type == VFIFO)
1402			fp->fa2_rdev = 0xffffffff;
1403		else
1404			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1405		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1406		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1407		fp->fa2_fileid = txdr_unsigned((u_int32_t)vap->va_fileid);
1408		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1409		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1410		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1411	}
1412}
1413
1414/*
1415 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1416 * 	- look up fsid in mount list (if not found ret error)
1417 *	- get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP()
1418 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1419 *	- if not lockflag unlock it with VOP_UNLOCK()
1420 */
1421int
1422nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1423    struct ucred *cred, struct nfssvc_sock *slp, struct mbuf *nam,
1424    int *rdonlyp)
1425{
1426	struct mount *mp;
1427	int i;
1428	struct ucred *credanon;
1429	int error, exflags;
1430	struct sockaddr_in *saddr;
1431
1432	*vpp = NULL;
1433	mp = vfs_getvfs(&fhp->fh_fsid);
1434
1435	if (!mp)
1436		return (ESTALE);
1437	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1438	if (error)
1439		return (error);
1440	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1441	if (error)
1442		return (error);
1443
1444	saddr = mtod(nam, struct sockaddr_in *);
1445	if (saddr->sin_family == AF_INET &&
1446	    (ntohs(saddr->sin_port) >= IPPORT_RESERVED ||
1447	    (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) {
1448		vput(*vpp);
1449		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1450	}
1451
1452	/* Check/setup credentials. */
1453	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1454		cred->cr_uid = credanon->cr_uid;
1455		cred->cr_gid = credanon->cr_gid;
1456		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS_MAX; i++)
1457			cred->cr_groups[i] = credanon->cr_groups[i];
1458		cred->cr_ngroups = i;
1459	}
1460	if (exflags & MNT_EXRDONLY)
1461		*rdonlyp = 1;
1462	else
1463		*rdonlyp = 0;
1464	if (!lockflag)
1465		VOP_UNLOCK(*vpp);
1466
1467	return (0);
1468}
1469
1470/*
1471 * This function compares two net addresses by family and returns non zero
1472 * if they are the same host, or if there is any doubt it returns 0.
1473 * The AF_INET family is handled as a special case so that address mbufs
1474 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1475 */
1476int
1477netaddr_match(int family, union nethostaddr *haddr, struct mbuf *nam)
1478{
1479	struct sockaddr_in *inetaddr;
1480
1481	switch (family) {
1482	case AF_INET:
1483		inetaddr = mtod(nam, struct sockaddr_in *);
1484		if (inetaddr->sin_family == AF_INET &&
1485		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1486			return (1);
1487		break;
1488	default:
1489		break;
1490	};
1491	return (0);
1492}
1493
1494/*
1495 * The write verifier has changed (probably due to a server reboot), so all
1496 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
1497 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
1498 * flag. Once done the new write verifier can be set for the mount point.
1499 */
1500void
1501nfs_clearcommit(struct mount *mp)
1502{
1503	struct vnode *vp;
1504	struct buf *bp;
1505	int s;
1506
1507	s = splbio();
1508loop:
1509	TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
1510		if (vp->v_mount != mp)	/* Paranoia */
1511			goto loop;
1512		LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
1513			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
1514			    == (B_DELWRI | B_NEEDCOMMIT))
1515				bp->b_flags &= ~B_NEEDCOMMIT;
1516		}
1517	}
1518	splx(s);
1519}
1520
1521void
1522nfs_merge_commit_ranges(struct vnode *vp)
1523{
1524	struct nfsnode *np = VTONFS(vp);
1525
1526	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
1527		np->n_pushedlo = np->n_pushlo;
1528		np->n_pushedhi = np->n_pushhi;
1529		np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
1530	} else {
1531		if (np->n_pushlo < np->n_pushedlo)
1532			np->n_pushedlo = np->n_pushlo;
1533		if (np->n_pushhi > np->n_pushedhi)
1534			np->n_pushedhi = np->n_pushhi;
1535	}
1536
1537	np->n_pushlo = np->n_pushhi = 0;
1538	np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
1539}
1540
1541int
1542nfs_in_committed_range(struct vnode *vp, struct buf *bp)
1543{
1544	struct nfsnode *np = VTONFS(vp);
1545	off_t lo, hi;
1546
1547	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
1548		return 0;
1549	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1550	hi = lo + bp->b_dirtyend;
1551
1552	return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
1553}
1554
1555int
1556nfs_in_tobecommitted_range(struct vnode *vp, struct buf *bp)
1557{
1558	struct nfsnode *np = VTONFS(vp);
1559	off_t lo, hi;
1560
1561	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
1562		return 0;
1563	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1564	hi = lo + bp->b_dirtyend;
1565
1566	return (lo >= np->n_pushlo && hi <= np->n_pushhi);
1567}
1568
1569void
1570nfs_add_committed_range(struct vnode *vp, struct buf *bp)
1571{
1572	struct nfsnode *np = VTONFS(vp);
1573	off_t lo, hi;
1574
1575	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1576	hi = lo + bp->b_dirtyend;
1577
1578	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
1579		np->n_pushedlo = lo;
1580		np->n_pushedhi = hi;
1581		np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
1582	} else {
1583		if (hi > np->n_pushedhi)
1584			np->n_pushedhi = hi;
1585		if (lo < np->n_pushedlo)
1586			np->n_pushedlo = lo;
1587	}
1588}
1589
1590void
1591nfs_del_committed_range(struct vnode *vp, struct buf *bp)
1592{
1593	struct nfsnode *np = VTONFS(vp);
1594	off_t lo, hi;
1595
1596	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
1597		return;
1598
1599	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1600	hi = lo + bp->b_dirtyend;
1601
1602	if (lo > np->n_pushedhi || hi < np->n_pushedlo)
1603		return;
1604	if (lo <= np->n_pushedlo)
1605		np->n_pushedlo = hi;
1606	else if (hi >= np->n_pushedhi)
1607		np->n_pushedhi = lo;
1608	else {
1609		/*
1610		 * XXX There's only one range. If the deleted range
1611		 * is in the middle, pick the largest of the
1612		 * contiguous ranges that it leaves.
1613		 */
1614		if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
1615			np->n_pushedhi = lo;
1616		else
1617			np->n_pushedlo = hi;
1618	}
1619}
1620
1621void
1622nfs_add_tobecommitted_range(struct vnode *vp, struct buf *bp)
1623{
1624	struct nfsnode *np = VTONFS(vp);
1625	off_t lo, hi;
1626
1627	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1628	hi = lo + bp->b_dirtyend;
1629
1630	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
1631		np->n_pushlo = lo;
1632		np->n_pushhi = hi;
1633		np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
1634	} else {
1635		if (lo < np->n_pushlo)
1636			np->n_pushlo = lo;
1637		if (hi > np->n_pushhi)
1638			np->n_pushhi = hi;
1639	}
1640}
1641
1642void
1643nfs_del_tobecommitted_range(struct vnode *vp, struct buf *bp)
1644{
1645	struct nfsnode *np = VTONFS(vp);
1646	off_t lo, hi;
1647
1648	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
1649		return;
1650
1651	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1652	hi = lo + bp->b_dirtyend;
1653
1654	if (lo > np->n_pushhi || hi < np->n_pushlo)
1655		return;
1656
1657	if (lo <= np->n_pushlo)
1658		np->n_pushlo = hi;
1659	else if (hi >= np->n_pushhi)
1660		np->n_pushhi = lo;
1661	else {
1662		/*
1663		 * XXX There's only one range. If the deleted range
1664		 * is in the middle, pick the largest of the
1665		 * contiguous ranges that it leaves.
1666		 */
1667		if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
1668			np->n_pushhi = lo;
1669		else
1670			np->n_pushlo = hi;
1671	}
1672}
1673
1674/*
1675 * Map errnos to NFS error numbers. For Version 3 also filter out error
1676 * numbers not specified for the associated procedure.
1677 */
1678int
1679nfsrv_errmap(struct nfsrv_descript *nd, int err)
1680{
1681	const short *defaulterrp, *errp;
1682
1683	if (nd->nd_flag & ND_NFSV3) {
1684	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1685		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1686		while (*++errp) {
1687			if (*errp == err)
1688				return (err);
1689			else if (*errp > err)
1690				break;
1691		}
1692		return ((int)*defaulterrp);
1693	    } else
1694		return (err & 0xffff);
1695	}
1696	if (err <= nitems(nfsrv_v2errmap))
1697		return ((int)nfsrv_v2errmap[err - 1]);
1698	return (NFSERR_IO);
1699}
1700
1701/*
1702 * If full is non zero, set all fields, otherwise just set mode and time fields
1703 */
1704void
1705nfsm_v3attrbuild(struct mbuf **mp, struct vattr *a, int full)
1706{
1707	struct mbuf *mb;
1708	u_int32_t *tl;
1709
1710	mb = *mp;
1711
1712	if (a->va_mode != (mode_t)VNOVAL) {
1713		tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED);
1714		*tl++ = nfs_true;
1715		*tl = txdr_unsigned(a->va_mode);
1716	} else {
1717		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1718		*tl = nfs_false;
1719	}
1720	if (full && a->va_uid != (uid_t)VNOVAL) {
1721		tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED);
1722		*tl++ = nfs_true;
1723		*tl = txdr_unsigned(a->va_uid);
1724	} else {
1725		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1726		*tl = nfs_false;
1727	}
1728	if (full && a->va_gid != (gid_t)VNOVAL) {
1729		tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED);
1730		*tl++ = nfs_true;
1731		*tl = txdr_unsigned((a)->va_gid);
1732	} else {
1733		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1734		*tl = nfs_false;
1735	}
1736	if (full && a->va_size != VNOVAL) {
1737		tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
1738		*tl++ = nfs_true;
1739		txdr_hyper(a->va_size, tl);
1740	} else {
1741		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1742		*tl = nfs_false;
1743	}
1744	if (a->va_atime.tv_nsec != VNOVAL) {
1745		if (a->va_atime.tv_sec != gettime()) {
1746			tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
1747			*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
1748			txdr_nfsv3time(&a->va_atime, tl);
1749		} else {
1750			tl = nfsm_build(&mb, NFSX_UNSIGNED);
1751			*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
1752		}
1753	} else {
1754		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1755		*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
1756	}
1757	if (a->va_mtime.tv_nsec != VNOVAL) {
1758		if (a->va_mtime.tv_sec != gettime()) {
1759			tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
1760			*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
1761			txdr_nfsv3time(&a->va_mtime, tl);
1762		} else {
1763			tl = nfsm_build(&mb, NFSX_UNSIGNED);
1764			*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
1765		}
1766	} else {
1767		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1768		*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
1769	}
1770
1771	*mp = mb;
1772}
1773
1774/*
1775 * Ensure a contiguous buffer len bytes long
1776 */
1777void *
1778nfsm_build(struct mbuf **mp, u_int len)
1779{
1780	struct mbuf *mb, *mb2;
1781	caddr_t bpos;
1782
1783	mb = *mp;
1784	bpos = mb_offset(mb);
1785
1786	if (len > m_trailingspace(mb)) {
1787		MGET(mb2, M_WAIT, MT_DATA);
1788		if (len > MLEN)
1789			panic("build > MLEN");
1790		mb->m_next = mb2;
1791		mb = mb2;
1792		mb->m_len = 0;
1793		bpos = mtod(mb, caddr_t);
1794	}
1795	mb->m_len += len;
1796
1797	*mp = mb;
1798
1799	return (bpos);
1800}
1801
1802void
1803nfsm_fhtom(struct nfsm_info *info, struct vnode *v, int v3)
1804{
1805	struct nfsnode *n = VTONFS(v);
1806
1807	if (v3) {
1808		nfsm_strtombuf(&info->nmi_mb, n->n_fhp, n->n_fhsize);
1809	} else {
1810		nfsm_buftombuf(&info->nmi_mb, n->n_fhp, NFSX_V2FH);
1811	}
1812}
1813
1814void
1815nfsm_srvfhtom(struct mbuf **mp, fhandle_t *f, int v3)
1816{
1817	if (v3) {
1818		nfsm_strtombuf(mp, f, NFSX_V3FH);
1819	} else {
1820		nfsm_buftombuf(mp, f, NFSX_V2FH);
1821	}
1822}
1823
1824int
1825nfsm_srvsattr(struct mbuf **mp, struct vattr *va, struct mbuf *mrep,
1826    caddr_t *dposp)
1827{
1828	struct nfsm_info	info;
1829	int error = 0;
1830	uint32_t *tl;
1831
1832	info.nmi_md = *mp;
1833	info.nmi_dpos = *dposp;
1834	info.nmi_mrep = mrep;
1835	info.nmi_errorp = &error;
1836
1837	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1838	if (tl == NULL)
1839		return error;
1840	if (*tl == nfs_true) {
1841		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1842		if (tl == NULL)
1843			return error;
1844		va->va_mode = nfstov_mode(*tl);
1845	}
1846
1847	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1848	if (tl == NULL)
1849		return error;
1850	if (*tl == nfs_true) {
1851		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1852		if (tl == NULL)
1853			return error;
1854		va->va_uid = fxdr_unsigned(uid_t, *tl);
1855	}
1856
1857	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1858	if (tl == NULL)
1859		return error;
1860	if (*tl == nfs_true) {
1861		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1862		if (tl == NULL)
1863			return error;
1864		va->va_gid = fxdr_unsigned(gid_t, *tl);
1865	}
1866
1867	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1868	if (tl == NULL)
1869		return error;
1870	if (*tl == nfs_true) {
1871		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
1872		if (tl == NULL)
1873			return error;
1874		va->va_size = fxdr_hyper(tl);
1875	}
1876
1877	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1878	if (tl == NULL)
1879		return error;
1880	switch (fxdr_unsigned(int, *tl)) {
1881	case NFSV3SATTRTIME_TOCLIENT:
1882		va->va_vaflags |= VA_UTIMES_CHANGE;
1883		va->va_vaflags &= ~VA_UTIMES_NULL;
1884		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
1885		if (tl == NULL)
1886			return error;
1887		fxdr_nfsv3time(tl, &va->va_atime);
1888		break;
1889	case NFSV3SATTRTIME_TOSERVER:
1890		va->va_vaflags |= VA_UTIMES_CHANGE;
1891		getnanotime(&va->va_atime);
1892		break;
1893	};
1894
1895	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1896	if (tl == NULL)
1897		return error;
1898	switch (fxdr_unsigned(int, *tl)) {
1899	case NFSV3SATTRTIME_TOCLIENT:
1900		va->va_vaflags |= VA_UTIMES_CHANGE;
1901		va->va_vaflags &= ~VA_UTIMES_NULL;
1902		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
1903		if (tl == NULL)
1904			return error;
1905		fxdr_nfsv3time(tl, &va->va_mtime);
1906		break;
1907	case NFSV3SATTRTIME_TOSERVER:
1908		va->va_vaflags |= VA_UTIMES_CHANGE;
1909		getnanotime(&va->va_mtime);
1910		break;
1911	};
1912
1913	*dposp = info.nmi_dpos;
1914	*mp = info.nmi_md;
1915	return 0;
1916}
1917
1918void
1919txdr_nfsv2time(const struct timespec *from, struct nfsv2_time *to)
1920{
1921	if (from->tv_nsec == VNOVAL) {
1922		to->nfsv2_sec = nfs_xdrneg1;
1923		to->nfsv2_usec = nfs_xdrneg1;
1924	} else if (from->tv_sec == -1) {
1925		/*
1926		 * can't request a time of -1; send
1927		 * -1.000001 == {-2,999999} instead
1928		 */
1929		to->nfsv2_sec = htonl(-2);
1930		to->nfsv2_usec = htonl(999999);
1931	} else {
1932		to->nfsv2_sec = htonl(from->tv_sec);
1933		to->nfsv2_usec = htonl(from->tv_nsec / 1000);
1934	}
1935}
1936