if_faith.c revision 263478
1227825Stheraven/* $KAME: if_faith.c,v 1.23 2001/12/17 13:55:29 sumikawa Exp $ */ 2227825Stheraven 3227825Stheraven/*- 4353358Sdim * Copyright (c) 1982, 1986, 1993 5353358Sdim * The Regents of the University of California. All rights reserved. 6353358Sdim * 7227825Stheraven * Redistribution and use in source and binary forms, with or without 8227825Stheraven * modification, are permitted provided that the following conditions 9227825Stheraven * are met: 10227825Stheraven * 1. Redistributions of source code must retain the above copyright 11227825Stheraven * notice, this list of conditions and the following disclaimer. 12227825Stheraven * 2. Redistributions in binary form must reproduce the above copyright 13227825Stheraven * notice, this list of conditions and the following disclaimer in the 14227825Stheraven * documentation and/or other materials provided with the distribution. 15227825Stheraven * 4. Neither the name of the University nor the names of its contributors 16227825Stheraven * may be used to endorse or promote products derived from this software 17227825Stheraven * without specific prior written permission. 18227825Stheraven * 19227825Stheraven * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20227825Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21321369Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22353358Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23227825Stheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24276792Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25261272Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26276792Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27341825Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28276792Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29288943Sdim * SUCH DAMAGE. 30276792Sdim * 31276792Sdim * $FreeBSD: stable/10/sys/net/if_faith.c 263478 2014-03-21 15:15:30Z glebius $ 32276792Sdim */ 33322320Sdim/* 34276792Sdim * derived from 35227825Stheraven * @(#)if_loop.c 8.1 (Berkeley) 6/10/93 36321369Sdim * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp 37321369Sdim */ 38353358Sdim 39353358Sdim/* 40353358Sdim * Loopback interface driver for protocol testing and timing. 41300770Sdim */ 42300770Sdim#include "opt_inet.h" 43321369Sdim#include "opt_inet6.h" 44227825Stheraven 45227825Stheraven#include <sys/param.h> 46227825Stheraven#include <sys/systm.h> 47227825Stheraven#include <sys/kernel.h> 48227825Stheraven#include <sys/mbuf.h> 49227825Stheraven#include <sys/module.h> 50227825Stheraven#include <sys/socket.h> 51327952Sdim#include <sys/errno.h> 52321369Sdim#include <sys/sockio.h> 53321369Sdim#include <sys/time.h> 54321369Sdim#include <sys/queue.h> 55321369Sdim#include <sys/types.h> 56321369Sdim#include <sys/malloc.h> 57321369Sdim 58321369Sdim#include <net/if.h> 59321369Sdim#include <net/if_clone.h> 60321369Sdim#include <net/if_types.h> 61321369Sdim#include <net/netisr.h> 62321369Sdim#include <net/route.h> 63321369Sdim#include <net/bpf.h> 64321369Sdim#include <net/vnet.h> 65321369Sdim 66321369Sdim#ifdef INET 67327952Sdim#include <netinet/in.h> 68327952Sdim#include <netinet/in_systm.h> 69327952Sdim#include <netinet/in_var.h> 70353358Sdim#include <netinet/ip.h> 71353358Sdim#endif 72353358Sdim 73353358Sdim#ifdef INET6 74353358Sdim#ifndef INET 75353358Sdim#include <netinet/in.h> 76353358Sdim#endif 77353358Sdim#include <netinet6/in6_var.h> 78353358Sdim#include <netinet/ip6.h> 79353358Sdim#include <netinet6/ip6_var.h> 80353358Sdim#endif 81353358Sdim 82353358Sdimstruct faith_softc { 83353358Sdim struct ifnet *sc_ifp; 84353358Sdim}; 85353358Sdim 86327952Sdimstatic int faithioctl(struct ifnet *, u_long, caddr_t); 87353358Sdimstatic int faithoutput(struct ifnet *, struct mbuf *, const struct sockaddr *, 88353358Sdim struct route *); 89353358Sdimstatic void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *); 90353358Sdim#ifdef INET6 91353358Sdimstatic int faithprefix(struct in6_addr *); 92353358Sdim#endif 93353358Sdim 94353358Sdimstatic int faithmodevent(module_t, int, void *); 95353358Sdim 96327952Sdimstatic const char faithname[] = "faith"; 97353358Sdimstatic MALLOC_DEFINE(M_FAITH, faithname, "Firewall Assisted Tunnel Interface"); 98353358Sdim 99353358Sdimstatic int faith_clone_create(struct if_clone *, int, caddr_t); 100353358Sdimstatic void faith_clone_destroy(struct ifnet *); 101353358Sdimstatic struct if_clone *faith_cloner; 102353358Sdim 103327952Sdim#define FAITHMTU 1500 104353358Sdim 105327952Sdimstatic int 106321369Sdimfaithmodevent(mod, type, data) 107321369Sdim module_t mod; 108321369Sdim int type; 109249989Sdim void *data; 110227825Stheraven{ 111241900Sdim 112241900Sdim switch (type) { 113241900Sdim case MOD_LOAD: 114241900Sdim faith_cloner = if_clone_simple(faithname, faith_clone_create, 115227825Stheraven faith_clone_destroy, 0); 116241900Sdim#ifdef INET6 117241900Sdim faithprefix_p = faithprefix; 118241900Sdim#endif 119241900Sdim 120241900Sdim break; 121249989Sdim case MOD_UNLOAD: 122227825Stheraven#ifdef INET6 123227825Stheraven faithprefix_p = NULL; 124227825Stheraven#endif 125249989Sdim 126249989Sdim if_clone_detach(faith_cloner); 127227825Stheraven break; 128227825Stheraven default: 129321369Sdim return EOPNOTSUPP; 130227825Stheraven } 131227825Stheraven return 0; 132227825Stheraven} 133227825Stheraven 134227825Stheravenstatic moduledata_t faith_mod = { 135227825Stheraven "if_faith", 136227825Stheraven faithmodevent, 137227825Stheraven 0 138227825Stheraven}; 139227825Stheraven 140227825StheravenDECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 141227825StheravenMODULE_VERSION(if_faith, 1); 142227825Stheraven 143227825Stheravenstatic int 144227825Stheravenfaith_clone_create(ifc, unit, params) 145227825Stheraven struct if_clone *ifc; 146227825Stheraven int unit; 147227825Stheraven caddr_t params; 148227825Stheraven{ 149227825Stheraven struct ifnet *ifp; 150227825Stheraven struct faith_softc *sc; 151227825Stheraven 152227825Stheraven sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK | M_ZERO); 153227825Stheraven ifp = sc->sc_ifp = if_alloc(IFT_FAITH); 154227825Stheraven if (ifp == NULL) { 155321369Sdim free(sc, M_FAITH); 156321369Sdim return (ENOSPC); 157321369Sdim } 158227825Stheraven 159227825Stheraven ifp->if_softc = sc; 160227825Stheraven if_initname(sc->sc_ifp, faithname, unit); 161227825Stheraven 162227825Stheraven ifp->if_mtu = FAITHMTU; 163227825Stheraven /* Change to BROADCAST experimentaly to announce its prefix. */ 164321369Sdim ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST; 165227825Stheraven ifp->if_ioctl = faithioctl; 166227825Stheraven ifp->if_output = faithoutput; 167227825Stheraven ifp->if_hdrlen = 0; 168227825Stheraven ifp->if_addrlen = 0; 169227825Stheraven ifp->if_snd.ifq_maxlen = ifqmaxlen; 170227825Stheraven if_attach(ifp); 171227825Stheraven bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 172227825Stheraven return (0); 173227825Stheraven} 174227825Stheraven 175227825Stheravenstatic void 176227825Stheravenfaith_clone_destroy(ifp) 177227825Stheraven struct ifnet *ifp; 178227825Stheraven{ 179227825Stheraven struct faith_softc *sc = ifp->if_softc; 180227825Stheraven 181227825Stheraven bpfdetach(ifp); 182227825Stheraven if_detach(ifp); 183227825Stheraven if_free(ifp); 184227825Stheraven free(sc, M_FAITH); 185249989Sdim} 186227825Stheraven 187227825Stheravenstatic int 188227825Stheravenfaithoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 189227825Stheraven struct route *ro) 190227825Stheraven{ 191227825Stheraven int isr; 192227825Stheraven u_int32_t af; 193227825Stheraven struct rtentry *rt = NULL; 194227825Stheraven 195227825Stheraven M_ASSERTPKTHDR(m); 196227825Stheraven 197227825Stheraven if (ro != NULL) 198227825Stheraven rt = ro->ro_rt; 199227825Stheraven /* BPF writes need to be handled specially. */ 200227825Stheraven if (dst->sa_family == AF_UNSPEC) 201249989Sdim bcopy(dst->sa_data, &af, sizeof(af)); 202227825Stheraven else 203227825Stheraven af = dst->sa_family; 204227825Stheraven 205227825Stheraven if (bpf_peers_present(ifp->if_bpf)) 206227825Stheraven bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 207227825Stheraven 208241900Sdim if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 209227825Stheraven m_freem(m); 210227825Stheraven return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 211227825Stheraven rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 212227825Stheraven } 213227825Stheraven ifp->if_opackets++; 214227825Stheraven ifp->if_obytes += m->m_pkthdr.len; 215227825Stheraven switch (af) { 216227825Stheraven#ifdef INET 217227825Stheraven case AF_INET: 218227825Stheraven isr = NETISR_IP; 219227825Stheraven break; 220227825Stheraven#endif 221227825Stheraven#ifdef INET6 222227825Stheraven case AF_INET6: 223227825Stheraven isr = NETISR_IPV6; 224227825Stheraven break; 225227825Stheraven#endif 226227825Stheraven default: 227227825Stheraven m_freem(m); 228227825Stheraven return EAFNOSUPPORT; 229227825Stheraven } 230227825Stheraven 231227825Stheraven /* XXX do we need more sanity checks? */ 232314564Sdim 233314564Sdim m->m_pkthdr.rcvif = ifp; 234227825Stheraven ifp->if_ipackets++; 235227825Stheraven ifp->if_ibytes += m->m_pkthdr.len; 236227825Stheraven netisr_dispatch(isr, m); 237227825Stheraven return (0); 238227825Stheraven} 239227825Stheraven 240227825Stheraven/* ARGSUSED */ 241227825Stheravenstatic void 242227825Stheravenfaithrtrequest(cmd, rt, info) 243227825Stheraven int cmd; 244227825Stheraven struct rtentry *rt; 245227825Stheraven struct rt_addrinfo *info; 246227825Stheraven{ 247227825Stheraven RT_LOCK_ASSERT(rt); 248227825Stheraven rt->rt_mtu = rt->rt_ifp->if_mtu; 249227825Stheraven} 250227825Stheraven 251227825Stheraven/* 252227825Stheraven * Process an ioctl request. 253227825Stheraven */ 254227825Stheraven/* ARGSUSED */ 255227825Stheravenstatic int 256314564Sdimfaithioctl(ifp, cmd, data) 257227825Stheraven struct ifnet *ifp; 258227825Stheraven u_long cmd; 259227825Stheraven caddr_t data; 260227825Stheraven{ 261227825Stheraven struct ifaddr *ifa; 262227825Stheraven struct ifreq *ifr = (struct ifreq *)data; 263227825Stheraven int error = 0; 264227825Stheraven 265227825Stheraven switch (cmd) { 266227825Stheraven 267227825Stheraven case SIOCSIFADDR: 268227825Stheraven ifp->if_flags |= IFF_UP; 269227825Stheraven ifp->if_drv_flags |= IFF_DRV_RUNNING; 270227825Stheraven ifa = (struct ifaddr *)data; 271227825Stheraven ifa->ifa_rtrequest = faithrtrequest; 272227825Stheraven /* 273227825Stheraven * Everything else is done at a higher level. 274353358Sdim */ 275353358Sdim break; 276227825Stheraven 277353358Sdim case SIOCADDMULTI: 278227825Stheraven case SIOCDELMULTI: 279227825Stheraven if (ifr == 0) { 280227825Stheraven error = EAFNOSUPPORT; /* XXX */ 281227825Stheraven break; 282227825Stheraven } 283227825Stheraven switch (ifr->ifr_addr.sa_family) { 284227825Stheraven#ifdef INET 285227825Stheraven case AF_INET: 286227825Stheraven break; 287227825Stheraven#endif 288227825Stheraven#ifdef INET6 289227825Stheraven case AF_INET6: 290227825Stheraven break; 291227825Stheraven#endif 292227825Stheraven 293227825Stheraven default: 294227825Stheraven error = EAFNOSUPPORT; 295227825Stheraven break; 296227825Stheraven } 297227825Stheraven break; 298227825Stheraven 299227825Stheraven#ifdef SIOCSIFMTU 300227825Stheraven case SIOCSIFMTU: 301227825Stheraven ifp->if_mtu = ifr->ifr_mtu; 302227825Stheraven break; 303227825Stheraven#endif 304227825Stheraven 305227825Stheraven case SIOCSIFFLAGS: 306227825Stheraven break; 307227825Stheraven 308227825Stheraven default: 309227825Stheraven error = EINVAL; 310227825Stheraven } 311227825Stheraven return (error); 312227825Stheraven} 313227825Stheraven 314227825Stheraven#ifdef INET6 315227825Stheraven/* 316227825Stheraven * XXX could be slow 317227825Stheraven * XXX could be layer violation to call sys/net from sys/netinet6 318227825Stheraven */ 319227825Stheravenstatic int 320227825Stheravenfaithprefix(in6) 321227825Stheraven struct in6_addr *in6; 322227825Stheraven{ 323227825Stheraven struct rtentry *rt; 324227825Stheraven struct sockaddr_in6 sin6; 325227825Stheraven int ret; 326227825Stheraven 327227825Stheraven if (V_ip6_keepfaith == 0) 328227825Stheraven return 0; 329227825Stheraven 330227825Stheraven bzero(&sin6, sizeof(sin6)); 331232924Stheraven sin6.sin6_family = AF_INET6; 332227825Stheraven sin6.sin6_len = sizeof(struct sockaddr_in6); 333227825Stheraven sin6.sin6_addr = *in6; 334227825Stheraven rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB); 335227825Stheraven if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && 336227825Stheraven (rt->rt_ifp->if_flags & IFF_UP) != 0) 337227825Stheraven ret = 1; 338314564Sdim else 339314564Sdim ret = 0; 340227825Stheraven if (rt) 341227825Stheraven RTFREE_LOCKED(rt); 342227825Stheraven return ret; 343314564Sdim} 344227825Stheraven#endif 345227825Stheraven