if_gif.c revision 132199
162587Sitojun/* $FreeBSD: head/sys/net/if_gif.c 132199 2004-07-15 08:26:07Z phk $ */ 295023Ssuz/* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ */ 362587Sitojun 454263Sshin/* 554263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 654263Sshin * All rights reserved. 754263Sshin * 854263Sshin * Redistribution and use in source and binary forms, with or without 954263Sshin * modification, are permitted provided that the following conditions 1054263Sshin * are met: 1154263Sshin * 1. Redistributions of source code must retain the above copyright 1254263Sshin * notice, this list of conditions and the following disclaimer. 1354263Sshin * 2. Redistributions in binary form must reproduce the above copyright 1454263Sshin * notice, this list of conditions and the following disclaimer in the 1554263Sshin * documentation and/or other materials provided with the distribution. 1654263Sshin * 3. Neither the name of the project nor the names of its contributors 1754263Sshin * may be used to endorse or promote products derived from this software 1854263Sshin * without specific prior written permission. 1954263Sshin * 2054263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2154263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2254263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2354263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2454263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2554263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2654263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2754263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2854263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2954263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3054263Sshin * SUCH DAMAGE. 3154263Sshin */ 3254263Sshin 3354263Sshin#include "opt_inet.h" 3454263Sshin#include "opt_inet6.h" 35101739Srwatson#include "opt_mac.h" 3654263Sshin 3754263Sshin#include <sys/param.h> 3854263Sshin#include <sys/systm.h> 3954263Sshin#include <sys/kernel.h> 40101182Srwatson#include <sys/mac.h> 4154263Sshin#include <sys/malloc.h> 4254263Sshin#include <sys/mbuf.h> 43129880Sphk#include <sys/module.h> 4454263Sshin#include <sys/socket.h> 4554263Sshin#include <sys/sockio.h> 4654263Sshin#include <sys/errno.h> 4754263Sshin#include <sys/time.h> 4891270Sbrooks#include <sys/sysctl.h> 4954263Sshin#include <sys/syslog.h> 5062587Sitojun#include <sys/protosw.h> 5179106Sbrooks#include <sys/conf.h> 5254263Sshin#include <machine/cpu.h> 5354263Sshin 5454263Sshin#include <net/if.h> 55130933Sbrooks#include <net/if_clone.h> 5654263Sshin#include <net/if_types.h> 5754263Sshin#include <net/netisr.h> 5854263Sshin#include <net/route.h> 5954263Sshin#include <net/bpf.h> 6054263Sshin 6154263Sshin#include <netinet/in.h> 6254263Sshin#include <netinet/in_systm.h> 6378064Sume#include <netinet/ip.h> 6478064Sume#ifdef INET 6554263Sshin#include <netinet/in_var.h> 6654263Sshin#include <netinet/in_gif.h> 6779106Sbrooks#include <netinet/ip_var.h> 6854263Sshin#endif /* INET */ 6954263Sshin 7054263Sshin#ifdef INET6 7154263Sshin#ifndef INET 7254263Sshin#include <netinet/in.h> 7354263Sshin#endif 7454263Sshin#include <netinet6/in6_var.h> 7554263Sshin#include <netinet/ip6.h> 7654263Sshin#include <netinet6/ip6_var.h> 7754263Sshin#include <netinet6/in6_gif.h> 7862587Sitojun#include <netinet6/ip6protosw.h> 7954263Sshin#endif /* INET6 */ 8054263Sshin 8162587Sitojun#include <netinet/ip_encap.h> 8254263Sshin#include <net/if_gif.h> 8354263Sshin 8454263Sshin#include <net/net_osdep.h> 8554263Sshin 8679106Sbrooks#define GIFNAME "gif" 8762587Sitojun 88127305Srwatson/* 89127898Sru * gif_mtx protects the global gif_softc_list. 90127305Srwatson * XXX: Per-softc locking is still required. 91127305Srwatson */ 92127305Srwatsonstatic struct mtx gif_mtx; 9379106Sbrooksstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 9489065Smsmithstatic LIST_HEAD(, gif_softc) gif_softc_list; 9579106Sbrooks 9683998Sbrooksvoid (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 9783998Sbrooksvoid (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 9883998Sbrooksvoid (*ng_gif_attach_p)(struct ifnet *ifp); 9983998Sbrooksvoid (*ng_gif_detach_p)(struct ifnet *ifp); 10083998Sbrooks 101128209Sbrooksstatic int gif_clone_create(struct if_clone *, int); 102128209Sbrooksstatic void gif_clone_destroy(struct ifnet *); 10379106Sbrooks 104130933SbrooksIFC_SIMPLE_DECLARE(gif, 0); 10579106Sbrooks 10692725Salfredstatic int gifmodevent(module_t, int, void *); 10779106Sbrooks 10891270SbrooksSYSCTL_DECL(_net_link); 10991270SbrooksSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 11091270Sbrooks "Generic Tunnel Interface"); 11162587Sitojun#ifndef MAX_GIF_NEST 11262587Sitojun/* 11391270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels. 11462587Sitojun * Since, setting a large value to this macro with a careless configuration 11562587Sitojun * may introduce system crash, we don't allow any nestings by default. 11662587Sitojun * If you need to configure nested gif tunnels, you can define this macro 11795023Ssuz * in your kernel configuration file. However, if you do so, please be 11862587Sitojun * careful to configure the tunnels so that it won't make a loop. 11962587Sitojun */ 12062587Sitojun#define MAX_GIF_NEST 1 12162587Sitojun#endif 12262587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST; 12391270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 12491270Sbrooks &max_gif_nesting, 0, "Max nested tunnels"); 12562587Sitojun 12691270Sbrooks/* 12791270Sbrooks * By default, we disallow creation of multiple tunnels between the same 12891270Sbrooks * pair of addresses. Some applications require this functionality so 12991270Sbrooks * we allow control over this check here. 13091270Sbrooks */ 13191270Sbrooks#ifdef XBONEHACK 13291270Sbrooksstatic int parallel_tunnels = 1; 13391270Sbrooks#else 13491270Sbrooksstatic int parallel_tunnels = 0; 13591270Sbrooks#endif 13691270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 13791270Sbrooks ¶llel_tunnels, 0, "Allow parallel tunnels?"); 13891270Sbrooks 139128209Sbrooksstatic int 14079106Sbrooksgif_clone_create(ifc, unit) 14179106Sbrooks struct if_clone *ifc; 14292081Smux int unit; 14354263Sshin{ 14478064Sume struct gif_softc *sc; 14554263Sshin 146131672Sbms sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO); 14779106Sbrooks 14879106Sbrooks sc->gif_if.if_softc = sc; 149121816Sbrooks if_initname(&sc->gif_if, ifc->ifc_name, unit); 15079106Sbrooks 151105293Sume gifattach0(sc); 152105293Sume 153127305Srwatson mtx_lock(&gif_mtx); 154105293Sume LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 155127305Srwatson mtx_unlock(&gif_mtx); 156105293Sume return (0); 157105293Sume} 158105293Sume 159105293Sumevoid 160105293Sumegifattach0(sc) 161105293Sume struct gif_softc *sc; 162105293Sume{ 163105293Sume 16479106Sbrooks sc->encap_cookie4 = sc->encap_cookie6 = NULL; 16562587Sitojun 166105293Sume sc->gif_if.if_addrlen = 0; 16779106Sbrooks sc->gif_if.if_mtu = GIF_MTU; 16879106Sbrooks sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 16978064Sume#if 0 17079106Sbrooks /* turn off ingress filter */ 17179106Sbrooks sc->gif_if.if_flags |= IFF_LINK2; 17278064Sume#endif 17379106Sbrooks sc->gif_if.if_ioctl = gif_ioctl; 17479106Sbrooks sc->gif_if.if_output = gif_output; 17579106Sbrooks sc->gif_if.if_type = IFT_GIF; 17679106Sbrooks sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 17779106Sbrooks if_attach(&sc->gif_if); 17879106Sbrooks bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 17983998Sbrooks if (ng_gif_attach_p != NULL) 18083998Sbrooks (*ng_gif_attach_p)(&sc->gif_if); 18179106Sbrooks} 18279106Sbrooks 183127305Srwatsonstatic void 184127305Srwatsongif_destroy(struct gif_softc *sc) 18579106Sbrooks{ 186127305Srwatson struct ifnet *ifp = &sc->gif_if; 18779106Sbrooks int err; 18879106Sbrooks 189127305Srwatson gif_delete_tunnel(ifp); 190105293Sume#ifdef INET6 191105293Sume if (sc->encap_cookie6 != NULL) { 192105293Sume err = encap_detach(sc->encap_cookie6); 193105293Sume KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 194105293Sume } 195105293Sume#endif 196105293Sume#ifdef INET 19779106Sbrooks if (sc->encap_cookie4 != NULL) { 19879106Sbrooks err = encap_detach(sc->encap_cookie4); 19979106Sbrooks KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 20079106Sbrooks } 201105293Sume#endif 20279106Sbrooks 20383998Sbrooks if (ng_gif_detach_p != NULL) 20483998Sbrooks (*ng_gif_detach_p)(ifp); 20579106Sbrooks bpfdetach(ifp); 20679106Sbrooks if_detach(ifp); 20779106Sbrooks 20879106Sbrooks free(sc, M_GIF); 20979106Sbrooks} 21079106Sbrooks 211128209Sbrooksstatic void 212127305Srwatsongif_clone_destroy(ifp) 213127305Srwatson struct ifnet *ifp; 214127305Srwatson{ 215127305Srwatson struct gif_softc *sc = ifp->if_softc; 216127305Srwatson 217127305Srwatson mtx_lock(&gif_mtx); 218127305Srwatson LIST_REMOVE(sc, gif_list); 219127305Srwatson mtx_unlock(&gif_mtx); 220127305Srwatson gif_destroy(sc); 221127305Srwatson} 222127305Srwatson 22379106Sbrooksstatic int 22479106Sbrooksgifmodevent(mod, type, data) 22579106Sbrooks module_t mod; 22679106Sbrooks int type; 22779106Sbrooks void *data; 22879106Sbrooks{ 229127305Srwatson struct gif_softc *sc; 23079106Sbrooks 23179106Sbrooks switch (type) { 23279106Sbrooks case MOD_LOAD: 233127305Srwatson mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF); 23483997Sbrooks LIST_INIT(&gif_softc_list); 23579106Sbrooks if_clone_attach(&gif_cloner); 23679106Sbrooks 23779106Sbrooks#ifdef INET6 23879106Sbrooks ip6_gif_hlim = GIF_HLIM; 23962587Sitojun#endif 24079106Sbrooks 24179106Sbrooks break; 24279106Sbrooks case MOD_UNLOAD: 24379106Sbrooks if_clone_detach(&gif_cloner); 24479106Sbrooks 245127305Srwatson mtx_lock(&gif_mtx); 246127305Srwatson while ((sc = LIST_FIRST(&gif_softc_list)) != NULL) { 247127305Srwatson LIST_REMOVE(sc, gif_list); 248127305Srwatson mtx_unlock(&gif_mtx); 249127305Srwatson gif_destroy(sc); 250127305Srwatson mtx_lock(&gif_mtx); 251127305Srwatson } 252127305Srwatson mtx_unlock(&gif_mtx); 253127305Srwatson mtx_destroy(&gif_mtx); 25479106Sbrooks#ifdef INET6 25579106Sbrooks ip6_gif_hlim = 0; 25662587Sitojun#endif 25779106Sbrooks break; 258132199Sphk default: 259132199Sphk return EOPNOTSUPP; 26054263Sshin } 26179106Sbrooks return 0; 26254263Sshin} 26354263Sshin 26479106Sbrooksstatic moduledata_t gif_mod = { 26579106Sbrooks "if_gif", 26679106Sbrooks gifmodevent, 26779106Sbrooks 0 26879106Sbrooks}; 26954263Sshin 27079106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 27183997SbrooksMODULE_VERSION(if_gif, 1); 27279106Sbrooks 273105293Sumeint 27462587Sitojungif_encapcheck(m, off, proto, arg) 27562587Sitojun const struct mbuf *m; 27662587Sitojun int off; 27762587Sitojun int proto; 27862587Sitojun void *arg; 27962587Sitojun{ 28062587Sitojun struct ip ip; 28162587Sitojun struct gif_softc *sc; 28262587Sitojun 28362587Sitojun sc = (struct gif_softc *)arg; 28462587Sitojun if (sc == NULL) 28562587Sitojun return 0; 28662587Sitojun 28762587Sitojun if ((sc->gif_if.if_flags & IFF_UP) == 0) 28862587Sitojun return 0; 28962587Sitojun 29062587Sitojun /* no physical address */ 29162587Sitojun if (!sc->gif_psrc || !sc->gif_pdst) 29262587Sitojun return 0; 29362587Sitojun 29462587Sitojun switch (proto) { 29562587Sitojun#ifdef INET 29662587Sitojun case IPPROTO_IPV4: 29762587Sitojun break; 29862587Sitojun#endif 29962587Sitojun#ifdef INET6 30062587Sitojun case IPPROTO_IPV6: 30162587Sitojun break; 30262587Sitojun#endif 30362587Sitojun default: 30462587Sitojun return 0; 30562587Sitojun } 30662587Sitojun 307105339Sume /* Bail on short packets */ 308105339Sume if (m->m_pkthdr.len < sizeof(ip)) 309105339Sume return 0; 310105339Sume 31191327Sbrooks m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 31262587Sitojun 31362587Sitojun switch (ip.ip_v) { 31462587Sitojun#ifdef INET 31562587Sitojun case 4: 31662587Sitojun if (sc->gif_psrc->sa_family != AF_INET || 31762587Sitojun sc->gif_pdst->sa_family != AF_INET) 31862587Sitojun return 0; 31962587Sitojun return gif_encapcheck4(m, off, proto, arg); 32062587Sitojun#endif 32162587Sitojun#ifdef INET6 32262587Sitojun case 6: 323105293Sume if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 324105293Sume return 0; 32562587Sitojun if (sc->gif_psrc->sa_family != AF_INET6 || 32662587Sitojun sc->gif_pdst->sa_family != AF_INET6) 32762587Sitojun return 0; 32862587Sitojun return gif_encapcheck6(m, off, proto, arg); 32962587Sitojun#endif 33062587Sitojun default: 33162587Sitojun return 0; 33262587Sitojun } 33362587Sitojun} 33462587Sitojun 33554263Sshinint 33654263Sshingif_output(ifp, m, dst, rt) 33754263Sshin struct ifnet *ifp; 33854263Sshin struct mbuf *m; 33954263Sshin struct sockaddr *dst; 34054263Sshin struct rtentry *rt; /* added in net2 */ 34154263Sshin{ 34278064Sume struct gif_softc *sc = (struct gif_softc*)ifp; 343127898Sru struct m_tag *mtag; 34454263Sshin int error = 0; 345127898Sru int gif_called; 34654263Sshin 347101182Srwatson#ifdef MAC 348101182Srwatson error = mac_check_ifnet_transmit(ifp, m); 349101739Srwatson if (error) { 350101739Srwatson m_freem(m); 351101739Srwatson goto end; 352101739Srwatson } 353101182Srwatson#endif 354101182Srwatson 35554263Sshin /* 35654263Sshin * gif may cause infinite recursion calls when misconfigured. 357127898Sru * We'll prevent this by detecting loops. 358127898Sru * 359127898Sru * High nesting level may cause stack exhaustion. 36054263Sshin * We'll prevent this by introducing upper limit. 36154263Sshin */ 362127898Sru gif_called = 1; 363127898Sru mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, NULL); 364127898Sru while (mtag != NULL) { 365127898Sru if (*(struct ifnet **)(mtag + 1) == ifp) { 366127898Sru log(LOG_NOTICE, 367127898Sru "gif_output: loop detected on %s\n", 368127898Sru (*(struct ifnet **)(mtag + 1))->if_xname); 369127898Sru m_freem(m); 370127898Sru error = EIO; /* is there better errno? */ 371127898Sru goto end; 372127898Sru } 373127898Sru mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag); 374127898Sru gif_called++; 375127898Sru } 376127898Sru if (gif_called > max_gif_nesting) { 37754263Sshin log(LOG_NOTICE, 37854263Sshin "gif_output: recursively called too many times(%d)\n", 379127303Srwatson gif_called); 38054263Sshin m_freem(m); 38154263Sshin error = EIO; /* is there better errno? */ 38254263Sshin goto end; 38354263Sshin } 384127898Sru mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *), 385127898Sru M_NOWAIT); 386127898Sru if (mtag == NULL) { 387127898Sru m_freem(m); 388127898Sru error = ENOMEM; 389127898Sru goto end; 390127898Sru } 391127898Sru *(struct ifnet **)(mtag + 1) = ifp; 392127898Sru m_tag_prepend(m, mtag); 39362587Sitojun 39454263Sshin m->m_flags &= ~(M_BCAST|M_MCAST); 39554263Sshin if (!(ifp->if_flags & IFF_UP) || 39654263Sshin sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 39754263Sshin m_freem(m); 39854263Sshin error = ENETDOWN; 39954263Sshin goto end; 40054263Sshin } 40154263Sshin 40254263Sshin if (ifp->if_bpf) { 40378064Sume u_int32_t af = dst->sa_family; 404123922Ssam bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 40554263Sshin } 40662587Sitojun ifp->if_opackets++; 40754263Sshin ifp->if_obytes += m->m_pkthdr.len; 40854263Sshin 40978064Sume /* inner AF-specific encapsulation */ 41078064Sume 41162587Sitojun /* XXX should we check if our outer source is legal? */ 41262587Sitojun 41378064Sume /* dispatch to output logic based on outer AF */ 41454263Sshin switch (sc->gif_psrc->sa_family) { 41554263Sshin#ifdef INET 41654263Sshin case AF_INET: 417105340Sume error = in_gif_output(ifp, dst->sa_family, m); 41854263Sshin break; 41954263Sshin#endif 42054263Sshin#ifdef INET6 42154263Sshin case AF_INET6: 422105340Sume error = in6_gif_output(ifp, dst->sa_family, m); 42354263Sshin break; 42454263Sshin#endif 42554263Sshin default: 42662587Sitojun m_freem(m); 42754263Sshin error = ENETDOWN; 42878064Sume goto end; 42954263Sshin } 43054263Sshin 43154263Sshin end: 43278064Sume if (error) 43378064Sume ifp->if_oerrors++; 43454263Sshin return error; 43554263Sshin} 43654263Sshin 43754263Sshinvoid 438105338Sumegif_input(m, af, ifp) 43954263Sshin struct mbuf *m; 44054263Sshin int af; 441105338Sume struct ifnet *ifp; 44254263Sshin{ 44369152Sjlemon int isr; 44454263Sshin 445105338Sume if (ifp == NULL) { 44654263Sshin /* just in case */ 44754263Sshin m_freem(m); 44854263Sshin return; 44954263Sshin } 45054263Sshin 451105338Sume m->m_pkthdr.rcvif = ifp; 452101182Srwatson 453101182Srwatson#ifdef MAC 454105338Sume mac_create_mbuf_from_ifnet(ifp, m); 455101182Srwatson#endif 456101182Srwatson 457105338Sume if (ifp->if_bpf) { 45878064Sume u_int32_t af1 = af; 459123922Ssam bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 46054263Sshin } 46154263Sshin 46283998Sbrooks if (ng_gif_input_p != NULL) { 463105338Sume (*ng_gif_input_p)(ifp, &m, af); 46483998Sbrooks if (m == NULL) 46583998Sbrooks return; 46683998Sbrooks } 46783998Sbrooks 46854263Sshin /* 46954263Sshin * Put the packet to the network layer input queue according to the 47054263Sshin * specified address family. 47154263Sshin * Note: older versions of gif_input directly called network layer 47295023Ssuz * input functions, e.g. ip6_input, here. We changed the policy to 47354263Sshin * prevent too many recursive calls of such input functions, which 47495023Ssuz * might cause kernel panic. But the change may introduce another 47554263Sshin * problem; if the input queue is full, packets are discarded. 47695023Ssuz * The kernel stack overflow really happened, and we believed 47795023Ssuz * queue-full rarely occurs, so we changed the policy. 47854263Sshin */ 47954263Sshin switch (af) { 48054263Sshin#ifdef INET 48154263Sshin case AF_INET: 48254263Sshin isr = NETISR_IP; 48354263Sshin break; 48454263Sshin#endif 48554263Sshin#ifdef INET6 48654263Sshin case AF_INET6: 48754263Sshin isr = NETISR_IPV6; 48854263Sshin break; 48954263Sshin#endif 49054263Sshin default: 49183998Sbrooks if (ng_gif_input_orphan_p != NULL) 492105338Sume (*ng_gif_input_orphan_p)(ifp, m, af); 49383998Sbrooks else 49483998Sbrooks m_freem(m); 49554263Sshin return; 49654263Sshin } 49754263Sshin 498105338Sume ifp->if_ipackets++; 499105338Sume ifp->if_ibytes += m->m_pkthdr.len; 500111888Sjlemon netisr_dispatch(isr, m); 50154263Sshin} 50254263Sshin 50362587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 50454263Sshinint 50554263Sshingif_ioctl(ifp, cmd, data) 50654263Sshin struct ifnet *ifp; 50754263Sshin u_long cmd; 50854263Sshin caddr_t data; 50954263Sshin{ 51054263Sshin struct gif_softc *sc = (struct gif_softc*)ifp; 51154263Sshin struct ifreq *ifr = (struct ifreq*)data; 51254263Sshin int error = 0, size; 51362587Sitojun struct sockaddr *dst, *src; 514105339Sume#ifdef SIOCSIFMTU /* xxx */ 515105339Sume u_long mtu; 516105339Sume#endif 517105339Sume 51854263Sshin switch (cmd) { 51954263Sshin case SIOCSIFADDR: 520105293Sume ifp->if_flags |= IFF_UP; 52154263Sshin break; 52262587Sitojun 52354263Sshin case SIOCSIFDSTADDR: 52454263Sshin break; 52554263Sshin 52654263Sshin case SIOCADDMULTI: 52754263Sshin case SIOCDELMULTI: 52854263Sshin break; 52954263Sshin 53062587Sitojun#ifdef SIOCSIFMTU /* xxx */ 53154263Sshin case SIOCGIFMTU: 53254263Sshin break; 53362587Sitojun 53454263Sshin case SIOCSIFMTU: 535105339Sume mtu = ifr->ifr_mtu; 536105339Sume if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 537105339Sume return (EINVAL); 538105339Sume ifp->if_mtu = mtu; 53954263Sshin break; 54062587Sitojun#endif /* SIOCSIFMTU */ 54154263Sshin 542105339Sume#ifdef INET 54354263Sshin case SIOCSIFPHYADDR: 544105339Sume#endif 54554263Sshin#ifdef INET6 54654263Sshin case SIOCSIFPHYADDR_IN6: 54754263Sshin#endif /* INET6 */ 54878064Sume case SIOCSLIFPHYADDR: 54962587Sitojun switch (cmd) { 55078064Sume#ifdef INET 55162587Sitojun case SIOCSIFPHYADDR: 55254263Sshin src = (struct sockaddr *) 55354263Sshin &(((struct in_aliasreq *)data)->ifra_addr); 55454263Sshin dst = (struct sockaddr *) 55554263Sshin &(((struct in_aliasreq *)data)->ifra_dstaddr); 55662587Sitojun break; 55778064Sume#endif 55862587Sitojun#ifdef INET6 55962587Sitojun case SIOCSIFPHYADDR_IN6: 56062587Sitojun src = (struct sockaddr *) 56162587Sitojun &(((struct in6_aliasreq *)data)->ifra_addr); 56262587Sitojun dst = (struct sockaddr *) 56362587Sitojun &(((struct in6_aliasreq *)data)->ifra_dstaddr); 56462587Sitojun break; 56562587Sitojun#endif 56678064Sume case SIOCSLIFPHYADDR: 56778064Sume src = (struct sockaddr *) 56878064Sume &(((struct if_laddrreq *)data)->addr); 56978064Sume dst = (struct sockaddr *) 57078064Sume &(((struct if_laddrreq *)data)->dstaddr); 571105293Sume break; 57291327Sbrooks default: 573105293Sume return EINVAL; 57462587Sitojun } 57554263Sshin 57678064Sume /* sa_family must be equal */ 57778064Sume if (src->sa_family != dst->sa_family) 57878064Sume return EINVAL; 57978064Sume 58078064Sume /* validate sa_len */ 58178064Sume switch (src->sa_family) { 58278064Sume#ifdef INET 58378064Sume case AF_INET: 58478064Sume if (src->sa_len != sizeof(struct sockaddr_in)) 58578064Sume return EINVAL; 58678064Sume break; 58778064Sume#endif 58878064Sume#ifdef INET6 58978064Sume case AF_INET6: 59078064Sume if (src->sa_len != sizeof(struct sockaddr_in6)) 59178064Sume return EINVAL; 59278064Sume break; 59378064Sume#endif 59478064Sume default: 59578064Sume return EAFNOSUPPORT; 59678064Sume } 59778064Sume switch (dst->sa_family) { 59878064Sume#ifdef INET 59978064Sume case AF_INET: 60078064Sume if (dst->sa_len != sizeof(struct sockaddr_in)) 60178064Sume return EINVAL; 60278064Sume break; 60378064Sume#endif 60478064Sume#ifdef INET6 60578064Sume case AF_INET6: 60678064Sume if (dst->sa_len != sizeof(struct sockaddr_in6)) 60778064Sume return EINVAL; 60878064Sume break; 60978064Sume#endif 61078064Sume default: 61178064Sume return EAFNOSUPPORT; 61278064Sume } 61378064Sume 61478064Sume /* check sa_family looks sane for the cmd */ 61578064Sume switch (cmd) { 61678064Sume case SIOCSIFPHYADDR: 61778064Sume if (src->sa_family == AF_INET) 61878064Sume break; 61978064Sume return EAFNOSUPPORT; 62078064Sume#ifdef INET6 62178064Sume case SIOCSIFPHYADDR_IN6: 62278064Sume if (src->sa_family == AF_INET6) 62378064Sume break; 62478064Sume return EAFNOSUPPORT; 62578064Sume#endif /* INET6 */ 62678064Sume case SIOCSLIFPHYADDR: 62778064Sume /* checks done in the above */ 62878064Sume break; 62978064Sume } 63078064Sume 631105293Sume error = gif_set_tunnel(&sc->gif_if, src, dst); 63262587Sitojun break; 63362587Sitojun 63462587Sitojun#ifdef SIOCDIFPHYADDR 63562587Sitojun case SIOCDIFPHYADDR: 636105293Sume gif_delete_tunnel(&sc->gif_if); 63754263Sshin break; 63862587Sitojun#endif 63962587Sitojun 64054263Sshin case SIOCGIFPSRCADDR: 64154263Sshin#ifdef INET6 64254263Sshin case SIOCGIFPSRCADDR_IN6: 64354263Sshin#endif /* INET6 */ 64454263Sshin if (sc->gif_psrc == NULL) { 64554263Sshin error = EADDRNOTAVAIL; 64654263Sshin goto bad; 64754263Sshin } 64854263Sshin src = sc->gif_psrc; 64978064Sume switch (cmd) { 65054263Sshin#ifdef INET 65178064Sume case SIOCGIFPSRCADDR: 65254263Sshin dst = &ifr->ifr_addr; 65378064Sume size = sizeof(ifr->ifr_addr); 65454263Sshin break; 65554263Sshin#endif /* INET */ 65654263Sshin#ifdef INET6 65778064Sume case SIOCGIFPSRCADDR_IN6: 65854263Sshin dst = (struct sockaddr *) 65954263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 66078064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 66154263Sshin break; 66254263Sshin#endif /* INET6 */ 66354263Sshin default: 66454263Sshin error = EADDRNOTAVAIL; 66554263Sshin goto bad; 66654263Sshin } 66778064Sume if (src->sa_len > size) 66878064Sume return EINVAL; 66978064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 67054263Sshin break; 67162587Sitojun 67254263Sshin case SIOCGIFPDSTADDR: 67354263Sshin#ifdef INET6 67454263Sshin case SIOCGIFPDSTADDR_IN6: 67554263Sshin#endif /* INET6 */ 67654263Sshin if (sc->gif_pdst == NULL) { 67754263Sshin error = EADDRNOTAVAIL; 67854263Sshin goto bad; 67954263Sshin } 68054263Sshin src = sc->gif_pdst; 68178064Sume switch (cmd) { 68254263Sshin#ifdef INET 68378064Sume case SIOCGIFPDSTADDR: 68454263Sshin dst = &ifr->ifr_addr; 68578064Sume size = sizeof(ifr->ifr_addr); 68654263Sshin break; 68754263Sshin#endif /* INET */ 68854263Sshin#ifdef INET6 68978064Sume case SIOCGIFPDSTADDR_IN6: 69054263Sshin dst = (struct sockaddr *) 69154263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 69278064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 69354263Sshin break; 69454263Sshin#endif /* INET6 */ 69554263Sshin default: 69654263Sshin error = EADDRNOTAVAIL; 69754263Sshin goto bad; 69854263Sshin } 69978064Sume if (src->sa_len > size) 70078064Sume return EINVAL; 70178064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 70254263Sshin break; 70354263Sshin 70478064Sume case SIOCGLIFPHYADDR: 70578064Sume if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 70678064Sume error = EADDRNOTAVAIL; 70778064Sume goto bad; 70878064Sume } 70978064Sume 71078064Sume /* copy src */ 71178064Sume src = sc->gif_psrc; 71278064Sume dst = (struct sockaddr *) 71378064Sume &(((struct if_laddrreq *)data)->addr); 71478064Sume size = sizeof(((struct if_laddrreq *)data)->addr); 71578064Sume if (src->sa_len > size) 71678064Sume return EINVAL; 71778064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 71878064Sume 71978064Sume /* copy dst */ 72078064Sume src = sc->gif_pdst; 72178064Sume dst = (struct sockaddr *) 72278064Sume &(((struct if_laddrreq *)data)->dstaddr); 72378064Sume size = sizeof(((struct if_laddrreq *)data)->dstaddr); 72478064Sume if (src->sa_len > size) 72578064Sume return EINVAL; 72678064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 72778064Sume break; 72878064Sume 72954263Sshin case SIOCSIFFLAGS: 73062587Sitojun /* if_ioctl() takes care of it */ 73154263Sshin break; 73254263Sshin 73354263Sshin default: 73454263Sshin error = EINVAL; 73554263Sshin break; 73654263Sshin } 73754263Sshin bad: 73854263Sshin return error; 73954263Sshin} 74079106Sbrooks 741127305Srwatson/* 742127305Srwatson * XXXRW: There's a general event-ordering issue here: the code to check 743127305Srwatson * if a given tunnel is already present happens before we perform a 744127305Srwatson * potentially blocking setup of the tunnel. This code needs to be 745127305Srwatson * re-ordered so that the check and replacement can be atomic using 746127305Srwatson * a mutex. 747127305Srwatson */ 748105293Sumeint 749105293Sumegif_set_tunnel(ifp, src, dst) 750105293Sume struct ifnet *ifp; 751105293Sume struct sockaddr *src; 752105293Sume struct sockaddr *dst; 753105293Sume{ 754105293Sume struct gif_softc *sc = (struct gif_softc *)ifp; 755105293Sume struct gif_softc *sc2; 756105293Sume struct sockaddr *osrc, *odst, *sa; 757105293Sume int s; 758105293Sume int error = 0; 759105293Sume 760105293Sume s = splnet(); 761105293Sume 762127305Srwatson mtx_lock(&gif_mtx); 763105293Sume LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 764105293Sume if (sc2 == sc) 765105293Sume continue; 766105293Sume if (!sc2->gif_pdst || !sc2->gif_psrc) 767105293Sume continue; 768105293Sume if (sc2->gif_pdst->sa_family != dst->sa_family || 769105293Sume sc2->gif_pdst->sa_len != dst->sa_len || 770105293Sume sc2->gif_psrc->sa_family != src->sa_family || 771105293Sume sc2->gif_psrc->sa_len != src->sa_len) 772105293Sume continue; 773105293Sume 774105293Sume /* 775105293Sume * Disallow parallel tunnels unless instructed 776105293Sume * otherwise. 777105293Sume */ 778105293Sume if (!parallel_tunnels && 779105293Sume bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 780105293Sume bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 781105293Sume error = EADDRNOTAVAIL; 782127305Srwatson mtx_unlock(&gif_mtx); 783105293Sume goto bad; 784105293Sume } 785105293Sume 786105293Sume /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 787105293Sume } 788127305Srwatson mtx_unlock(&gif_mtx); 789105293Sume 790105293Sume /* XXX we can detach from both, but be polite just in case */ 791105293Sume if (sc->gif_psrc) 792105293Sume switch (sc->gif_psrc->sa_family) { 793105293Sume#ifdef INET 794105293Sume case AF_INET: 795105293Sume (void)in_gif_detach(sc); 796105293Sume break; 797105293Sume#endif 798105293Sume#ifdef INET6 799105293Sume case AF_INET6: 800105293Sume (void)in6_gif_detach(sc); 801105293Sume break; 802105293Sume#endif 803105293Sume } 804105293Sume 805105293Sume osrc = sc->gif_psrc; 806111119Simp sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 807105293Sume bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 808105293Sume sc->gif_psrc = sa; 809105293Sume 810105293Sume odst = sc->gif_pdst; 811111119Simp sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 812105293Sume bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 813105293Sume sc->gif_pdst = sa; 814105293Sume 815105293Sume switch (sc->gif_psrc->sa_family) { 816105293Sume#ifdef INET 817105293Sume case AF_INET: 818105293Sume error = in_gif_attach(sc); 819105293Sume break; 820105293Sume#endif 821105293Sume#ifdef INET6 822105293Sume case AF_INET6: 823105293Sume error = in6_gif_attach(sc); 824105293Sume break; 825105293Sume#endif 826105293Sume } 827105293Sume if (error) { 828105293Sume /* rollback */ 829105293Sume free((caddr_t)sc->gif_psrc, M_IFADDR); 830105293Sume free((caddr_t)sc->gif_pdst, M_IFADDR); 831105293Sume sc->gif_psrc = osrc; 832105293Sume sc->gif_pdst = odst; 833105293Sume goto bad; 834105293Sume } 835105293Sume 836105293Sume if (osrc) 837105293Sume free((caddr_t)osrc, M_IFADDR); 838105293Sume if (odst) 839105293Sume free((caddr_t)odst, M_IFADDR); 840105293Sume 841105293Sume if (sc->gif_psrc && sc->gif_pdst) 842105293Sume ifp->if_flags |= IFF_RUNNING; 843105293Sume else 844105293Sume ifp->if_flags &= ~IFF_RUNNING; 845105293Sume splx(s); 846105293Sume 847105293Sume return 0; 848105293Sume 849105293Sume bad: 850105293Sume if (sc->gif_psrc && sc->gif_pdst) 851105293Sume ifp->if_flags |= IFF_RUNNING; 852105293Sume else 853105293Sume ifp->if_flags &= ~IFF_RUNNING; 854105293Sume splx(s); 855105293Sume 856105293Sume return error; 857105293Sume} 858105293Sume 85979106Sbrooksvoid 860105293Sumegif_delete_tunnel(ifp) 861105293Sume struct ifnet *ifp; 86279106Sbrooks{ 863105293Sume struct gif_softc *sc = (struct gif_softc *)ifp; 864105293Sume int s; 86579106Sbrooks 866105293Sume s = splnet(); 867105293Sume 86879106Sbrooks if (sc->gif_psrc) { 86979106Sbrooks free((caddr_t)sc->gif_psrc, M_IFADDR); 87079106Sbrooks sc->gif_psrc = NULL; 87179106Sbrooks } 87279106Sbrooks if (sc->gif_pdst) { 87379106Sbrooks free((caddr_t)sc->gif_pdst, M_IFADDR); 87479106Sbrooks sc->gif_pdst = NULL; 87579106Sbrooks } 876105293Sume /* it is safe to detach from both */ 877105293Sume#ifdef INET 878105293Sume (void)in_gif_detach(sc); 879105293Sume#endif 880105293Sume#ifdef INET6 881105293Sume (void)in6_gif_detach(sc); 882105293Sume#endif 883105293Sume 884105293Sume if (sc->gif_psrc && sc->gif_pdst) 885105293Sume ifp->if_flags |= IFF_RUNNING; 886105293Sume else 887105293Sume ifp->if_flags &= ~IFF_RUNNING; 888105293Sume splx(s); 88979106Sbrooks} 890