if_faith.c revision 129880
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 * 4. Neither the name of the University nor the names of its contributors
1654263Sshin *    may be used to endorse or promote products derived from this software
1754263Sshin *    without specific prior written permission.
1854263Sshin *
1954263Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2054263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2154263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2254263Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2354263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2454263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2554263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2654263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2754263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2854263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2954263Sshin * SUCH DAMAGE.
3054263Sshin *
3154263Sshin * $FreeBSD: head/sys/net/if_faith.c 129880 2004-05-30 20:27:19Z phk $
3254263Sshin */
3354263Sshin/*
3454263Sshin * derived from
3554263Sshin *	@(#)if_loop.c	8.1 (Berkeley) 6/10/93
3654263Sshin * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp
3754263Sshin */
3854263Sshin
3954263Sshin/*
4054263Sshin * Loopback interface driver for protocol testing and timing.
4154263Sshin */
4278064Sume#include "opt_inet.h"
4378064Sume#include "opt_inet6.h"
4454263Sshin
4554263Sshin#include <sys/param.h>
4654263Sshin#include <sys/systm.h>
4754263Sshin#include <sys/kernel.h>
4854263Sshin#include <sys/mbuf.h>
49129880Sphk#include <sys/module.h>
5054263Sshin#include <sys/socket.h>
5178064Sume#include <sys/errno.h>
5254263Sshin#include <sys/sockio.h>
5378064Sume#include <sys/time.h>
5478064Sume#include <sys/queue.h>
5583934Sbrooks#include <sys/types.h>
5683934Sbrooks#include <sys/malloc.h>
5754263Sshin
5854263Sshin#include <net/if.h>
5954263Sshin#include <net/if_types.h>
6054263Sshin#include <net/netisr.h>
6154263Sshin#include <net/route.h>
6254263Sshin#include <net/bpf.h>
6354263Sshin
6478064Sume#ifdef	INET
6578064Sume#include <netinet/in.h>
6678064Sume#include <netinet/in_systm.h>
6778064Sume#include <netinet/in_var.h>
6878064Sume#include <netinet/ip.h>
6978064Sume#endif
7078064Sume
7178064Sume#ifdef INET6
7278064Sume#ifndef INET
7378064Sume#include <netinet/in.h>
7478064Sume#endif
7578064Sume#include <netinet6/in6_var.h>
7678064Sume#include <netinet/ip6.h>
7778064Sume#include <netinet6/ip6_var.h>
7878064Sume#endif
7978064Sume
8071991Speter#include <net/net_osdep.h>
8171991Speter
8283934Sbrooks#define FAITHNAME	"faith"
8383934Sbrooks
8483934Sbrooksstruct faith_softc {
8583934Sbrooks	struct ifnet sc_if;	/* must be first */
8683934Sbrooks	LIST_ENTRY(faith_softc) sc_list;
8783934Sbrooks};
8883934Sbrooks
8992725Salfredstatic int faithioctl(struct ifnet *, u_long, caddr_t);
9092725Salfredint faithoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
9192725Salfred	struct rtentry *);
9292725Salfredstatic void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *);
9391317Sdillon#ifdef INET6
9492725Salfredstatic int faithprefix(struct in6_addr *);
9591317Sdillon#endif
9654263Sshin
9792725Salfredstatic int faithmodevent(module_t, int, void *);
9878064Sume
99126781Srwatsonstatic struct mtx faith_mtx;
10083934Sbrooksstatic MALLOC_DEFINE(M_FAITH, FAITHNAME, "Firewall Assisted Tunnel Interface");
10189065Smsmithstatic LIST_HEAD(, faith_softc) faith_softc_list;
10254263Sshin
103128209Sbrooksstatic int	faith_clone_create(struct if_clone *, int);
104128209Sbrooksstatic void	faith_clone_destroy(struct ifnet *);
105126781Srwatsonstatic void	faith_destroy(struct faith_softc *);
10683934Sbrooks
10792081Smuxstruct if_clone faith_cloner = IF_CLONE_INITIALIZER(FAITHNAME,
10897289Sbrooks    faith_clone_create, faith_clone_destroy, 0, IF_MAXUNIT);
10983934Sbrooks
11054263Sshin#define	FAITHMTU	1500
11154263Sshin
11283934Sbrooksstatic int
11383934Sbrooksfaithmodevent(mod, type, data)
11483934Sbrooks	module_t mod;
11583934Sbrooks	int type;
11683934Sbrooks	void *data;
11754263Sshin{
118126781Srwatson	struct faith_softc *sc;
11954263Sshin
12083934Sbrooks	switch (type) {
12183934Sbrooks	case MOD_LOAD:
122126781Srwatson		mtx_init(&faith_mtx, "faith_mtx", NULL, MTX_DEF);
12383934Sbrooks		LIST_INIT(&faith_softc_list);
12483934Sbrooks		if_clone_attach(&faith_cloner);
12583934Sbrooks
12683934Sbrooks#ifdef INET6
12783934Sbrooks		faithprefix_p = faithprefix;
12878064Sume#endif
12983934Sbrooks
13083934Sbrooks		break;
13183934Sbrooks	case MOD_UNLOAD:
13283934Sbrooks#ifdef INET6
13383934Sbrooks		faithprefix_p = NULL;
13478064Sume#endif
13583934Sbrooks
13683934Sbrooks		if_clone_detach(&faith_cloner);
13783934Sbrooks
138126781Srwatson		mtx_lock(&faith_mtx);
139126781Srwatson		while ((sc = LIST_FIRST(&faith_softc_list)) != NULL) {
140126781Srwatson			LIST_REMOVE(sc, sc_list);
141126781Srwatson			mtx_unlock(&faith_mtx);
142126781Srwatson			faith_destroy(sc);
143126781Srwatson			mtx_lock(&faith_mtx);
144126781Srwatson		}
145126781Srwatson		mtx_unlock(&faith_mtx);
146126781Srwatson		mtx_destroy(&faith_mtx);
14783934Sbrooks		break;
14854263Sshin	}
14983934Sbrooks	return 0;
15054263Sshin}
15178064Sume
15283934Sbrooksstatic moduledata_t faith_mod = {
15383934Sbrooks	"if_faith",
15483934Sbrooks	faithmodevent,
15583934Sbrooks	0
15683934Sbrooks};
15783934Sbrooks
15883934SbrooksDECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
15983934SbrooksMODULE_VERSION(if_faith, 1);
16083934Sbrooks
161128209Sbrooksstatic int
16283934Sbrooksfaith_clone_create(ifc, unit)
16383934Sbrooks	struct if_clone *ifc;
16492081Smux	int unit;
16583934Sbrooks{
16683934Sbrooks	struct faith_softc *sc;
16783934Sbrooks
168111119Simp	sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK);
16983934Sbrooks	bzero(sc, sizeof(struct faith_softc));
17083934Sbrooks
17183934Sbrooks	sc->sc_if.if_softc = sc;
172121816Sbrooks	if_initname(&sc->sc_if, ifc->ifc_name, unit);
17383934Sbrooks
17483934Sbrooks	sc->sc_if.if_mtu = FAITHMTU;
17583934Sbrooks	/* Change to BROADCAST experimentaly to announce its prefix. */
17683934Sbrooks	sc->sc_if.if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST;
17783934Sbrooks	sc->sc_if.if_ioctl = faithioctl;
17883934Sbrooks	sc->sc_if.if_output = faithoutput;
17983934Sbrooks	sc->sc_if.if_type = IFT_FAITH;
18083934Sbrooks	sc->sc_if.if_hdrlen = 0;
18183934Sbrooks	sc->sc_if.if_addrlen = 0;
18288034Sbrooks	sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
18383934Sbrooks	if_attach(&sc->sc_if);
18483934Sbrooks	bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
185126781Srwatson	mtx_lock(&faith_mtx);
18683934Sbrooks	LIST_INSERT_HEAD(&faith_softc_list, sc, sc_list);
187126781Srwatson	mtx_unlock(&faith_mtx);
18883934Sbrooks	return (0);
18983934Sbrooks}
19083934Sbrooks
191126781Srwatsonstatic void
192126781Srwatsonfaith_destroy(struct faith_softc *sc)
193126781Srwatson{
194126781Srwatson
195126781Srwatson	bpfdetach(&sc->sc_if);
196126781Srwatson	if_detach(&sc->sc_if);
197126781Srwatson	free(sc, M_FAITH);
198126781Srwatson}
199126781Srwatson
200128209Sbrooksstatic void
20183934Sbrooksfaith_clone_destroy(ifp)
20283934Sbrooks	struct ifnet *ifp;
20383934Sbrooks{
20483934Sbrooks	struct faith_softc *sc = (void *) ifp;
20583934Sbrooks
206126781Srwatson	mtx_lock(&faith_mtx);
20783934Sbrooks	LIST_REMOVE(sc, sc_list);
208126781Srwatson	mtx_unlock(&faith_mtx);
20983934Sbrooks
210126781Srwatson	faith_destroy(sc);
21183934Sbrooks}
21283934Sbrooks
21383934Sbrooksint
21478064Sumefaithoutput(ifp, m, dst, rt)
21578064Sume	struct ifnet *ifp;
21678064Sume	struct mbuf *m;
21778064Sume	struct sockaddr *dst;
21878064Sume	struct rtentry *rt;
21978064Sume{
22078064Sume	int isr;
22178064Sume
222113255Sdes	M_ASSERTPKTHDR(m);
22383934Sbrooks
22478064Sume	/* BPF write needs to be handled specially */
22578064Sume	if (dst->sa_family == AF_UNSPEC) {
22678064Sume		dst->sa_family = *(mtod(m, int *));
22778064Sume		m->m_len -= sizeof(int);
22878064Sume		m->m_pkthdr.len -= sizeof(int);
22978064Sume		m->m_data += sizeof(int);
23078064Sume	}
23178064Sume
23278064Sume	if (ifp->if_bpf) {
23378064Sume		u_int32_t af = dst->sa_family;
234123922Ssam		bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
23578064Sume	}
23678064Sume
23778064Sume	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
23878064Sume		m_freem(m);
23978064Sume		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
24078064Sume		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
24178064Sume	}
24278064Sume	ifp->if_opackets++;
24378064Sume	ifp->if_obytes += m->m_pkthdr.len;
24478064Sume	switch (dst->sa_family) {
24578064Sume#ifdef INET
24678064Sume	case AF_INET:
24778064Sume		isr = NETISR_IP;
24878064Sume		break;
24978064Sume#endif
25078064Sume#ifdef INET6
25178064Sume	case AF_INET6:
25278064Sume		isr = NETISR_IPV6;
25378064Sume		break;
25478064Sume#endif
25578064Sume	default:
25678064Sume		m_freem(m);
25778064Sume		return EAFNOSUPPORT;
25878064Sume	}
25978064Sume
26078064Sume	/* XXX do we need more sanity checks? */
26178064Sume
26278064Sume	m->m_pkthdr.rcvif = ifp;
26378064Sume	ifp->if_ipackets++;
26478064Sume	ifp->if_ibytes += m->m_pkthdr.len;
265111888Sjlemon	netisr_dispatch(isr, m);
26678064Sume	return (0);
26778064Sume}
26878064Sume
26978064Sume/* ARGSUSED */
27078064Sumestatic void
27185074Srufaithrtrequest(cmd, rt, info)
27278064Sume	int cmd;
27378064Sume	struct rtentry *rt;
27485074Sru	struct rt_addrinfo *info;
27578064Sume{
276120727Ssam	RT_LOCK_ASSERT(rt);
277122922Sandre	if (rt)
278122922Sandre		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
27978064Sume}
28078064Sume
28178064Sume/*
28278064Sume * Process an ioctl request.
28378064Sume */
28478064Sume/* ARGSUSED */
28578064Sumestatic int
28678064Sumefaithioctl(ifp, cmd, data)
28778064Sume	struct ifnet *ifp;
28878064Sume	u_long cmd;
28978064Sume	caddr_t data;
29078064Sume{
29178064Sume	struct ifaddr *ifa;
29278064Sume	struct ifreq *ifr = (struct ifreq *)data;
29378064Sume	int error = 0;
29478064Sume
29578064Sume	switch (cmd) {
29678064Sume
29778064Sume	case SIOCSIFADDR:
29878064Sume		ifp->if_flags |= IFF_UP | IFF_RUNNING;
29978064Sume		ifa = (struct ifaddr *)data;
30078064Sume		ifa->ifa_rtrequest = faithrtrequest;
30178064Sume		/*
30278064Sume		 * Everything else is done at a higher level.
30378064Sume		 */
30478064Sume		break;
30578064Sume
30678064Sume	case SIOCADDMULTI:
30778064Sume	case SIOCDELMULTI:
30878064Sume		if (ifr == 0) {
30978064Sume			error = EAFNOSUPPORT;		/* XXX */
31078064Sume			break;
31178064Sume		}
31278064Sume		switch (ifr->ifr_addr.sa_family) {
31378064Sume#ifdef INET
31478064Sume		case AF_INET:
31578064Sume			break;
31678064Sume#endif
31778064Sume#ifdef INET6
31878064Sume		case AF_INET6:
31978064Sume			break;
32078064Sume#endif
32178064Sume
32278064Sume		default:
32378064Sume			error = EAFNOSUPPORT;
32478064Sume			break;
32578064Sume		}
32678064Sume		break;
32778064Sume
32878064Sume#ifdef SIOCSIFMTU
32978064Sume	case SIOCSIFMTU:
33078064Sume		ifp->if_mtu = ifr->ifr_mtu;
33178064Sume		break;
33278064Sume#endif
33378064Sume
33478064Sume	case SIOCSIFFLAGS:
33578064Sume		break;
33678064Sume
33778064Sume	default:
33878064Sume		error = EINVAL;
33978064Sume	}
34078064Sume	return (error);
34178064Sume}
34278064Sume
34379326Sume#ifdef INET6
34478064Sume/*
34578064Sume * XXX could be slow
34678064Sume * XXX could be layer violation to call sys/net from sys/netinet6
34778064Sume */
34883934Sbrooksstatic int
34978064Sumefaithprefix(in6)
35078064Sume	struct in6_addr *in6;
35178064Sume{
35278064Sume	struct rtentry *rt;
35378064Sume	struct sockaddr_in6 sin6;
35478064Sume	int ret;
35578064Sume
35678064Sume	if (ip6_keepfaith == 0)
35778064Sume		return 0;
35878064Sume
35978064Sume	bzero(&sin6, sizeof(sin6));
36078064Sume	sin6.sin6_family = AF_INET6;
36178064Sume	sin6.sin6_len = sizeof(struct sockaddr_in6);
36278064Sume	sin6.sin6_addr = *in6;
36378064Sume	rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
36478064Sume	if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
36578064Sume	    (rt->rt_ifp->if_flags & IFF_UP) != 0)
36678064Sume		ret = 1;
36778064Sume	else
36878064Sume		ret = 0;
36978064Sume	if (rt)
370120727Ssam		RTFREE_LOCKED(rt);
37178064Sume	return ret;
37278064Sume}
37379326Sume#endif
374