if_faith.c revision 181803
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: head/sys/net/if_faith.c 181803 2008-08-17 23:27:27Z bz $ 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> 57181803Sbz#include <sys/vimage.h> 5854263Sshin 5954263Sshin#include <net/if.h> 60130933Sbrooks#include <net/if_clone.h> 6154263Sshin#include <net/if_types.h> 6254263Sshin#include <net/netisr.h> 6354263Sshin#include <net/route.h> 6454263Sshin#include <net/bpf.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 8283934Sbrooks#define FAITHNAME "faith" 8383934Sbrooks 8483934Sbrooksstruct faith_softc { 85147256Sbrooks struct ifnet *sc_ifp; 8683934Sbrooks}; 8783934Sbrooks 8892725Salfredstatic int faithioctl(struct ifnet *, u_long, caddr_t); 8992725Salfredint faithoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 9092725Salfred struct rtentry *); 9192725Salfredstatic void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *); 9291317Sdillon#ifdef INET6 9392725Salfredstatic int faithprefix(struct in6_addr *); 9491317Sdillon#endif 9554263Sshin 9692725Salfredstatic int faithmodevent(module_t, int, void *); 9778064Sume 9883934Sbrooksstatic MALLOC_DEFINE(M_FAITH, FAITHNAME, "Firewall Assisted Tunnel Interface"); 9954263Sshin 100160195Ssamstatic int faith_clone_create(struct if_clone *, int, caddr_t); 101128209Sbrooksstatic void faith_clone_destroy(struct ifnet *); 10283934Sbrooks 103130933SbrooksIFC_SIMPLE_DECLARE(faith, 0); 10483934Sbrooks 10554263Sshin#define FAITHMTU 1500 10654263Sshin 10783934Sbrooksstatic int 10883934Sbrooksfaithmodevent(mod, type, data) 10983934Sbrooks module_t mod; 11083934Sbrooks int type; 11183934Sbrooks void *data; 11254263Sshin{ 11354263Sshin 11483934Sbrooks switch (type) { 11583934Sbrooks case MOD_LOAD: 11683934Sbrooks if_clone_attach(&faith_cloner); 11783934Sbrooks 11883934Sbrooks#ifdef INET6 11983934Sbrooks faithprefix_p = faithprefix; 12078064Sume#endif 12183934Sbrooks 12283934Sbrooks break; 12383934Sbrooks case MOD_UNLOAD: 12483934Sbrooks#ifdef INET6 12583934Sbrooks faithprefix_p = NULL; 12678064Sume#endif 12783934Sbrooks 12883934Sbrooks if_clone_detach(&faith_cloner); 12983934Sbrooks break; 130132199Sphk default: 131132199Sphk return EOPNOTSUPP; 13254263Sshin } 13383934Sbrooks return 0; 13454263Sshin} 13578064Sume 13683934Sbrooksstatic moduledata_t faith_mod = { 13783934Sbrooks "if_faith", 13883934Sbrooks faithmodevent, 13983934Sbrooks 0 14083934Sbrooks}; 14183934Sbrooks 14283934SbrooksDECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 14383934SbrooksMODULE_VERSION(if_faith, 1); 14483934Sbrooks 145128209Sbrooksstatic int 146160195Ssamfaith_clone_create(ifc, unit, params) 14783934Sbrooks struct if_clone *ifc; 14892081Smux int unit; 149160195Ssam caddr_t params; 15083934Sbrooks{ 151147256Sbrooks struct ifnet *ifp; 15283934Sbrooks struct faith_softc *sc; 15383934Sbrooks 154131675Sbms sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK | M_ZERO); 155147256Sbrooks ifp = sc->sc_ifp = if_alloc(IFT_FAITH); 156147256Sbrooks if (ifp == NULL) { 157147256Sbrooks free(sc, M_FAITH); 158147256Sbrooks return (ENOSPC); 159147256Sbrooks } 16083934Sbrooks 161147256Sbrooks ifp->if_softc = sc; 162147256Sbrooks if_initname(sc->sc_ifp, ifc->ifc_name, unit); 16383934Sbrooks 164147256Sbrooks ifp->if_mtu = FAITHMTU; 16583934Sbrooks /* Change to BROADCAST experimentaly to announce its prefix. */ 166147256Sbrooks ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST; 167147256Sbrooks ifp->if_ioctl = faithioctl; 168147256Sbrooks ifp->if_output = faithoutput; 169147256Sbrooks ifp->if_hdrlen = 0; 170147256Sbrooks ifp->if_addrlen = 0; 171147256Sbrooks ifp->if_snd.ifq_maxlen = ifqmaxlen; 172147256Sbrooks if_attach(ifp); 173147611Sdwmalone bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 17483934Sbrooks return (0); 17583934Sbrooks} 17683934Sbrooks 177126781Srwatsonstatic void 17883934Sbrooksfaith_clone_destroy(ifp) 17983934Sbrooks struct ifnet *ifp; 18083934Sbrooks{ 181147256Sbrooks struct faith_softc *sc = ifp->if_softc; 18283934Sbrooks 183151266Sthompsa bpfdetach(ifp); 184151266Sthompsa if_detach(ifp); 185151266Sthompsa if_free(ifp); 186151266Sthompsa free(sc, M_FAITH); 18783934Sbrooks} 18883934Sbrooks 18983934Sbrooksint 19078064Sumefaithoutput(ifp, m, dst, rt) 19178064Sume struct ifnet *ifp; 19278064Sume struct mbuf *m; 19378064Sume struct sockaddr *dst; 19478064Sume struct rtentry *rt; 19578064Sume{ 19678064Sume int isr; 197147611Sdwmalone u_int32_t af; 19878064Sume 199113255Sdes M_ASSERTPKTHDR(m); 20083934Sbrooks 201147611Sdwmalone /* BPF writes need to be handled specially. */ 20278064Sume if (dst->sa_family == AF_UNSPEC) { 203147611Sdwmalone bcopy(dst->sa_data, &af, sizeof(af)); 204147611Sdwmalone dst->sa_family = af; 20578064Sume } 20678064Sume 207159183Ssam if (bpf_peers_present(ifp->if_bpf)) { 208147611Sdwmalone af = dst->sa_family; 209123922Ssam bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 21078064Sume } 21178064Sume 21278064Sume if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 21378064Sume m_freem(m); 21478064Sume return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 21578064Sume rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 21678064Sume } 21778064Sume ifp->if_opackets++; 21878064Sume ifp->if_obytes += m->m_pkthdr.len; 21978064Sume switch (dst->sa_family) { 22078064Sume#ifdef INET 22178064Sume case AF_INET: 22278064Sume isr = NETISR_IP; 22378064Sume break; 22478064Sume#endif 22578064Sume#ifdef INET6 22678064Sume case AF_INET6: 22778064Sume isr = NETISR_IPV6; 22878064Sume break; 22978064Sume#endif 23078064Sume default: 23178064Sume m_freem(m); 23278064Sume return EAFNOSUPPORT; 23378064Sume } 23478064Sume 23578064Sume /* XXX do we need more sanity checks? */ 23678064Sume 23778064Sume m->m_pkthdr.rcvif = ifp; 23878064Sume ifp->if_ipackets++; 23978064Sume ifp->if_ibytes += m->m_pkthdr.len; 240111888Sjlemon netisr_dispatch(isr, m); 24178064Sume return (0); 24278064Sume} 24378064Sume 24478064Sume/* ARGSUSED */ 24578064Sumestatic void 24685074Srufaithrtrequest(cmd, rt, info) 24778064Sume int cmd; 24878064Sume struct rtentry *rt; 24985074Sru struct rt_addrinfo *info; 25078064Sume{ 251120727Ssam RT_LOCK_ASSERT(rt); 252142352Ssam rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; 25378064Sume} 25478064Sume 25578064Sume/* 25678064Sume * Process an ioctl request. 25778064Sume */ 25878064Sume/* ARGSUSED */ 25978064Sumestatic int 26078064Sumefaithioctl(ifp, cmd, data) 26178064Sume struct ifnet *ifp; 26278064Sume u_long cmd; 26378064Sume caddr_t data; 26478064Sume{ 26578064Sume struct ifaddr *ifa; 26678064Sume struct ifreq *ifr = (struct ifreq *)data; 26778064Sume int error = 0; 26878064Sume 26978064Sume switch (cmd) { 27078064Sume 27178064Sume case SIOCSIFADDR: 272148887Srwatson ifp->if_flags |= IFF_UP; 273148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 27478064Sume ifa = (struct ifaddr *)data; 27578064Sume ifa->ifa_rtrequest = faithrtrequest; 27678064Sume /* 27778064Sume * Everything else is done at a higher level. 27878064Sume */ 27978064Sume break; 28078064Sume 28178064Sume case SIOCADDMULTI: 28278064Sume case SIOCDELMULTI: 28378064Sume if (ifr == 0) { 28478064Sume error = EAFNOSUPPORT; /* XXX */ 28578064Sume break; 28678064Sume } 28778064Sume switch (ifr->ifr_addr.sa_family) { 28878064Sume#ifdef INET 28978064Sume case AF_INET: 29078064Sume break; 29178064Sume#endif 29278064Sume#ifdef INET6 29378064Sume case AF_INET6: 29478064Sume break; 29578064Sume#endif 29678064Sume 29778064Sume default: 29878064Sume error = EAFNOSUPPORT; 29978064Sume break; 30078064Sume } 30178064Sume break; 30278064Sume 30378064Sume#ifdef SIOCSIFMTU 30478064Sume case SIOCSIFMTU: 30578064Sume ifp->if_mtu = ifr->ifr_mtu; 30678064Sume break; 30778064Sume#endif 30878064Sume 30978064Sume case SIOCSIFFLAGS: 31078064Sume break; 31178064Sume 31278064Sume default: 31378064Sume error = EINVAL; 31478064Sume } 31578064Sume return (error); 31678064Sume} 31778064Sume 31879326Sume#ifdef INET6 31978064Sume/* 32078064Sume * XXX could be slow 32178064Sume * XXX could be layer violation to call sys/net from sys/netinet6 32278064Sume */ 32383934Sbrooksstatic int 32478064Sumefaithprefix(in6) 32578064Sume struct in6_addr *in6; 32678064Sume{ 32778064Sume struct rtentry *rt; 32878064Sume struct sockaddr_in6 sin6; 32978064Sume int ret; 33078064Sume 331181803Sbz if (V_ip6_keepfaith == 0) 33278064Sume return 0; 33378064Sume 33478064Sume bzero(&sin6, sizeof(sin6)); 33578064Sume sin6.sin6_family = AF_INET6; 33678064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 33778064Sume sin6.sin6_addr = *in6; 33878064Sume rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); 33978064Sume if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && 34078064Sume (rt->rt_ifp->if_flags & IFF_UP) != 0) 34178064Sume ret = 1; 34278064Sume else 34378064Sume ret = 0; 34478064Sume if (rt) 345120727Ssam RTFREE_LOCKED(rt); 34678064Sume return ret; 34778064Sume} 34879326Sume#endif 349