nfs_subs.c revision 3664
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	@(#)nfs_subs.c	8.3 (Berkeley) 1/4/94
37 * $Id: nfs_subs.c,v 1.6 1994/10/02 17:27:01 phk Exp $
38 */
39
40/*
41 * These functions support the macros and help fiddle mbuf chains for
42 * the nfs op functions. They do things like create the rpc header and
43 * copy data between mbuf chains and uio lists.
44 */
45#include <sys/param.h>
46#include <sys/proc.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/mount.h>
50#include <sys/vnode.h>
51#include <sys/namei.h>
52#include <sys/mbuf.h>
53#include <sys/socket.h>
54#include <sys/stat.h>
55#ifdef VFS_LKM
56#include <sys/sysent.h>
57#include <sys/syscall.h>
58#endif
59
60#include <vm/vm.h>
61
62#include <nfs/rpcv2.h>
63#include <nfs/nfsv2.h>
64#include <nfs/nfsnode.h>
65#include <nfs/nfs.h>
66#include <nfs/xdr_subs.h>
67#include <nfs/nfsm_subs.h>
68#include <nfs/nfsmount.h>
69#include <nfs/nqnfs.h>
70#include <nfs/nfsrtt.h>
71
72#include <miscfs/specfs/specdev.h>
73
74#include <netinet/in.h>
75#ifdef ISO
76#include <netiso/iso.h>
77#endif
78
79#define TRUE	1
80#define	FALSE	0
81
82/*
83 * Data items converted to xdr at startup, since they are constant
84 * This is kinda hokey, but may save a little time doing byte swaps
85 */
86u_long nfs_procids[NFS_NPROCS];
87u_long nfs_xdrneg1;
88u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
89	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
90	rpc_auth_kerb;
91u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
92
93/* And other global data */
94static u_long nfs_xid = 0;
95enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
96extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
97extern int nqnfs_piggy[NFS_NPROCS];
98extern struct nfsrtt nfsrtt;
99extern time_t nqnfsstarttime;
100extern u_long nqnfs_prog, nqnfs_vers;
101extern int nqsrv_clockskew;
102extern int nqsrv_writeslack;
103extern int nqsrv_maxlease;
104
105#ifdef VFS_LKM
106struct getfh_args;
107extern int getfh(struct proc *, struct getfh_args *, int *);
108struct nfssvc_args;
109extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
110#endif
111
112LIST_HEAD(nfsnodehashhead, nfsnode);
113
114/*
115 * Create the header for an rpc request packet
116 * The hsiz is the size of the rest of the nfs request header.
117 * (just used to decide if a cluster is a good idea)
118 */
119struct mbuf *
120nfsm_reqh(vp, procid, hsiz, bposp)
121	struct vnode *vp;
122	u_long procid;
123	int hsiz;
124	caddr_t *bposp;
125{
126	register struct mbuf *mb;
127	register u_long *tl;
128	register caddr_t bpos;
129	struct mbuf *mb2;
130	struct nfsmount *nmp;
131	int nqflag;
132
133	MGET(mb, M_WAIT, MT_DATA);
134	if (hsiz >= MINCLSIZE)
135		MCLGET(mb, M_WAIT);
136	mb->m_len = 0;
137	bpos = mtod(mb, caddr_t);
138
139	/*
140	 * For NQNFS, add lease request.
141	 */
142	if (vp) {
143		nmp = VFSTONFS(vp->v_mount);
144		if (nmp->nm_flag & NFSMNT_NQNFS) {
145			nqflag = NQNFS_NEEDLEASE(vp, procid);
146			if (nqflag) {
147				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
148				*tl++ = txdr_unsigned(nqflag);
149				*tl = txdr_unsigned(nmp->nm_leaseterm);
150			} else {
151				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
152				*tl = 0;
153			}
154		}
155	}
156	/* Finally, return values */
157	*bposp = bpos;
158	return (mb);
159}
160
161/*
162 * Build the RPC header and fill in the authorization info.
163 * The authorization string argument is only used when the credentials
164 * come from outside of the kernel.
165 * Returns the head of the mbuf list.
166 */
167struct mbuf *
168nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
169	mrest_len, mbp, xidp)
170	register struct ucred *cr;
171	int nqnfs;
172	int procid;
173	int auth_type;
174	int auth_len;
175	char *auth_str;
176	struct mbuf *mrest;
177	int mrest_len;
178	struct mbuf **mbp;
179	u_long *xidp;
180{
181	register struct mbuf *mb;
182	register u_long *tl;
183	register caddr_t bpos;
184	register int i;
185	struct mbuf *mreq, *mb2;
186	int siz, grpsiz, authsiz;
187
188	authsiz = nfsm_rndup(auth_len);
189	if (auth_type == RPCAUTH_NQNFS)
190		authsiz += 2 * NFSX_UNSIGNED;
191	MGETHDR(mb, M_WAIT, MT_DATA);
192	if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
193		MCLGET(mb, M_WAIT);
194	} else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
195		MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
196	} else {
197		MH_ALIGN(mb, 8*NFSX_UNSIGNED);
198	}
199	mb->m_len = 0;
200	mreq = mb;
201	bpos = mtod(mb, caddr_t);
202
203	/*
204	 * First the RPC header.
205	 */
206	nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
207	if (++nfs_xid == 0)
208		nfs_xid++;
209	*tl++ = *xidp = txdr_unsigned(nfs_xid);
210	*tl++ = rpc_call;
211	*tl++ = rpc_vers;
212	if (nqnfs) {
213		*tl++ = txdr_unsigned(NQNFS_PROG);
214		*tl++ = txdr_unsigned(NQNFS_VER1);
215	} else {
216		*tl++ = txdr_unsigned(NFS_PROG);
217		*tl++ = txdr_unsigned(NFS_VER2);
218	}
219	*tl++ = txdr_unsigned(procid);
220
221	/*
222	 * And then the authorization cred.
223	 */
224	*tl++ = txdr_unsigned(auth_type);
225	*tl = txdr_unsigned(authsiz);
226	switch (auth_type) {
227	case RPCAUTH_UNIX:
228		nfsm_build(tl, u_long *, auth_len);
229		*tl++ = 0;		/* stamp ?? */
230		*tl++ = 0;		/* NULL hostname */
231		*tl++ = txdr_unsigned(cr->cr_uid);
232		*tl++ = txdr_unsigned(cr->cr_groups[0]);
233		grpsiz = (auth_len >> 2) - 5;
234		*tl++ = txdr_unsigned(grpsiz);
235		for (i = 1; i <= grpsiz; i++)
236			*tl++ = txdr_unsigned(cr->cr_groups[i]);
237		break;
238	case RPCAUTH_NQNFS:
239		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
240		*tl++ = txdr_unsigned(cr->cr_uid);
241		*tl = txdr_unsigned(auth_len);
242		siz = auth_len;
243		while (siz > 0) {
244			if (M_TRAILINGSPACE(mb) == 0) {
245				MGET(mb2, M_WAIT, MT_DATA);
246				if (siz >= MINCLSIZE)
247					MCLGET(mb2, M_WAIT);
248				mb->m_next = mb2;
249				mb = mb2;
250				mb->m_len = 0;
251				bpos = mtod(mb, caddr_t);
252			}
253			i = min(siz, M_TRAILINGSPACE(mb));
254			bcopy(auth_str, bpos, i);
255			mb->m_len += i;
256			auth_str += i;
257			bpos += i;
258			siz -= i;
259		}
260		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
261			for (i = 0; i < siz; i++)
262				*bpos++ = '\0';
263			mb->m_len += siz;
264		}
265		break;
266	};
267	nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
268	*tl++ = txdr_unsigned(RPCAUTH_NULL);
269	*tl = 0;
270	mb->m_next = mrest;
271	mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
272	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
273	*mbp = mb;
274	return (mreq);
275}
276
277/*
278 * copies mbuf chain to the uio scatter/gather list
279 */
280int
281nfsm_mbuftouio(mrep, uiop, siz, dpos)
282	struct mbuf **mrep;
283	register struct uio *uiop;
284	int siz;
285	caddr_t *dpos;
286{
287	register char *mbufcp, *uiocp;
288	register int xfer, left, len;
289	register struct mbuf *mp;
290	long uiosiz, rem;
291	int error = 0;
292
293	mp = *mrep;
294	mbufcp = *dpos;
295	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
296	rem = nfsm_rndup(siz)-siz;
297	while (siz > 0) {
298		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
299			return (EFBIG);
300		left = uiop->uio_iov->iov_len;
301		uiocp = uiop->uio_iov->iov_base;
302		if (left > siz)
303			left = siz;
304		uiosiz = left;
305		while (left > 0) {
306			while (len == 0) {
307				mp = mp->m_next;
308				if (mp == NULL)
309					return (EBADRPC);
310				mbufcp = mtod(mp, caddr_t);
311				len = mp->m_len;
312			}
313			xfer = (left > len) ? len : left;
314#ifdef notdef
315			/* Not Yet.. */
316			if (uiop->uio_iov->iov_op != NULL)
317				(*(uiop->uio_iov->iov_op))
318				(mbufcp, uiocp, xfer);
319			else
320#endif
321			if (uiop->uio_segflg == UIO_SYSSPACE)
322				bcopy(mbufcp, uiocp, xfer);
323			else
324				copyout(mbufcp, uiocp, xfer);
325			left -= xfer;
326			len -= xfer;
327			mbufcp += xfer;
328			uiocp += xfer;
329			uiop->uio_offset += xfer;
330			uiop->uio_resid -= xfer;
331		}
332		if (uiop->uio_iov->iov_len <= siz) {
333			uiop->uio_iovcnt--;
334			uiop->uio_iov++;
335		} else {
336			uiop->uio_iov->iov_base += uiosiz;
337			uiop->uio_iov->iov_len -= uiosiz;
338		}
339		siz -= uiosiz;
340	}
341	*dpos = mbufcp;
342	*mrep = mp;
343	if (rem > 0) {
344		if (len < rem)
345			error = nfs_adv(mrep, dpos, rem, len);
346		else
347			*dpos += rem;
348	}
349	return (error);
350}
351
352/*
353 * copies a uio scatter/gather list to an mbuf chain...
354 */
355int
356nfsm_uiotombuf(uiop, mq, siz, bpos)
357	register struct uio *uiop;
358	struct mbuf **mq;
359	int siz;
360	caddr_t *bpos;
361{
362	register char *uiocp;
363	register struct mbuf *mp, *mp2;
364	register int xfer, left, mlen;
365	int uiosiz, clflg, rem;
366	char *cp;
367
368	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
369		clflg = 1;
370	else
371		clflg = 0;
372	rem = nfsm_rndup(siz)-siz;
373	mp = mp2 = *mq;
374	while (siz > 0) {
375		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
376			return (EINVAL);
377		left = uiop->uio_iov->iov_len;
378		uiocp = uiop->uio_iov->iov_base;
379		if (left > siz)
380			left = siz;
381		uiosiz = left;
382		while (left > 0) {
383			mlen = M_TRAILINGSPACE(mp);
384			if (mlen == 0) {
385				MGET(mp, M_WAIT, MT_DATA);
386				if (clflg)
387					MCLGET(mp, M_WAIT);
388				mp->m_len = 0;
389				mp2->m_next = mp;
390				mp2 = mp;
391				mlen = M_TRAILINGSPACE(mp);
392			}
393			xfer = (left > mlen) ? mlen : left;
394#ifdef notdef
395			/* Not Yet.. */
396			if (uiop->uio_iov->iov_op != NULL)
397				(*(uiop->uio_iov->iov_op))
398				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
399			else
400#endif
401			if (uiop->uio_segflg == UIO_SYSSPACE)
402				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
403			else
404				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
405			mp->m_len += xfer;
406			left -= xfer;
407			uiocp += xfer;
408			uiop->uio_offset += xfer;
409			uiop->uio_resid -= xfer;
410		}
411		if (uiop->uio_iov->iov_len <= siz) {
412			uiop->uio_iovcnt--;
413			uiop->uio_iov++;
414		} else {
415			uiop->uio_iov->iov_base += uiosiz;
416			uiop->uio_iov->iov_len -= uiosiz;
417		}
418		siz -= uiosiz;
419	}
420	if (rem > 0) {
421		if (rem > M_TRAILINGSPACE(mp)) {
422			MGET(mp, M_WAIT, MT_DATA);
423			mp->m_len = 0;
424			mp2->m_next = mp;
425		}
426		cp = mtod(mp, caddr_t)+mp->m_len;
427		for (left = 0; left < rem; left++)
428			*cp++ = '\0';
429		mp->m_len += rem;
430		*bpos = cp;
431	} else
432		*bpos = mtod(mp, caddr_t)+mp->m_len;
433	*mq = mp;
434	return (0);
435}
436
437/*
438 * Help break down an mbuf chain by setting the first siz bytes contiguous
439 * pointed to by returned val.
440 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
441 * cases. (The macros use the vars. dpos and dpos2)
442 */
443int
444nfsm_disct(mdp, dposp, siz, left, cp2)
445	struct mbuf **mdp;
446	caddr_t *dposp;
447	int siz;
448	int left;
449	caddr_t *cp2;
450{
451	register struct mbuf *mp, *mp2;
452	register int siz2, xfer;
453	register caddr_t p;
454
455	mp = *mdp;
456	while (left == 0) {
457		*mdp = mp = mp->m_next;
458		if (mp == NULL)
459			return (EBADRPC);
460		left = mp->m_len;
461		*dposp = mtod(mp, caddr_t);
462	}
463	if (left >= siz) {
464		*cp2 = *dposp;
465		*dposp += siz;
466	} else if (mp->m_next == NULL) {
467		return (EBADRPC);
468	} else if (siz > MHLEN) {
469		panic("nfs S too big");
470	} else {
471		MGET(mp2, M_WAIT, MT_DATA);
472		mp2->m_next = mp->m_next;
473		mp->m_next = mp2;
474		mp->m_len -= left;
475		mp = mp2;
476		*cp2 = p = mtod(mp, caddr_t);
477		bcopy(*dposp, p, left);		/* Copy what was left */
478		siz2 = siz-left;
479		p += left;
480		mp2 = mp->m_next;
481		/* Loop around copying up the siz2 bytes */
482		while (siz2 > 0) {
483			if (mp2 == NULL)
484				return (EBADRPC);
485			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
486			if (xfer > 0) {
487				bcopy(mtod(mp2, caddr_t), p, xfer);
488				NFSMADV(mp2, xfer);
489				mp2->m_len -= xfer;
490				p += xfer;
491				siz2 -= xfer;
492			}
493			if (siz2 > 0)
494				mp2 = mp2->m_next;
495		}
496		mp->m_len = siz;
497		*mdp = mp2;
498		*dposp = mtod(mp2, caddr_t);
499	}
500	return (0);
501}
502
503/*
504 * Advance the position in the mbuf chain.
505 */
506int
507nfs_adv(mdp, dposp, offs, left)
508	struct mbuf **mdp;
509	caddr_t *dposp;
510	int offs;
511	int left;
512{
513	register struct mbuf *m;
514	register int s;
515
516	m = *mdp;
517	s = left;
518	while (s < offs) {
519		offs -= s;
520		m = m->m_next;
521		if (m == NULL)
522			return (EBADRPC);
523		s = m->m_len;
524	}
525	*mdp = m;
526	*dposp = mtod(m, caddr_t)+offs;
527	return (0);
528}
529
530/*
531 * Copy a string into mbufs for the hard cases...
532 */
533int
534nfsm_strtmbuf(mb, bpos, cp, siz)
535	struct mbuf **mb;
536	char **bpos;
537	char *cp;
538	long siz;
539{
540	register struct mbuf *m1 = 0, *m2;
541	long left, xfer, len, tlen;
542	u_long *tl;
543	int putsize;
544
545	putsize = 1;
546	m2 = *mb;
547	left = M_TRAILINGSPACE(m2);
548	if (left > 0) {
549		tl = ((u_long *)(*bpos));
550		*tl++ = txdr_unsigned(siz);
551		putsize = 0;
552		left -= NFSX_UNSIGNED;
553		m2->m_len += NFSX_UNSIGNED;
554		if (left > 0) {
555			bcopy(cp, (caddr_t) tl, left);
556			siz -= left;
557			cp += left;
558			m2->m_len += left;
559			left = 0;
560		}
561	}
562	/* Loop around adding mbufs */
563	while (siz > 0) {
564		MGET(m1, M_WAIT, MT_DATA);
565		if (siz > MLEN)
566			MCLGET(m1, M_WAIT);
567		m1->m_len = NFSMSIZ(m1);
568		m2->m_next = m1;
569		m2 = m1;
570		tl = mtod(m1, u_long *);
571		tlen = 0;
572		if (putsize) {
573			*tl++ = txdr_unsigned(siz);
574			m1->m_len -= NFSX_UNSIGNED;
575			tlen = NFSX_UNSIGNED;
576			putsize = 0;
577		}
578		if (siz < m1->m_len) {
579			len = nfsm_rndup(siz);
580			xfer = siz;
581			if (xfer < len)
582				*(tl+(xfer>>2)) = 0;
583		} else {
584			xfer = len = m1->m_len;
585		}
586		bcopy(cp, (caddr_t) tl, xfer);
587		m1->m_len = len+tlen;
588		siz -= xfer;
589		cp += xfer;
590	}
591	*mb = m1;
592	*bpos = mtod(m1, caddr_t)+m1->m_len;
593	return (0);
594}
595
596/*
597 * Called once to initialize data structures...
598 */
599int
600nfs_init()
601{
602	register int i;
603
604	nfsrtt.pos = 0;
605	rpc_vers = txdr_unsigned(RPC_VER2);
606	rpc_call = txdr_unsigned(RPC_CALL);
607	rpc_reply = txdr_unsigned(RPC_REPLY);
608	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
609	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
610	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
611	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
612	rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
613	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
614	rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
615	nfs_vers = txdr_unsigned(NFS_VER2);
616	nfs_prog = txdr_unsigned(NFS_PROG);
617	nfs_true = txdr_unsigned(TRUE);
618	nfs_false = txdr_unsigned(FALSE);
619	nfs_xdrneg1 = txdr_unsigned(-1);
620	/* Loop thru nfs procids */
621	for (i = 0; i < NFS_NPROCS; i++)
622		nfs_procids[i] = txdr_unsigned(i);
623	/* Ensure async daemons disabled */
624	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
625		nfs_iodwant[i] = (struct proc *)0;
626	TAILQ_INIT(&nfs_bufq);
627	nfs_nhinit();			/* Init the nfsnode table */
628	nfsrv_init(0);			/* Init server data structures */
629	nfsrv_initcache();		/* Init the server request cache */
630
631	/*
632	 * Initialize the nqnfs server stuff.
633	 */
634	if (nqnfsstarttime == 0) {
635		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
636			+ nqsrv_clockskew + nqsrv_writeslack;
637		NQLOADNOVRAM(nqnfsstarttime);
638		nqnfs_prog = txdr_unsigned(NQNFS_PROG);
639		nqnfs_vers = txdr_unsigned(NQNFS_VER1);
640		CIRCLEQ_INIT(&nqtimerhead);
641		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
642	}
643
644	/*
645	 * Initialize reply list and start timer
646	 */
647	TAILQ_INIT(&nfs_reqq);
648	nfs_timer(0);
649
650	/*
651	 * Set up lease_check and lease_updatetime so that other parts
652	 * of the system can call us, if we are loadable.
653	 */
654	lease_check = nfs_lease_check;
655	lease_updatetime = nfs_lease_updatetime;
656	vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */
657#ifdef VFS_LKM
658	sysent[SYS_nfssvc].sy_narg = 2;
659	sysent[SYS_nfssvc].sy_call = nfssvc;
660	sysent[SYS_getfh].sy_narg = 2;
661	sysent[SYS_getfh].sy_call = getfh;
662#endif
663
664	return (0);
665}
666
667/*
668 * Attribute cache routines.
669 * nfs_loadattrcache() - loads or updates the cache contents from attributes
670 *	that are on the mbuf list
671 * nfs_getattrcache() - returns valid attributes if found in cache, returns
672 *	error otherwise
673 */
674
675/*
676 * Load the attribute cache (that lives in the nfsnode entry) with
677 * the values on the mbuf list and
678 * Iff vap not NULL
679 *    copy the attributes to *vaper
680 */
681int
682nfs_loadattrcache(vpp, mdp, dposp, vaper)
683	struct vnode **vpp;
684	struct mbuf **mdp;
685	caddr_t *dposp;
686	struct vattr *vaper;
687{
688	register struct vnode *vp = *vpp;
689	register struct vattr *vap;
690	register struct nfsv2_fattr *fp;
691	extern int (**spec_nfsv2nodeop_p)();
692	register struct nfsnode *np;
693	register struct nfsnodehashhead *nhpp;
694	register long t1;
695	caddr_t dpos, cp2;
696	int error = 0, isnq;
697	struct mbuf *md;
698	enum vtype vtyp;
699	u_short vmode;
700	long rdev;
701	struct timespec mtime;
702	struct vnode *nvp;
703
704	md = *mdp;
705	dpos = *dposp;
706	t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
707	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
708	error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2);
709	if (error)
710		return (error);
711	fp = (struct nfsv2_fattr *)cp2;
712	vtyp = nfstov_type(fp->fa_type);
713	vmode = fxdr_unsigned(u_short, fp->fa_mode);
714	if (vtyp == VNON || vtyp == VREG)
715		vtyp = IFTOVT(vmode);
716	if (isnq) {
717		rdev = fxdr_unsigned(long, fp->fa_nqrdev);
718		fxdr_nqtime(&fp->fa_nqmtime, &mtime);
719	} else {
720		rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
721		fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
722	}
723	/*
724	 * If v_type == VNON it is a new node, so fill in the v_type,
725	 * n_mtime fields. Check to see if it represents a special
726	 * device, and if so, check for a possible alias. Once the
727	 * correct vnode has been obtained, fill in the rest of the
728	 * information.
729	 */
730	np = VTONFS(vp);
731	if (vp->v_type == VNON) {
732		if (vtyp == VCHR && rdev == 0xffffffff)
733			vp->v_type = vtyp = VFIFO;
734		else
735			vp->v_type = vtyp;
736		if (vp->v_type == VFIFO) {
737			extern int (**fifo_nfsv2nodeop_p)();
738			vp->v_op = fifo_nfsv2nodeop_p;
739		}
740		if (vp->v_type == VCHR || vp->v_type == VBLK) {
741			vp->v_op = spec_nfsv2nodeop_p;
742			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
743			if (nvp) {
744				/*
745				 * Discard unneeded vnode, but save its nfsnode.
746				 */
747				LIST_REMOVE(np, n_hash);
748				nvp->v_data = vp->v_data;
749				vp->v_data = NULL;
750				vp->v_op = spec_vnodeop_p;
751				vrele(vp);
752				vgone(vp);
753				/*
754				 * Reinitialize aliased node.
755				 */
756				np->n_vnode = nvp;
757				nhpp = nfs_hash(&np->n_fh);
758				LIST_INSERT_HEAD(nhpp, np, n_hash);
759				*vpp = vp = nvp;
760			}
761		}
762		np->n_mtime = mtime.ts_sec;
763	}
764	vap = &np->n_vattr;
765	vap->va_type = vtyp;
766	vap->va_mode = (vmode & 07777);
767	vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
768	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
769	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
770	vap->va_rdev = (dev_t)rdev;
771	vap->va_mtime = mtime;
772	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
773	if (isnq) {
774		fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
775		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
776		fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
777		vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
778		fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
779		vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
780		fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
781		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
782		fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
783	} else {
784		vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
785		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
786		vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
787		vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
788		fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
789		vap->va_flags = 0;
790		fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime);
791		vap->va_gen = 0;
792		vap->va_filerev = 0;
793	}
794	if (vap->va_size != np->n_size) {
795		if (vap->va_type == VREG) {
796			if (np->n_flag & NMODIFIED) {
797				if (vap->va_size < np->n_size)
798					vap->va_size = np->n_size;
799				else
800					np->n_size = vap->va_size;
801			} else
802				np->n_size = vap->va_size;
803			vnode_pager_setsize(vp, (u_long)np->n_size);
804		} else
805			np->n_size = vap->va_size;
806	}
807	np->n_attrstamp = time.tv_sec;
808	*dposp = dpos;
809	*mdp = md;
810	if (vaper != NULL) {
811		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
812#ifdef notdef
813		if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
814		if (np->n_size > vap->va_size)
815			vaper->va_size = np->n_size;
816#endif
817		if (np->n_flag & NCHG) {
818			if (np->n_flag & NACC) {
819				vaper->va_atime.ts_sec = np->n_atim.tv_sec;
820				vaper->va_atime.ts_nsec =
821				    np->n_atim.tv_usec * 1000;
822			}
823			if (np->n_flag & NUPD) {
824				vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
825				vaper->va_mtime.ts_nsec =
826				    np->n_mtim.tv_usec * 1000;
827			}
828		}
829	}
830	return (0);
831}
832
833/*
834 * Check the time stamp
835 * If the cache is valid, copy contents to *vap and return 0
836 * otherwise return an error
837 */
838int
839nfs_getattrcache(vp, vaper)
840	register struct vnode *vp;
841	struct vattr *vaper;
842{
843	register struct nfsnode *np = VTONFS(vp);
844	register struct vattr *vap;
845
846	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
847		if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
848			nfsstats.attrcache_misses++;
849			return (ENOENT);
850		}
851	} else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
852		nfsstats.attrcache_misses++;
853		return (ENOENT);
854	}
855	nfsstats.attrcache_hits++;
856	vap = &np->n_vattr;
857	if (vap->va_size != np->n_size) {
858		if (vap->va_type == VREG) {
859			if (np->n_flag & NMODIFIED) {
860				if (vap->va_size < np->n_size)
861					vap->va_size = np->n_size;
862				else
863					np->n_size = vap->va_size;
864			} else
865				np->n_size = vap->va_size;
866			vnode_pager_setsize(vp, (u_long)np->n_size);
867		} else
868			np->n_size = vap->va_size;
869	}
870	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
871#ifdef notdef
872	if ((np->n_flag & NMODIFIED) == 0) {
873		np->n_size = vaper->va_size;
874		vnode_pager_setsize(vp, (u_long)np->n_size);
875	} else if (np->n_size > vaper->va_size)
876	if (np->n_size > vaper->va_size)
877		vaper->va_size = np->n_size;
878#endif
879	if (np->n_flag & NCHG) {
880		if (np->n_flag & NACC) {
881			vaper->va_atime.ts_sec = np->n_atim.tv_sec;
882			vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
883		}
884		if (np->n_flag & NUPD) {
885			vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
886			vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
887		}
888	}
889	return (0);
890}
891
892/*
893 * Set up nameidata for a lookup() call and do it
894 */
895int
896nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
897	register struct nameidata *ndp;
898	fhandle_t *fhp;
899	int len;
900	struct nfssvc_sock *slp;
901	struct mbuf *nam;
902	struct mbuf **mdp;
903	caddr_t *dposp;
904	struct proc *p;
905{
906	register int i, rem;
907	register struct mbuf *md;
908	register char *fromcp, *tocp;
909	struct vnode *dp;
910	int error, rdonly;
911	struct componentname *cnp = &ndp->ni_cnd;
912
913	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
914	/*
915	 * Copy the name from the mbuf list to ndp->ni_pnbuf
916	 * and set the various ndp fields appropriately.
917	 */
918	fromcp = *dposp;
919	tocp = cnp->cn_pnbuf;
920	md = *mdp;
921	rem = mtod(md, caddr_t) + md->m_len - fromcp;
922	cnp->cn_hash = 0;
923	for (i = 0; i < len; i++) {
924		while (rem == 0) {
925			md = md->m_next;
926			if (md == NULL) {
927				error = EBADRPC;
928				goto out;
929			}
930			fromcp = mtod(md, caddr_t);
931			rem = md->m_len;
932		}
933		if (*fromcp == '\0' || *fromcp == '/') {
934			error = EINVAL;
935			goto out;
936		}
937		cnp->cn_hash += (unsigned char)*fromcp;
938		*tocp++ = *fromcp++;
939		rem--;
940	}
941	*tocp = '\0';
942	*mdp = md;
943	*dposp = fromcp;
944	len = nfsm_rndup(len)-len;
945	if (len > 0) {
946		if (rem >= len)
947			*dposp += len;
948		else {
949			error = nfs_adv(mdp, dposp, len, rem);
950			if (error)
951				goto out;
952		}
953	}
954	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
955	cnp->cn_nameptr = cnp->cn_pnbuf;
956	/*
957	 * Extract and set starting directory.
958	 */
959	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
960	    nam, &rdonly);
961	if (error)
962		goto out;
963	if (dp->v_type != VDIR) {
964		vrele(dp);
965		error = ENOTDIR;
966		goto out;
967	}
968	ndp->ni_startdir = dp;
969	if (rdonly)
970		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
971	else
972		cnp->cn_flags |= NOCROSSMOUNT;
973	/*
974	 * And call lookup() to do the real work
975	 */
976	cnp->cn_proc = p;
977	error = lookup(ndp);
978	if (error)
979		goto out;
980	/*
981	 * Check for encountering a symbolic link
982	 */
983	if (cnp->cn_flags & ISSYMLINK) {
984		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
985			vput(ndp->ni_dvp);
986		else
987			vrele(ndp->ni_dvp);
988		vput(ndp->ni_vp);
989		ndp->ni_vp = NULL;
990		error = EINVAL;
991		goto out;
992	}
993	/*
994	 * Check for saved name request
995	 */
996	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
997		cnp->cn_flags |= HASBUF;
998		return (0);
999	}
1000out:
1001	FREE(cnp->cn_pnbuf, M_NAMEI);
1002	return (error);
1003}
1004
1005/*
1006 * A fiddled version of m_adj() that ensures null fill to a long
1007 * boundary and only trims off the back end
1008 */
1009void
1010nfsm_adj(mp, len, nul)
1011	struct mbuf *mp;
1012	register int len;
1013	int nul;
1014{
1015	register struct mbuf *m;
1016	register int count, i;
1017	register char *cp;
1018
1019	/*
1020	 * Trim from tail.  Scan the mbuf chain,
1021	 * calculating its length and finding the last mbuf.
1022	 * If the adjustment only affects this mbuf, then just
1023	 * adjust and return.  Otherwise, rescan and truncate
1024	 * after the remaining size.
1025	 */
1026	count = 0;
1027	m = mp;
1028	for (;;) {
1029		count += m->m_len;
1030		if (m->m_next == (struct mbuf *)0)
1031			break;
1032		m = m->m_next;
1033	}
1034	if (m->m_len > len) {
1035		m->m_len -= len;
1036		if (nul > 0) {
1037			cp = mtod(m, caddr_t)+m->m_len-nul;
1038			for (i = 0; i < nul; i++)
1039				*cp++ = '\0';
1040		}
1041		return;
1042	}
1043	count -= len;
1044	if (count < 0)
1045		count = 0;
1046	/*
1047	 * Correct length for chain is "count".
1048	 * Find the mbuf with last data, adjust its length,
1049	 * and toss data from remaining mbufs on chain.
1050	 */
1051	for (m = mp; m; m = m->m_next) {
1052		if (m->m_len >= count) {
1053			m->m_len = count;
1054			if (nul > 0) {
1055				cp = mtod(m, caddr_t)+m->m_len-nul;
1056				for (i = 0; i < nul; i++)
1057					*cp++ = '\0';
1058			}
1059			break;
1060		}
1061		count -= m->m_len;
1062	}
1063	for (m = m->m_next;m;m = m->m_next)
1064		m->m_len = 0;
1065}
1066
1067/*
1068 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1069 * 	- look up fsid in mount list (if not found ret error)
1070 *	- get vp and export rights by calling VFS_FHTOVP()
1071 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1072 *	- if not lockflag unlock it with VOP_UNLOCK()
1073 */
1074int
1075nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
1076	fhandle_t *fhp;
1077	int lockflag;
1078	struct vnode **vpp;
1079	struct ucred *cred;
1080	struct nfssvc_sock *slp;
1081	struct mbuf *nam;
1082	int *rdonlyp;
1083{
1084	register struct mount *mp;
1085	register struct nfsuid *uidp;
1086	register int i;
1087	struct ucred *credanon;
1088	int error, exflags;
1089
1090	*vpp = (struct vnode *)0;
1091	mp = getvfs(&fhp->fh_fsid);
1092	if (!mp)
1093		return (ESTALE);
1094	error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
1095	if (error)
1096		return (error);
1097	/*
1098	 * Check/setup credentials.
1099	 */
1100	if (exflags & MNT_EXKERB) {
1101		for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0;
1102		    uidp = uidp->nu_hash.le_next) {
1103			if (uidp->nu_uid == cred->cr_uid)
1104				break;
1105		}
1106		if (uidp == 0) {
1107			vput(*vpp);
1108			return (NQNFS_AUTHERR);
1109		}
1110		cred->cr_uid = uidp->nu_cr.cr_uid;
1111		for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
1112			cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
1113		cred->cr_ngroups = i;
1114	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1115		cred->cr_uid = credanon->cr_uid;
1116		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1117			cred->cr_groups[i] = credanon->cr_groups[i];
1118		cred->cr_ngroups = i;
1119	}
1120	if (exflags & MNT_EXRDONLY)
1121		*rdonlyp = 1;
1122	else
1123		*rdonlyp = 0;
1124	if (!lockflag)
1125		VOP_UNLOCK(*vpp);
1126	return (0);
1127}
1128
1129/*
1130 * This function compares two net addresses by family and returns TRUE
1131 * if they are the same host.
1132 * If there is any doubt, return FALSE.
1133 * The AF_INET family is handled as a special case so that address mbufs
1134 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1135 */
1136int
1137netaddr_match(family, haddr, nam)
1138	int family;
1139	union nethostaddr *haddr;
1140	struct mbuf *nam;
1141{
1142	register struct sockaddr_in *inetaddr;
1143
1144	switch (family) {
1145	case AF_INET:
1146		inetaddr = mtod(nam, struct sockaddr_in *);
1147		if (inetaddr->sin_family == AF_INET &&
1148		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1149			return (1);
1150		break;
1151#ifdef ISO
1152	case AF_ISO:
1153	    {
1154		register struct sockaddr_iso *isoaddr1, *isoaddr2;
1155
1156		isoaddr1 = mtod(nam, struct sockaddr_iso *);
1157		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
1158		if (isoaddr1->siso_family == AF_ISO &&
1159		    isoaddr1->siso_nlen > 0 &&
1160		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1161		    SAME_ISOADDR(isoaddr1, isoaddr2))
1162			return (1);
1163		break;
1164	    }
1165#endif	/* ISO */
1166	default:
1167		break;
1168	};
1169	return (0);
1170}
1171