if_faith.c revision 91317
178064Sume/* $KAME: if_faith.c,v 1.21 2001/02/20 07:59:26 itojun 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 91317 2002-02-26 17:11:37Z dillon $ 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> 6083934Sbrooks#include <machine/bus.h> /* XXX: Shouldn't really be required! */ 6183934Sbrooks#include <sys/rman.h> 6254263Sshin 6354263Sshin#include <net/if.h> 6454263Sshin#include <net/if_types.h> 6554263Sshin#include <net/netisr.h> 6654263Sshin#include <net/route.h> 6754263Sshin#include <net/bpf.h> 6854263Sshin 6978064Sume#ifdef INET 7078064Sume#include <netinet/in.h> 7178064Sume#include <netinet/in_systm.h> 7278064Sume#include <netinet/in_var.h> 7378064Sume#include <netinet/ip.h> 7478064Sume#endif 7578064Sume 7678064Sume#ifdef INET6 7778064Sume#ifndef INET 7878064Sume#include <netinet/in.h> 7978064Sume#endif 8078064Sume#include <netinet6/in6_var.h> 8178064Sume#include <netinet/ip6.h> 8278064Sume#include <netinet6/ip6_var.h> 8378064Sume#endif 8478064Sume 8571991Speter#include <net/net_osdep.h> 8671991Speter 8783934Sbrooks#define FAITHNAME "faith" 8883934Sbrooks#define FAITH_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */ 8983934Sbrooks 9083934Sbrooksstruct faith_softc { 9183934Sbrooks struct ifnet sc_if; /* must be first */ 9283934Sbrooks struct resource *r_unit; 9383934Sbrooks LIST_ENTRY(faith_softc) sc_list; 9483934Sbrooks}; 9583934Sbrooks 9678064Sumestatic int faithioctl __P((struct ifnet *, u_long, caddr_t)); 9778064Sumeint faithoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, 9878064Sume struct rtentry *)); 9985074Srustatic void faithrtrequest __P((int, struct rtentry *, struct rt_addrinfo *)); 10091317Sdillon#ifdef INET6 10183934Sbrooksstatic int faithprefix __P((struct in6_addr *)); 10291317Sdillon#endif 10354263Sshin 10483934Sbrooksstatic int faithmodevent __P((module_t, int, void *)); 10578064Sume 10683934Sbrooksstatic MALLOC_DEFINE(M_FAITH, FAITHNAME, "Firewall Assisted Tunnel Interface"); 10783934Sbrooksstatic struct rman faithunits[1]; 10889065Smsmithstatic LIST_HEAD(, faith_softc) faith_softc_list; 10954263Sshin 11083934Sbrooksint faith_clone_create __P((struct if_clone *, int *)); 11183934Sbrooksvoid faith_clone_destroy __P((struct ifnet *)); 11283934Sbrooks 11383934Sbrooksstruct if_clone faith_cloner = 11483934Sbrooks IF_CLONE_INITIALIZER(FAITHNAME, faith_clone_create, faith_clone_destroy); 11583934Sbrooks 11654263Sshin#define FAITHMTU 1500 11754263Sshin 11883934Sbrooksstatic int 11983934Sbrooksfaithmodevent(mod, type, data) 12083934Sbrooks module_t mod; 12183934Sbrooks int type; 12283934Sbrooks void *data; 12354263Sshin{ 12483934Sbrooks int err; 12554263Sshin 12683934Sbrooks switch (type) { 12783934Sbrooks case MOD_LOAD: 12883934Sbrooks faithunits->rm_type = RMAN_ARRAY; 12983934Sbrooks faithunits->rm_descr = "configurable if_faith units"; 13083934Sbrooks err = rman_init(faithunits); 13183934Sbrooks if (err != 0) 13283934Sbrooks return (err); 13383934Sbrooks err = rman_manage_region(faithunits, 0, FAITH_MAXUNIT); 13483934Sbrooks if (err != 0) { 13583934Sbrooks printf("%s: faithunits: rman_manage_region: " 13683934Sbrooks "Failed %d\n", FAITHNAME, err); 13783934Sbrooks rman_fini(faithunits); 13883934Sbrooks return (err); 13983934Sbrooks } 14083934Sbrooks LIST_INIT(&faith_softc_list); 14183934Sbrooks if_clone_attach(&faith_cloner); 14283934Sbrooks 14383934Sbrooks#ifdef INET6 14483934Sbrooks faithprefix_p = faithprefix; 14578064Sume#endif 14683934Sbrooks 14783934Sbrooks break; 14883934Sbrooks case MOD_UNLOAD: 14983934Sbrooks#ifdef INET6 15083934Sbrooks faithprefix_p = NULL; 15178064Sume#endif 15283934Sbrooks 15383934Sbrooks if_clone_detach(&faith_cloner); 15483934Sbrooks 15583934Sbrooks while (!LIST_EMPTY(&faith_softc_list)) 15683934Sbrooks faith_clone_destroy( 15783934Sbrooks &LIST_FIRST(&faith_softc_list)->sc_if); 15883934Sbrooks 15983934Sbrooks err = rman_fini(faithunits); 16083934Sbrooks if (err != 0) 16183934Sbrooks return (err); 16283934Sbrooks 16383934Sbrooks break; 16454263Sshin } 16583934Sbrooks return 0; 16654263Sshin} 16778064Sume 16883934Sbrooksstatic moduledata_t faith_mod = { 16983934Sbrooks "if_faith", 17083934Sbrooks faithmodevent, 17183934Sbrooks 0 17283934Sbrooks}; 17383934Sbrooks 17483934SbrooksDECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 17583934SbrooksMODULE_VERSION(if_faith, 1); 17683934Sbrooks 17778064Sumeint 17883934Sbrooksfaith_clone_create(ifc, unit) 17983934Sbrooks struct if_clone *ifc; 18083934Sbrooks int *unit; 18183934Sbrooks{ 18283934Sbrooks struct resource *r; 18383934Sbrooks struct faith_softc *sc; 18483934Sbrooks 18583934Sbrooks if (*unit > FAITH_MAXUNIT) 18683934Sbrooks return (ENXIO); 18783934Sbrooks 18883934Sbrooks if (*unit < 0) { 18983934Sbrooks r = rman_reserve_resource(faithunits, 0, FAITH_MAXUNIT, 1, 19083934Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 19183934Sbrooks if (r == NULL) 19283934Sbrooks return (ENOSPC); 19383934Sbrooks *unit = rman_get_start(r); 19483934Sbrooks } else { 19583934Sbrooks r = rman_reserve_resource(faithunits, *unit, *unit, 1, 19683934Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 19783934Sbrooks if (r == NULL) 19883934Sbrooks return (ENOSPC); 19983934Sbrooks } 20083934Sbrooks 20183934Sbrooks sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK); 20283934Sbrooks bzero(sc, sizeof(struct faith_softc)); 20383934Sbrooks 20483934Sbrooks sc->sc_if.if_softc = sc; 20583934Sbrooks sc->sc_if.if_name = FAITHNAME; 20683934Sbrooks sc->sc_if.if_unit = *unit; 20783934Sbrooks sc->r_unit = r; 20883934Sbrooks 20983934Sbrooks sc->sc_if.if_mtu = FAITHMTU; 21083934Sbrooks /* Change to BROADCAST experimentaly to announce its prefix. */ 21183934Sbrooks sc->sc_if.if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST; 21283934Sbrooks sc->sc_if.if_ioctl = faithioctl; 21383934Sbrooks sc->sc_if.if_output = faithoutput; 21483934Sbrooks sc->sc_if.if_type = IFT_FAITH; 21583934Sbrooks sc->sc_if.if_hdrlen = 0; 21683934Sbrooks sc->sc_if.if_addrlen = 0; 21788034Sbrooks sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen; 21883934Sbrooks if_attach(&sc->sc_if); 21983934Sbrooks bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int)); 22083934Sbrooks LIST_INSERT_HEAD(&faith_softc_list, sc, sc_list); 22183934Sbrooks return (0); 22283934Sbrooks} 22383934Sbrooks 22483934Sbrooksvoid 22583934Sbrooksfaith_clone_destroy(ifp) 22683934Sbrooks struct ifnet *ifp; 22783934Sbrooks{ 22883934Sbrooks int err; 22983934Sbrooks struct faith_softc *sc = (void *) ifp; 23083934Sbrooks 23183934Sbrooks LIST_REMOVE(sc, sc_list); 23283934Sbrooks bpfdetach(ifp); 23383934Sbrooks if_detach(ifp); 23483934Sbrooks 23583934Sbrooks err = rman_release_resource(sc->r_unit); 23683934Sbrooks KASSERT(err == 0, ("Unexpected error freeing resource")); 23783934Sbrooks 23883934Sbrooks free(sc, M_FAITH); 23983934Sbrooks} 24083934Sbrooks 24183934Sbrooksint 24278064Sumefaithoutput(ifp, m, dst, rt) 24378064Sume struct ifnet *ifp; 24478064Sume struct mbuf *m; 24578064Sume struct sockaddr *dst; 24678064Sume struct rtentry *rt; 24778064Sume{ 24878064Sume int isr; 24978064Sume struct ifqueue *ifq = 0; 25078064Sume 25178064Sume if ((m->m_flags & M_PKTHDR) == 0) 25278064Sume panic("faithoutput no HDR"); 25383934Sbrooks 25478064Sume /* BPF write needs to be handled specially */ 25578064Sume if (dst->sa_family == AF_UNSPEC) { 25678064Sume dst->sa_family = *(mtod(m, int *)); 25778064Sume m->m_len -= sizeof(int); 25878064Sume m->m_pkthdr.len -= sizeof(int); 25978064Sume m->m_data += sizeof(int); 26078064Sume } 26178064Sume 26278064Sume if (ifp->if_bpf) { 26378064Sume /* 26478064Sume * We need to prepend the address family as 26578064Sume * a four byte field. Cons up a faith header 26678064Sume * to pacify bpf. This is safe because bpf 26778064Sume * will only read from the mbuf (i.e., it won't 26878064Sume * try to free it or keep a pointer a to it). 26978064Sume */ 27078064Sume struct mbuf m0; 27178064Sume u_int32_t af = dst->sa_family; 27278064Sume 27378064Sume m0.m_next = m; 27478064Sume m0.m_len = 4; 27578064Sume m0.m_data = (char *)⁡ 27678064Sume 27778064Sume bpf_mtap(ifp, &m0); 27878064Sume } 27978064Sume 28078064Sume if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 28178064Sume m_freem(m); 28278064Sume return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 28378064Sume rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 28478064Sume } 28578064Sume ifp->if_opackets++; 28678064Sume ifp->if_obytes += m->m_pkthdr.len; 28778064Sume switch (dst->sa_family) { 28878064Sume#ifdef INET 28978064Sume case AF_INET: 29078064Sume ifq = &ipintrq; 29178064Sume isr = NETISR_IP; 29278064Sume break; 29378064Sume#endif 29478064Sume#ifdef INET6 29578064Sume case AF_INET6: 29678064Sume ifq = &ip6intrq; 29778064Sume isr = NETISR_IPV6; 29878064Sume break; 29978064Sume#endif 30078064Sume default: 30178064Sume m_freem(m); 30278064Sume return EAFNOSUPPORT; 30378064Sume } 30478064Sume 30578064Sume /* XXX do we need more sanity checks? */ 30678064Sume 30778064Sume m->m_pkthdr.rcvif = ifp; 30878064Sume ifp->if_ipackets++; 30978064Sume ifp->if_ibytes += m->m_pkthdr.len; 31078064Sume (void) IF_HANDOFF(ifq, m, NULL); 31178064Sume schednetisr(isr); 31278064Sume return (0); 31378064Sume} 31478064Sume 31578064Sume/* ARGSUSED */ 31678064Sumestatic void 31785074Srufaithrtrequest(cmd, rt, info) 31878064Sume int cmd; 31978064Sume struct rtentry *rt; 32085074Sru struct rt_addrinfo *info; 32178064Sume{ 32278064Sume if (rt) { 32378064Sume rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ 32478064Sume /* 32578064Sume * For optimal performance, the send and receive buffers 32678064Sume * should be at least twice the MTU plus a little more for 32778064Sume * overhead. 32878064Sume */ 32978064Sume rt->rt_rmx.rmx_recvpipe = 33078064Sume rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU; 33178064Sume } 33278064Sume} 33378064Sume 33478064Sume/* 33578064Sume * Process an ioctl request. 33678064Sume */ 33778064Sume/* ARGSUSED */ 33878064Sumestatic int 33978064Sumefaithioctl(ifp, cmd, data) 34078064Sume struct ifnet *ifp; 34178064Sume u_long cmd; 34278064Sume caddr_t data; 34378064Sume{ 34478064Sume struct ifaddr *ifa; 34578064Sume struct ifreq *ifr = (struct ifreq *)data; 34678064Sume int error = 0; 34778064Sume 34878064Sume switch (cmd) { 34978064Sume 35078064Sume case SIOCSIFADDR: 35178064Sume ifp->if_flags |= IFF_UP | IFF_RUNNING; 35278064Sume ifa = (struct ifaddr *)data; 35378064Sume ifa->ifa_rtrequest = faithrtrequest; 35478064Sume /* 35578064Sume * Everything else is done at a higher level. 35678064Sume */ 35778064Sume break; 35878064Sume 35978064Sume case SIOCADDMULTI: 36078064Sume case SIOCDELMULTI: 36178064Sume if (ifr == 0) { 36278064Sume error = EAFNOSUPPORT; /* XXX */ 36378064Sume break; 36478064Sume } 36578064Sume switch (ifr->ifr_addr.sa_family) { 36678064Sume#ifdef INET 36778064Sume case AF_INET: 36878064Sume break; 36978064Sume#endif 37078064Sume#ifdef INET6 37178064Sume case AF_INET6: 37278064Sume break; 37378064Sume#endif 37478064Sume 37578064Sume default: 37678064Sume error = EAFNOSUPPORT; 37778064Sume break; 37878064Sume } 37978064Sume break; 38078064Sume 38178064Sume#ifdef SIOCSIFMTU 38278064Sume case SIOCSIFMTU: 38378064Sume ifp->if_mtu = ifr->ifr_mtu; 38478064Sume break; 38578064Sume#endif 38678064Sume 38778064Sume case SIOCSIFFLAGS: 38878064Sume break; 38978064Sume 39078064Sume default: 39178064Sume error = EINVAL; 39278064Sume } 39378064Sume return (error); 39478064Sume} 39578064Sume 39679326Sume#ifdef INET6 39778064Sume/* 39878064Sume * XXX could be slow 39978064Sume * XXX could be layer violation to call sys/net from sys/netinet6 40078064Sume */ 40183934Sbrooksstatic int 40278064Sumefaithprefix(in6) 40378064Sume struct in6_addr *in6; 40478064Sume{ 40578064Sume struct rtentry *rt; 40678064Sume struct sockaddr_in6 sin6; 40778064Sume int ret; 40878064Sume 40978064Sume if (ip6_keepfaith == 0) 41078064Sume return 0; 41178064Sume 41278064Sume bzero(&sin6, sizeof(sin6)); 41378064Sume sin6.sin6_family = AF_INET6; 41478064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 41578064Sume sin6.sin6_addr = *in6; 41678064Sume rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); 41778064Sume if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && 41878064Sume (rt->rt_ifp->if_flags & IFF_UP) != 0) 41978064Sume ret = 1; 42078064Sume else 42178064Sume ret = 0; 42278064Sume if (rt) 42378064Sume RTFREE(rt); 42478064Sume return ret; 42578064Sume} 42679326Sume#endif 427