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