if_faith.c revision 111119
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 * 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 111119 2003-02-19 05:47:46Z imp $ 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> 6054263Sshin 6154263Sshin#include <net/if.h> 6254263Sshin#include <net/if_types.h> 6354263Sshin#include <net/netisr.h> 6454263Sshin#include <net/route.h> 6554263Sshin#include <net/bpf.h> 6654263Sshin 6778064Sume#ifdef INET 6878064Sume#include <netinet/in.h> 6978064Sume#include <netinet/in_systm.h> 7078064Sume#include <netinet/in_var.h> 7178064Sume#include <netinet/ip.h> 7278064Sume#endif 7378064Sume 7478064Sume#ifdef INET6 7578064Sume#ifndef INET 7678064Sume#include <netinet/in.h> 7778064Sume#endif 7878064Sume#include <netinet6/in6_var.h> 7978064Sume#include <netinet/ip6.h> 8078064Sume#include <netinet6/ip6_var.h> 8178064Sume#endif 8278064Sume 8371991Speter#include <net/net_osdep.h> 8471991Speter 8583934Sbrooks#define FAITHNAME "faith" 8683934Sbrooks 8783934Sbrooksstruct faith_softc { 8883934Sbrooks struct ifnet sc_if; /* must be first */ 8983934Sbrooks LIST_ENTRY(faith_softc) sc_list; 9083934Sbrooks}; 9183934Sbrooks 9292725Salfredstatic int faithioctl(struct ifnet *, u_long, caddr_t); 9392725Salfredint faithoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 9492725Salfred struct rtentry *); 9592725Salfredstatic void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *); 9691317Sdillon#ifdef INET6 9792725Salfredstatic int faithprefix(struct in6_addr *); 9891317Sdillon#endif 9954263Sshin 10092725Salfredstatic int faithmodevent(module_t, int, void *); 10178064Sume 10283934Sbrooksstatic MALLOC_DEFINE(M_FAITH, FAITHNAME, "Firewall Assisted Tunnel Interface"); 10389065Smsmithstatic LIST_HEAD(, faith_softc) faith_softc_list; 10454263Sshin 10592725Salfredint faith_clone_create(struct if_clone *, int); 10697289Sbrooksvoid faith_clone_destroy(struct ifnet *); 10783934Sbrooks 10892081Smuxstruct if_clone faith_cloner = IF_CLONE_INITIALIZER(FAITHNAME, 10997289Sbrooks faith_clone_create, faith_clone_destroy, 0, IF_MAXUNIT); 11083934Sbrooks 11154263Sshin#define FAITHMTU 1500 11254263Sshin 11383934Sbrooksstatic int 11483934Sbrooksfaithmodevent(mod, type, data) 11583934Sbrooks module_t mod; 11683934Sbrooks int type; 11783934Sbrooks void *data; 11854263Sshin{ 11954263Sshin 12083934Sbrooks switch (type) { 12183934Sbrooks case MOD_LOAD: 12283934Sbrooks LIST_INIT(&faith_softc_list); 12383934Sbrooks if_clone_attach(&faith_cloner); 12483934Sbrooks 12583934Sbrooks#ifdef INET6 12683934Sbrooks faithprefix_p = faithprefix; 12778064Sume#endif 12883934Sbrooks 12983934Sbrooks break; 13083934Sbrooks case MOD_UNLOAD: 13183934Sbrooks#ifdef INET6 13283934Sbrooks faithprefix_p = NULL; 13378064Sume#endif 13483934Sbrooks 13583934Sbrooks if_clone_detach(&faith_cloner); 13683934Sbrooks 13783934Sbrooks while (!LIST_EMPTY(&faith_softc_list)) 13883934Sbrooks faith_clone_destroy( 13983934Sbrooks &LIST_FIRST(&faith_softc_list)->sc_if); 14083934Sbrooks 14183934Sbrooks break; 14254263Sshin } 14383934Sbrooks return 0; 14454263Sshin} 14578064Sume 14683934Sbrooksstatic moduledata_t faith_mod = { 14783934Sbrooks "if_faith", 14883934Sbrooks faithmodevent, 14983934Sbrooks 0 15083934Sbrooks}; 15183934Sbrooks 15283934SbrooksDECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 15383934SbrooksMODULE_VERSION(if_faith, 1); 15483934Sbrooks 15578064Sumeint 15683934Sbrooksfaith_clone_create(ifc, unit) 15783934Sbrooks struct if_clone *ifc; 15892081Smux int unit; 15983934Sbrooks{ 16083934Sbrooks struct faith_softc *sc; 16183934Sbrooks 162111119Simp sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK); 16383934Sbrooks bzero(sc, sizeof(struct faith_softc)); 16483934Sbrooks 16583934Sbrooks sc->sc_if.if_softc = sc; 16683934Sbrooks sc->sc_if.if_name = FAITHNAME; 16792081Smux sc->sc_if.if_unit = unit; 16883934Sbrooks 16983934Sbrooks sc->sc_if.if_mtu = FAITHMTU; 17083934Sbrooks /* Change to BROADCAST experimentaly to announce its prefix. */ 17183934Sbrooks sc->sc_if.if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST; 17283934Sbrooks sc->sc_if.if_ioctl = faithioctl; 17383934Sbrooks sc->sc_if.if_output = faithoutput; 17483934Sbrooks sc->sc_if.if_type = IFT_FAITH; 17583934Sbrooks sc->sc_if.if_hdrlen = 0; 17683934Sbrooks sc->sc_if.if_addrlen = 0; 17788034Sbrooks sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen; 17883934Sbrooks if_attach(&sc->sc_if); 17983934Sbrooks bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int)); 18083934Sbrooks LIST_INSERT_HEAD(&faith_softc_list, sc, sc_list); 18183934Sbrooks return (0); 18283934Sbrooks} 18383934Sbrooks 18497289Sbrooksvoid 18583934Sbrooksfaith_clone_destroy(ifp) 18683934Sbrooks struct ifnet *ifp; 18783934Sbrooks{ 18883934Sbrooks struct faith_softc *sc = (void *) ifp; 18983934Sbrooks 19083934Sbrooks LIST_REMOVE(sc, sc_list); 19183934Sbrooks bpfdetach(ifp); 19283934Sbrooks if_detach(ifp); 19383934Sbrooks 19483934Sbrooks free(sc, M_FAITH); 19583934Sbrooks} 19683934Sbrooks 19783934Sbrooksint 19878064Sumefaithoutput(ifp, m, dst, rt) 19978064Sume struct ifnet *ifp; 20078064Sume struct mbuf *m; 20178064Sume struct sockaddr *dst; 20278064Sume struct rtentry *rt; 20378064Sume{ 20478064Sume int isr; 20578064Sume struct ifqueue *ifq = 0; 20678064Sume 20778064Sume if ((m->m_flags & M_PKTHDR) == 0) 20878064Sume panic("faithoutput no HDR"); 20983934Sbrooks 21078064Sume /* BPF write needs to be handled specially */ 21178064Sume if (dst->sa_family == AF_UNSPEC) { 21278064Sume dst->sa_family = *(mtod(m, int *)); 21378064Sume m->m_len -= sizeof(int); 21478064Sume m->m_pkthdr.len -= sizeof(int); 21578064Sume m->m_data += sizeof(int); 21678064Sume } 21778064Sume 21878064Sume if (ifp->if_bpf) { 21978064Sume /* 22078064Sume * We need to prepend the address family as 22178064Sume * a four byte field. Cons up a faith header 22278064Sume * to pacify bpf. This is safe because bpf 22378064Sume * will only read from the mbuf (i.e., it won't 22478064Sume * try to free it or keep a pointer a to it). 22578064Sume */ 22678064Sume struct mbuf m0; 22778064Sume u_int32_t af = dst->sa_family; 22878064Sume 22978064Sume m0.m_next = m; 23078064Sume m0.m_len = 4; 23178064Sume m0.m_data = (char *)⁡ 23278064Sume 233106939Ssam BPF_MTAP(ifp, &m0); 23478064Sume } 23578064Sume 23678064Sume if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 23778064Sume m_freem(m); 23878064Sume return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 23978064Sume rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 24078064Sume } 24178064Sume ifp->if_opackets++; 24278064Sume ifp->if_obytes += m->m_pkthdr.len; 24378064Sume switch (dst->sa_family) { 24478064Sume#ifdef INET 24578064Sume case AF_INET: 24678064Sume ifq = &ipintrq; 24778064Sume isr = NETISR_IP; 24878064Sume break; 24978064Sume#endif 25078064Sume#ifdef INET6 25178064Sume case AF_INET6: 25278064Sume ifq = &ip6intrq; 25378064Sume isr = NETISR_IPV6; 25478064Sume break; 25578064Sume#endif 25678064Sume default: 25778064Sume m_freem(m); 25878064Sume return EAFNOSUPPORT; 25978064Sume } 26078064Sume 26178064Sume /* XXX do we need more sanity checks? */ 26278064Sume 26378064Sume m->m_pkthdr.rcvif = ifp; 26478064Sume ifp->if_ipackets++; 26578064Sume ifp->if_ibytes += m->m_pkthdr.len; 26678064Sume (void) IF_HANDOFF(ifq, m, NULL); 26778064Sume schednetisr(isr); 26878064Sume return (0); 26978064Sume} 27078064Sume 27178064Sume/* ARGSUSED */ 27278064Sumestatic void 27385074Srufaithrtrequest(cmd, rt, info) 27478064Sume int cmd; 27578064Sume struct rtentry *rt; 27685074Sru struct rt_addrinfo *info; 27778064Sume{ 27878064Sume if (rt) { 27978064Sume rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ 28078064Sume /* 28178064Sume * For optimal performance, the send and receive buffers 28278064Sume * should be at least twice the MTU plus a little more for 28378064Sume * overhead. 28478064Sume */ 28578064Sume rt->rt_rmx.rmx_recvpipe = 28678064Sume rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU; 28778064Sume } 28878064Sume} 28978064Sume 29078064Sume/* 29178064Sume * Process an ioctl request. 29278064Sume */ 29378064Sume/* ARGSUSED */ 29478064Sumestatic int 29578064Sumefaithioctl(ifp, cmd, data) 29678064Sume struct ifnet *ifp; 29778064Sume u_long cmd; 29878064Sume caddr_t data; 29978064Sume{ 30078064Sume struct ifaddr *ifa; 30178064Sume struct ifreq *ifr = (struct ifreq *)data; 30278064Sume int error = 0; 30378064Sume 30478064Sume switch (cmd) { 30578064Sume 30678064Sume case SIOCSIFADDR: 30778064Sume ifp->if_flags |= IFF_UP | IFF_RUNNING; 30878064Sume ifa = (struct ifaddr *)data; 30978064Sume ifa->ifa_rtrequest = faithrtrequest; 31078064Sume /* 31178064Sume * Everything else is done at a higher level. 31278064Sume */ 31378064Sume break; 31478064Sume 31578064Sume case SIOCADDMULTI: 31678064Sume case SIOCDELMULTI: 31778064Sume if (ifr == 0) { 31878064Sume error = EAFNOSUPPORT; /* XXX */ 31978064Sume break; 32078064Sume } 32178064Sume switch (ifr->ifr_addr.sa_family) { 32278064Sume#ifdef INET 32378064Sume case AF_INET: 32478064Sume break; 32578064Sume#endif 32678064Sume#ifdef INET6 32778064Sume case AF_INET6: 32878064Sume break; 32978064Sume#endif 33078064Sume 33178064Sume default: 33278064Sume error = EAFNOSUPPORT; 33378064Sume break; 33478064Sume } 33578064Sume break; 33678064Sume 33778064Sume#ifdef SIOCSIFMTU 33878064Sume case SIOCSIFMTU: 33978064Sume ifp->if_mtu = ifr->ifr_mtu; 34078064Sume break; 34178064Sume#endif 34278064Sume 34378064Sume case SIOCSIFFLAGS: 34478064Sume break; 34578064Sume 34678064Sume default: 34778064Sume error = EINVAL; 34878064Sume } 34978064Sume return (error); 35078064Sume} 35178064Sume 35279326Sume#ifdef INET6 35378064Sume/* 35478064Sume * XXX could be slow 35578064Sume * XXX could be layer violation to call sys/net from sys/netinet6 35678064Sume */ 35783934Sbrooksstatic int 35878064Sumefaithprefix(in6) 35978064Sume struct in6_addr *in6; 36078064Sume{ 36178064Sume struct rtentry *rt; 36278064Sume struct sockaddr_in6 sin6; 36378064Sume int ret; 36478064Sume 36578064Sume if (ip6_keepfaith == 0) 36678064Sume return 0; 36778064Sume 36878064Sume bzero(&sin6, sizeof(sin6)); 36978064Sume sin6.sin6_family = AF_INET6; 37078064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 37178064Sume sin6.sin6_addr = *in6; 37278064Sume rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); 37378064Sume if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && 37478064Sume (rt->rt_ifp->if_flags & IFF_UP) != 0) 37578064Sume ret = 1; 37678064Sume else 37778064Sume ret = 0; 37878064Sume if (rt) 37978064Sume RTFREE(rt); 38078064Sume return ret; 38178064Sume} 38279326Sume#endif 383