if_faith.c revision 120727
195023Ssuz/*	$KAME: if_faith.c,v 1.23 2001/12/17 13:55:29 sumikawa Exp $	*/
278064Sume
354263Sshin/*
454263Sshin * Copyright (c) 1982, 1986, 1993
554263Sshin *	The Regents of the University of California.  All rights reserved.
654263Sshin *
754263Sshin * Redistribution and use in source and binary forms, with or without
854263Sshin * modification, are permitted provided that the following conditions
954263Sshin * are met:
1054263Sshin * 1. Redistributions of source code must retain the above copyright
1154263Sshin *    notice, this list of conditions and the following disclaimer.
1254263Sshin * 2. Redistributions in binary form must reproduce the above copyright
1354263Sshin *    notice, this list of conditions and the following disclaimer in the
1454263Sshin *    documentation and/or other materials provided with the distribution.
1554263Sshin * 3. All advertising materials mentioning features or use of this software
1654263Sshin *    must display the following acknowledgement:
1754263Sshin *	This product includes software developed by the University of
1854263Sshin *	California, Berkeley and its contributors.
1954263Sshin * 4. Neither the name of the University nor the names of its contributors
2054263Sshin *    may be used to endorse or promote products derived from this software
2154263Sshin *    without specific prior written permission.
2254263Sshin *
2354263Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2454263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2554263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2654263Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2754263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2854263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2954263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3054263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3154263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3254263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3354263Sshin * SUCH DAMAGE.
3454263Sshin *
3554263Sshin * $FreeBSD: head/sys/net/if_faith.c 120727 2003-10-04 03:44:50Z sam $
3654263Sshin */
3754263Sshin/*
3854263Sshin * derived from
3954263Sshin *	@(#)if_loop.c	8.1 (Berkeley) 6/10/93
4054263Sshin * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp
4154263Sshin */
4254263Sshin
4354263Sshin/*
4454263Sshin * Loopback interface driver for protocol testing and timing.
4554263Sshin */
4678064Sume#include "opt_inet.h"
4778064Sume#include "opt_inet6.h"
4854263Sshin
4954263Sshin#include <sys/param.h>
5054263Sshin#include <sys/systm.h>
5154263Sshin#include <sys/kernel.h>
5254263Sshin#include <sys/mbuf.h>
5354263Sshin#include <sys/socket.h>
5478064Sume#include <sys/errno.h>
5554263Sshin#include <sys/sockio.h>
5678064Sume#include <sys/time.h>
5778064Sume#include <sys/queue.h>
5883934Sbrooks#include <sys/types.h>
5983934Sbrooks#include <sys/malloc.h>
6054263Sshin
6154263Sshin#include <net/if.h>
6254263Sshin#include <net/if_types.h>
6354263Sshin#include <net/netisr.h>
6454263Sshin#include <net/route.h>
6554263Sshin#include <net/bpf.h>
6654263Sshin
6778064Sume#ifdef	INET
6878064Sume#include <netinet/in.h>
6978064Sume#include <netinet/in_systm.h>
7078064Sume#include <netinet/in_var.h>
7178064Sume#include <netinet/ip.h>
7278064Sume#endif
7378064Sume
7478064Sume#ifdef INET6
7578064Sume#ifndef INET
7678064Sume#include <netinet/in.h>
7778064Sume#endif
7878064Sume#include <netinet6/in6_var.h>
7978064Sume#include <netinet/ip6.h>
8078064Sume#include <netinet6/ip6_var.h>
8178064Sume#endif
8278064Sume
8371991Speter#include <net/net_osdep.h>
8471991Speter
8583934Sbrooks#define FAITHNAME	"faith"
8683934Sbrooks
8783934Sbrooksstruct faith_softc {
8883934Sbrooks	struct ifnet sc_if;	/* must be first */
8983934Sbrooks	LIST_ENTRY(faith_softc) sc_list;
9083934Sbrooks};
9183934Sbrooks
9292725Salfredstatic int faithioctl(struct ifnet *, u_long, caddr_t);
9392725Salfredint faithoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
9492725Salfred	struct rtentry *);
9592725Salfredstatic void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *);
9691317Sdillon#ifdef INET6
9792725Salfredstatic int faithprefix(struct in6_addr *);
9891317Sdillon#endif
9954263Sshin
10092725Salfredstatic int faithmodevent(module_t, int, void *);
10178064Sume
10283934Sbrooksstatic MALLOC_DEFINE(M_FAITH, FAITHNAME, "Firewall Assisted Tunnel Interface");
10389065Smsmithstatic LIST_HEAD(, faith_softc) faith_softc_list;
10454263Sshin
10592725Salfredint	faith_clone_create(struct if_clone *, int);
10697289Sbrooksvoid	faith_clone_destroy(struct ifnet *);
10783934Sbrooks
10892081Smuxstruct if_clone faith_cloner = IF_CLONE_INITIALIZER(FAITHNAME,
10997289Sbrooks    faith_clone_create, faith_clone_destroy, 0, IF_MAXUNIT);
11083934Sbrooks
11154263Sshin#define	FAITHMTU	1500
11254263Sshin
11383934Sbrooksstatic int
11483934Sbrooksfaithmodevent(mod, type, data)
11583934Sbrooks	module_t mod;
11683934Sbrooks	int type;
11783934Sbrooks	void *data;
11854263Sshin{
11954263Sshin
12083934Sbrooks	switch (type) {
12183934Sbrooks	case MOD_LOAD:
12283934Sbrooks		LIST_INIT(&faith_softc_list);
12383934Sbrooks		if_clone_attach(&faith_cloner);
12483934Sbrooks
12583934Sbrooks#ifdef INET6
12683934Sbrooks		faithprefix_p = faithprefix;
12778064Sume#endif
12883934Sbrooks
12983934Sbrooks		break;
13083934Sbrooks	case MOD_UNLOAD:
13183934Sbrooks#ifdef INET6
13283934Sbrooks		faithprefix_p = NULL;
13378064Sume#endif
13483934Sbrooks
13583934Sbrooks		if_clone_detach(&faith_cloner);
13683934Sbrooks
13783934Sbrooks		while (!LIST_EMPTY(&faith_softc_list))
13883934Sbrooks			faith_clone_destroy(
13983934Sbrooks			    &LIST_FIRST(&faith_softc_list)->sc_if);
14083934Sbrooks
14183934Sbrooks		break;
14254263Sshin	}
14383934Sbrooks	return 0;
14454263Sshin}
14578064Sume
14683934Sbrooksstatic moduledata_t faith_mod = {
14783934Sbrooks	"if_faith",
14883934Sbrooks	faithmodevent,
14983934Sbrooks	0
15083934Sbrooks};
15183934Sbrooks
15283934SbrooksDECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
15383934SbrooksMODULE_VERSION(if_faith, 1);
15483934Sbrooks
15578064Sumeint
15683934Sbrooksfaith_clone_create(ifc, unit)
15783934Sbrooks	struct if_clone *ifc;
15892081Smux	int unit;
15983934Sbrooks{
16083934Sbrooks	struct faith_softc *sc;
16183934Sbrooks
162111119Simp	sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK);
16383934Sbrooks	bzero(sc, sizeof(struct faith_softc));
16483934Sbrooks
16583934Sbrooks	sc->sc_if.if_softc = sc;
16683934Sbrooks	sc->sc_if.if_name = FAITHNAME;
16792081Smux	sc->sc_if.if_unit = unit;
16883934Sbrooks
16983934Sbrooks	sc->sc_if.if_mtu = FAITHMTU;
17083934Sbrooks	/* Change to BROADCAST experimentaly to announce its prefix. */
17183934Sbrooks	sc->sc_if.if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST;
17283934Sbrooks	sc->sc_if.if_ioctl = faithioctl;
17383934Sbrooks	sc->sc_if.if_output = faithoutput;
17483934Sbrooks	sc->sc_if.if_type = IFT_FAITH;
17583934Sbrooks	sc->sc_if.if_hdrlen = 0;
17683934Sbrooks	sc->sc_if.if_addrlen = 0;
17788034Sbrooks	sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
17883934Sbrooks	if_attach(&sc->sc_if);
17983934Sbrooks	bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
18083934Sbrooks	LIST_INSERT_HEAD(&faith_softc_list, sc, sc_list);
18183934Sbrooks	return (0);
18283934Sbrooks}
18383934Sbrooks
18497289Sbrooksvoid
18583934Sbrooksfaith_clone_destroy(ifp)
18683934Sbrooks	struct ifnet *ifp;
18783934Sbrooks{
18883934Sbrooks	struct faith_softc *sc = (void *) ifp;
18983934Sbrooks
19083934Sbrooks	LIST_REMOVE(sc, sc_list);
19183934Sbrooks	bpfdetach(ifp);
19283934Sbrooks	if_detach(ifp);
19383934Sbrooks
19483934Sbrooks	free(sc, M_FAITH);
19583934Sbrooks}
19683934Sbrooks
19783934Sbrooksint
19878064Sumefaithoutput(ifp, m, dst, rt)
19978064Sume	struct ifnet *ifp;
20078064Sume	struct mbuf *m;
20178064Sume	struct sockaddr *dst;
20278064Sume	struct rtentry *rt;
20378064Sume{
20478064Sume	int isr;
20578064Sume
206113255Sdes	M_ASSERTPKTHDR(m);
20783934Sbrooks
20878064Sume	/* BPF write needs to be handled specially */
20978064Sume	if (dst->sa_family == AF_UNSPEC) {
21078064Sume		dst->sa_family = *(mtod(m, int *));
21178064Sume		m->m_len -= sizeof(int);
21278064Sume		m->m_pkthdr.len -= sizeof(int);
21378064Sume		m->m_data += sizeof(int);
21478064Sume	}
21578064Sume
21678064Sume	if (ifp->if_bpf) {
21778064Sume		/*
21878064Sume		 * We need to prepend the address family as
21978064Sume		 * a four byte field.  Cons up a faith header
22078064Sume		 * to pacify bpf.  This is safe because bpf
22178064Sume		 * will only read from the mbuf (i.e., it won't
22278064Sume		 * try to free it or keep a pointer a to it).
22378064Sume		 */
22478064Sume		struct mbuf m0;
22578064Sume		u_int32_t af = dst->sa_family;
22678064Sume
22778064Sume		m0.m_next = m;
22878064Sume		m0.m_len = 4;
22978064Sume		m0.m_data = (char *)&af;
23078064Sume
231106939Ssam		BPF_MTAP(ifp, &m0);
23278064Sume	}
23378064Sume
23478064Sume	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
23578064Sume		m_freem(m);
23678064Sume		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
23778064Sume		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
23878064Sume	}
23978064Sume	ifp->if_opackets++;
24078064Sume	ifp->if_obytes += m->m_pkthdr.len;
24178064Sume	switch (dst->sa_family) {
24278064Sume#ifdef INET
24378064Sume	case AF_INET:
24478064Sume		isr = NETISR_IP;
24578064Sume		break;
24678064Sume#endif
24778064Sume#ifdef INET6
24878064Sume	case AF_INET6:
24978064Sume		isr = NETISR_IPV6;
25078064Sume		break;
25178064Sume#endif
25278064Sume	default:
25378064Sume		m_freem(m);
25478064Sume		return EAFNOSUPPORT;
25578064Sume	}
25678064Sume
25778064Sume	/* XXX do we need more sanity checks? */
25878064Sume
25978064Sume	m->m_pkthdr.rcvif = ifp;
26078064Sume	ifp->if_ipackets++;
26178064Sume	ifp->if_ibytes += m->m_pkthdr.len;
262111888Sjlemon	netisr_dispatch(isr, m);
26378064Sume	return (0);
26478064Sume}
26578064Sume
26678064Sume/* ARGSUSED */
26778064Sumestatic void
26885074Srufaithrtrequest(cmd, rt, info)
26978064Sume	int cmd;
27078064Sume	struct rtentry *rt;
27185074Sru	struct rt_addrinfo *info;
27278064Sume{
273120727Ssam	RT_LOCK_ASSERT(rt);
274120727Ssam
27578064Sume	if (rt) {
27678064Sume		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
27778064Sume		/*
27878064Sume		 * For optimal performance, the send and receive buffers
27978064Sume		 * should be at least twice the MTU plus a little more for
28078064Sume		 * overhead.
28178064Sume		 */
28278064Sume		rt->rt_rmx.rmx_recvpipe =
28378064Sume			rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU;
28478064Sume	}
28578064Sume}
28678064Sume
28778064Sume/*
28878064Sume * Process an ioctl request.
28978064Sume */
29078064Sume/* ARGSUSED */
29178064Sumestatic int
29278064Sumefaithioctl(ifp, cmd, data)
29378064Sume	struct ifnet *ifp;
29478064Sume	u_long cmd;
29578064Sume	caddr_t data;
29678064Sume{
29778064Sume	struct ifaddr *ifa;
29878064Sume	struct ifreq *ifr = (struct ifreq *)data;
29978064Sume	int error = 0;
30078064Sume
30178064Sume	switch (cmd) {
30278064Sume
30378064Sume	case SIOCSIFADDR:
30478064Sume		ifp->if_flags |= IFF_UP | IFF_RUNNING;
30578064Sume		ifa = (struct ifaddr *)data;
30678064Sume		ifa->ifa_rtrequest = faithrtrequest;
30778064Sume		/*
30878064Sume		 * Everything else is done at a higher level.
30978064Sume		 */
31078064Sume		break;
31178064Sume
31278064Sume	case SIOCADDMULTI:
31378064Sume	case SIOCDELMULTI:
31478064Sume		if (ifr == 0) {
31578064Sume			error = EAFNOSUPPORT;		/* XXX */
31678064Sume			break;
31778064Sume		}
31878064Sume		switch (ifr->ifr_addr.sa_family) {
31978064Sume#ifdef INET
32078064Sume		case AF_INET:
32178064Sume			break;
32278064Sume#endif
32378064Sume#ifdef INET6
32478064Sume		case AF_INET6:
32578064Sume			break;
32678064Sume#endif
32778064Sume
32878064Sume		default:
32978064Sume			error = EAFNOSUPPORT;
33078064Sume			break;
33178064Sume		}
33278064Sume		break;
33378064Sume
33478064Sume#ifdef SIOCSIFMTU
33578064Sume	case SIOCSIFMTU:
33678064Sume		ifp->if_mtu = ifr->ifr_mtu;
33778064Sume		break;
33878064Sume#endif
33978064Sume
34078064Sume	case SIOCSIFFLAGS:
34178064Sume		break;
34278064Sume
34378064Sume	default:
34478064Sume		error = EINVAL;
34578064Sume	}
34678064Sume	return (error);
34778064Sume}
34878064Sume
34979326Sume#ifdef INET6
35078064Sume/*
35178064Sume * XXX could be slow
35278064Sume * XXX could be layer violation to call sys/net from sys/netinet6
35378064Sume */
35483934Sbrooksstatic int
35578064Sumefaithprefix(in6)
35678064Sume	struct in6_addr *in6;
35778064Sume{
35878064Sume	struct rtentry *rt;
35978064Sume	struct sockaddr_in6 sin6;
36078064Sume	int ret;
36178064Sume
36278064Sume	if (ip6_keepfaith == 0)
36378064Sume		return 0;
36478064Sume
36578064Sume	bzero(&sin6, sizeof(sin6));
36678064Sume	sin6.sin6_family = AF_INET6;
36778064Sume	sin6.sin6_len = sizeof(struct sockaddr_in6);
36878064Sume	sin6.sin6_addr = *in6;
36978064Sume	rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
37078064Sume	if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
37178064Sume	    (rt->rt_ifp->if_flags & IFF_UP) != 0)
37278064Sume		ret = 1;
37378064Sume	else
37478064Sume		ret = 0;
37578064Sume	if (rt)
376120727Ssam		RTFREE_LOCKED(rt);
37778064Sume	return ret;
37878064Sume}
37979326Sume#endif
380