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 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 *, 90191148Skmacy struct route *); 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 190191148Skmacyfaithoutput(ifp, m, dst, ro) 19178064Sume struct ifnet *ifp; 19278064Sume struct mbuf *m; 19378064Sume struct sockaddr *dst; 194191148Skmacy struct route *ro; 19578064Sume{ 19678064Sume int isr; 197147611Sdwmalone u_int32_t af; 198191148Skmacy struct rtentry *rt = NULL; 19978064Sume 200113255Sdes M_ASSERTPKTHDR(m); 20183934Sbrooks 202191148Skmacy if (ro != NULL) 203191148Skmacy rt = ro->ro_rt; 204147611Sdwmalone /* BPF writes need to be handled specially. */ 20578064Sume if (dst->sa_family == AF_UNSPEC) { 206147611Sdwmalone bcopy(dst->sa_data, &af, sizeof(af)); 207147611Sdwmalone dst->sa_family = af; 20878064Sume } 20978064Sume 210159183Ssam if (bpf_peers_present(ifp->if_bpf)) { 211147611Sdwmalone af = dst->sa_family; 212123922Ssam bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 21378064Sume } 21478064Sume 21578064Sume if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 21678064Sume m_freem(m); 21778064Sume return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 21878064Sume rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 21978064Sume } 22078064Sume ifp->if_opackets++; 22178064Sume ifp->if_obytes += m->m_pkthdr.len; 22278064Sume switch (dst->sa_family) { 22378064Sume#ifdef INET 22478064Sume case AF_INET: 22578064Sume isr = NETISR_IP; 22678064Sume break; 22778064Sume#endif 22878064Sume#ifdef INET6 22978064Sume case AF_INET6: 23078064Sume isr = NETISR_IPV6; 23178064Sume break; 23278064Sume#endif 23378064Sume default: 23478064Sume m_freem(m); 23578064Sume return EAFNOSUPPORT; 23678064Sume } 23778064Sume 23878064Sume /* XXX do we need more sanity checks? */ 23978064Sume 24078064Sume m->m_pkthdr.rcvif = ifp; 24178064Sume ifp->if_ipackets++; 24278064Sume ifp->if_ibytes += m->m_pkthdr.len; 243111888Sjlemon netisr_dispatch(isr, m); 24478064Sume return (0); 24578064Sume} 24678064Sume 24778064Sume/* ARGSUSED */ 24878064Sumestatic void 24985074Srufaithrtrequest(cmd, rt, info) 25078064Sume int cmd; 25178064Sume struct rtentry *rt; 25285074Sru struct rt_addrinfo *info; 25378064Sume{ 254120727Ssam RT_LOCK_ASSERT(rt); 255142352Ssam rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; 25678064Sume} 25778064Sume 25878064Sume/* 25978064Sume * Process an ioctl request. 26078064Sume */ 26178064Sume/* ARGSUSED */ 26278064Sumestatic int 26378064Sumefaithioctl(ifp, cmd, data) 26478064Sume struct ifnet *ifp; 26578064Sume u_long cmd; 26678064Sume caddr_t data; 26778064Sume{ 26878064Sume struct ifaddr *ifa; 26978064Sume struct ifreq *ifr = (struct ifreq *)data; 27078064Sume int error = 0; 27178064Sume 27278064Sume switch (cmd) { 27378064Sume 27478064Sume case SIOCSIFADDR: 275148887Srwatson ifp->if_flags |= IFF_UP; 276148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 27778064Sume ifa = (struct ifaddr *)data; 27878064Sume ifa->ifa_rtrequest = faithrtrequest; 27978064Sume /* 28078064Sume * Everything else is done at a higher level. 28178064Sume */ 28278064Sume break; 28378064Sume 28478064Sume case SIOCADDMULTI: 28578064Sume case SIOCDELMULTI: 28678064Sume if (ifr == 0) { 28778064Sume error = EAFNOSUPPORT; /* XXX */ 28878064Sume break; 28978064Sume } 29078064Sume switch (ifr->ifr_addr.sa_family) { 29178064Sume#ifdef INET 29278064Sume case AF_INET: 29378064Sume break; 29478064Sume#endif 29578064Sume#ifdef INET6 29678064Sume case AF_INET6: 29778064Sume break; 29878064Sume#endif 29978064Sume 30078064Sume default: 30178064Sume error = EAFNOSUPPORT; 30278064Sume break; 30378064Sume } 30478064Sume break; 30578064Sume 30678064Sume#ifdef SIOCSIFMTU 30778064Sume case SIOCSIFMTU: 30878064Sume ifp->if_mtu = ifr->ifr_mtu; 30978064Sume break; 31078064Sume#endif 31178064Sume 31278064Sume case SIOCSIFFLAGS: 31378064Sume break; 31478064Sume 31578064Sume default: 31678064Sume error = EINVAL; 31778064Sume } 31878064Sume return (error); 31978064Sume} 32078064Sume 32179326Sume#ifdef INET6 32278064Sume/* 32378064Sume * XXX could be slow 32478064Sume * XXX could be layer violation to call sys/net from sys/netinet6 32578064Sume */ 32683934Sbrooksstatic int 32778064Sumefaithprefix(in6) 32878064Sume struct in6_addr *in6; 32978064Sume{ 33078064Sume struct rtentry *rt; 33178064Sume struct sockaddr_in6 sin6; 33278064Sume int ret; 33378064Sume 334181803Sbz if (V_ip6_keepfaith == 0) 33578064Sume return 0; 33678064Sume 33778064Sume bzero(&sin6, sizeof(sin6)); 33878064Sume sin6.sin6_family = AF_INET6; 33978064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 34078064Sume sin6.sin6_addr = *in6; 341232292Sbz rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB); 34278064Sume if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && 34378064Sume (rt->rt_ifp->if_flags & IFF_UP) != 0) 34478064Sume ret = 1; 34578064Sume else 34678064Sume ret = 0; 34778064Sume if (rt) 348120727Ssam RTFREE_LOCKED(rt); 34978064Sume return ret; 35078064Sume} 35179326Sume#endif 352