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