195023Ssuz/*	$KAME: if_faith.c,v 1.23 2001/12/17 13:55:29 sumikawa Exp $	*/
278064Sume
3139823Simp/*-
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$
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>
59130933Sbrooks#include <net/if_clone.h>
6054263Sshin#include <net/if_types.h>
6154263Sshin#include <net/netisr.h>
6254263Sshin#include <net/route.h>
6354263Sshin#include <net/bpf.h>
64196019Srwatson#include <net/vnet.h>
6554263Sshin
6678064Sume#ifdef	INET
6778064Sume#include <netinet/in.h>
6878064Sume#include <netinet/in_systm.h>
6978064Sume#include <netinet/in_var.h>
7078064Sume#include <netinet/ip.h>
7178064Sume#endif
7278064Sume
7378064Sume#ifdef INET6
7478064Sume#ifndef INET
7578064Sume#include <netinet/in.h>
7678064Sume#endif
7778064Sume#include <netinet6/in6_var.h>
7878064Sume#include <netinet/ip6.h>
7978064Sume#include <netinet6/ip6_var.h>
8078064Sume#endif
8178064Sume
8283934Sbrooksstruct faith_softc {
83147256Sbrooks	struct ifnet *sc_ifp;
8483934Sbrooks};
8583934Sbrooks
8692725Salfredstatic int faithioctl(struct ifnet *, u_long, caddr_t);
87249925Sglebiusstatic int faithoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
88191148Skmacy	struct route *);
8992725Salfredstatic void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *);
9091317Sdillon#ifdef INET6
9192725Salfredstatic int faithprefix(struct in6_addr *);
9291317Sdillon#endif
9354263Sshin
9492725Salfredstatic int faithmodevent(module_t, int, void *);
9578064Sume
96241610Sglebiusstatic const char faithname[] = "faith";
97241610Sglebiusstatic MALLOC_DEFINE(M_FAITH, faithname, "Firewall Assisted Tunnel Interface");
9854263Sshin
99160195Ssamstatic int	faith_clone_create(struct if_clone *, int, caddr_t);
100128209Sbrooksstatic void	faith_clone_destroy(struct ifnet *);
101241610Sglebiusstatic struct if_clone *faith_cloner;
10283934Sbrooks
10354263Sshin#define	FAITHMTU	1500
10454263Sshin
10583934Sbrooksstatic int
10683934Sbrooksfaithmodevent(mod, type, data)
10783934Sbrooks	module_t mod;
10883934Sbrooks	int type;
10983934Sbrooks	void *data;
11054263Sshin{
11154263Sshin
11283934Sbrooks	switch (type) {
11383934Sbrooks	case MOD_LOAD:
114241610Sglebius		faith_cloner = if_clone_simple(faithname, faith_clone_create,
115241610Sglebius		    faith_clone_destroy, 0);
11683934Sbrooks#ifdef INET6
11783934Sbrooks		faithprefix_p = faithprefix;
11878064Sume#endif
11983934Sbrooks
12083934Sbrooks		break;
12183934Sbrooks	case MOD_UNLOAD:
12283934Sbrooks#ifdef INET6
12383934Sbrooks		faithprefix_p = NULL;
12478064Sume#endif
12583934Sbrooks
126241610Sglebius		if_clone_detach(faith_cloner);
12783934Sbrooks		break;
128132199Sphk	default:
129132199Sphk		return EOPNOTSUPP;
13054263Sshin	}
13183934Sbrooks	return 0;
13254263Sshin}
13378064Sume
13483934Sbrooksstatic moduledata_t faith_mod = {
13583934Sbrooks	"if_faith",
13683934Sbrooks	faithmodevent,
137241394Skevlo	0
13883934Sbrooks};
13983934Sbrooks
14083934SbrooksDECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
14183934SbrooksMODULE_VERSION(if_faith, 1);
14283934Sbrooks
143128209Sbrooksstatic int
144160195Ssamfaith_clone_create(ifc, unit, params)
14583934Sbrooks	struct if_clone *ifc;
14692081Smux	int unit;
147160195Ssam	caddr_t params;
14883934Sbrooks{
149147256Sbrooks	struct ifnet *ifp;
15083934Sbrooks	struct faith_softc *sc;
15183934Sbrooks
152131675Sbms	sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK | M_ZERO);
153147256Sbrooks	ifp = sc->sc_ifp = if_alloc(IFT_FAITH);
154147256Sbrooks	if (ifp == NULL) {
155147256Sbrooks		free(sc, M_FAITH);
156147256Sbrooks		return (ENOSPC);
157147256Sbrooks	}
15883934Sbrooks
159147256Sbrooks	ifp->if_softc = sc;
160241610Sglebius	if_initname(sc->sc_ifp, faithname, unit);
16183934Sbrooks
162147256Sbrooks	ifp->if_mtu = FAITHMTU;
16383934Sbrooks	/* Change to BROADCAST experimentaly to announce its prefix. */
164147256Sbrooks	ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST;
165147256Sbrooks	ifp->if_ioctl = faithioctl;
166147256Sbrooks	ifp->if_output = faithoutput;
167147256Sbrooks	ifp->if_hdrlen = 0;
168147256Sbrooks	ifp->if_addrlen = 0;
169147256Sbrooks	ifp->if_snd.ifq_maxlen = ifqmaxlen;
170147256Sbrooks	if_attach(ifp);
171147611Sdwmalone	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
17283934Sbrooks	return (0);
17383934Sbrooks}
17483934Sbrooks
175126781Srwatsonstatic void
17683934Sbrooksfaith_clone_destroy(ifp)
17783934Sbrooks	struct ifnet *ifp;
17883934Sbrooks{
179147256Sbrooks	struct faith_softc *sc = ifp->if_softc;
18083934Sbrooks
181151266Sthompsa	bpfdetach(ifp);
182151266Sthompsa	if_detach(ifp);
183151266Sthompsa	if_free(ifp);
184151266Sthompsa	free(sc, M_FAITH);
18583934Sbrooks}
18683934Sbrooks
187249925Sglebiusstatic int
188249925Sglebiusfaithoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
189249925Sglebius	struct route *ro)
19078064Sume{
19178064Sume	int isr;
192147611Sdwmalone	u_int32_t af;
193191148Skmacy	struct rtentry *rt = NULL;
19478064Sume
195113255Sdes	M_ASSERTPKTHDR(m);
19683934Sbrooks
197191148Skmacy	if (ro != NULL)
198191148Skmacy		rt = ro->ro_rt;
199147611Sdwmalone	/* BPF writes need to be handled specially. */
200249925Sglebius	if (dst->sa_family == AF_UNSPEC)
201147611Sdwmalone		bcopy(dst->sa_data, &af, sizeof(af));
202249925Sglebius	else
203249925Sglebius		af = dst->sa_family;
20478064Sume
205249925Sglebius	if (bpf_peers_present(ifp->if_bpf))
206123922Ssam		bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
20778064Sume
20878064Sume	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
20978064Sume		m_freem(m);
21078064Sume		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
21178064Sume		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
21278064Sume	}
21378064Sume	ifp->if_opackets++;
21478064Sume	ifp->if_obytes += m->m_pkthdr.len;
215249925Sglebius	switch (af) {
21678064Sume#ifdef INET
21778064Sume	case AF_INET:
21878064Sume		isr = NETISR_IP;
21978064Sume		break;
22078064Sume#endif
22178064Sume#ifdef INET6
22278064Sume	case AF_INET6:
22378064Sume		isr = NETISR_IPV6;
22478064Sume		break;
22578064Sume#endif
22678064Sume	default:
22778064Sume		m_freem(m);
22878064Sume		return EAFNOSUPPORT;
22978064Sume	}
23078064Sume
23178064Sume	/* XXX do we need more sanity checks? */
23278064Sume
23378064Sume	m->m_pkthdr.rcvif = ifp;
23478064Sume	ifp->if_ipackets++;
23578064Sume	ifp->if_ibytes += m->m_pkthdr.len;
236111888Sjlemon	netisr_dispatch(isr, m);
23778064Sume	return (0);
23878064Sume}
23978064Sume
24078064Sume/* ARGSUSED */
24178064Sumestatic void
24285074Srufaithrtrequest(cmd, rt, info)
24378064Sume	int cmd;
24478064Sume	struct rtentry *rt;
24585074Sru	struct rt_addrinfo *info;
24678064Sume{
247120727Ssam	RT_LOCK_ASSERT(rt);
248142352Ssam	rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
24978064Sume}
25078064Sume
25178064Sume/*
25278064Sume * Process an ioctl request.
25378064Sume */
25478064Sume/* ARGSUSED */
25578064Sumestatic int
25678064Sumefaithioctl(ifp, cmd, data)
25778064Sume	struct ifnet *ifp;
25878064Sume	u_long cmd;
25978064Sume	caddr_t data;
26078064Sume{
26178064Sume	struct ifaddr *ifa;
26278064Sume	struct ifreq *ifr = (struct ifreq *)data;
26378064Sume	int error = 0;
26478064Sume
26578064Sume	switch (cmd) {
26678064Sume
26778064Sume	case SIOCSIFADDR:
268148887Srwatson		ifp->if_flags |= IFF_UP;
269148887Srwatson		ifp->if_drv_flags |= IFF_DRV_RUNNING;
27078064Sume		ifa = (struct ifaddr *)data;
27178064Sume		ifa->ifa_rtrequest = faithrtrequest;
27278064Sume		/*
27378064Sume		 * Everything else is done at a higher level.
27478064Sume		 */
27578064Sume		break;
27678064Sume
27778064Sume	case SIOCADDMULTI:
27878064Sume	case SIOCDELMULTI:
27978064Sume		if (ifr == 0) {
28078064Sume			error = EAFNOSUPPORT;		/* XXX */
28178064Sume			break;
28278064Sume		}
28378064Sume		switch (ifr->ifr_addr.sa_family) {
28478064Sume#ifdef INET
28578064Sume		case AF_INET:
28678064Sume			break;
28778064Sume#endif
28878064Sume#ifdef INET6
28978064Sume		case AF_INET6:
29078064Sume			break;
29178064Sume#endif
29278064Sume
29378064Sume		default:
29478064Sume			error = EAFNOSUPPORT;
29578064Sume			break;
29678064Sume		}
29778064Sume		break;
29878064Sume
29978064Sume#ifdef SIOCSIFMTU
30078064Sume	case SIOCSIFMTU:
30178064Sume		ifp->if_mtu = ifr->ifr_mtu;
30278064Sume		break;
30378064Sume#endif
30478064Sume
30578064Sume	case SIOCSIFFLAGS:
30678064Sume		break;
30778064Sume
30878064Sume	default:
30978064Sume		error = EINVAL;
31078064Sume	}
31178064Sume	return (error);
31278064Sume}
31378064Sume
31479326Sume#ifdef INET6
31578064Sume/*
31678064Sume * XXX could be slow
31778064Sume * XXX could be layer violation to call sys/net from sys/netinet6
31878064Sume */
31983934Sbrooksstatic int
32078064Sumefaithprefix(in6)
32178064Sume	struct in6_addr *in6;
32278064Sume{
32378064Sume	struct rtentry *rt;
32478064Sume	struct sockaddr_in6 sin6;
32578064Sume	int ret;
32678064Sume
327181803Sbz	if (V_ip6_keepfaith == 0)
32878064Sume		return 0;
32978064Sume
33078064Sume	bzero(&sin6, sizeof(sin6));
33178064Sume	sin6.sin6_family = AF_INET6;
33278064Sume	sin6.sin6_len = sizeof(struct sockaddr_in6);
33378064Sume	sin6.sin6_addr = *in6;
334231852Sbz	rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB);
33578064Sume	if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
33678064Sume	    (rt->rt_ifp->if_flags & IFF_UP) != 0)
33778064Sume		ret = 1;
33878064Sume	else
33978064Sume		ret = 0;
34078064Sume	if (rt)
341120727Ssam		RTFREE_LOCKED(rt);
34278064Sume	return ret;
34378064Sume}
34479326Sume#endif
345