if_gif.c revision 127303
162587Sitojun/* $FreeBSD: head/sys/net/if_gif.c 127303 2004-03-22 14:24:26Z rwatson $ */ 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> 4354263Sshin#include <sys/socket.h> 4454263Sshin#include <sys/sockio.h> 4554263Sshin#include <sys/errno.h> 4654263Sshin#include <sys/time.h> 4791270Sbrooks#include <sys/sysctl.h> 4854263Sshin#include <sys/syslog.h> 4962587Sitojun#include <sys/protosw.h> 5079106Sbrooks#include <sys/conf.h> 5154263Sshin#include <machine/cpu.h> 5254263Sshin 5354263Sshin#include <net/if.h> 5454263Sshin#include <net/if_types.h> 5554263Sshin#include <net/netisr.h> 5654263Sshin#include <net/route.h> 5754263Sshin#include <net/bpf.h> 5854263Sshin 5954263Sshin#include <netinet/in.h> 6054263Sshin#include <netinet/in_systm.h> 6178064Sume#include <netinet/ip.h> 6278064Sume#ifdef INET 6354263Sshin#include <netinet/in_var.h> 6454263Sshin#include <netinet/in_gif.h> 6579106Sbrooks#include <netinet/ip_var.h> 6654263Sshin#endif /* INET */ 6754263Sshin 6854263Sshin#ifdef INET6 6954263Sshin#ifndef INET 7054263Sshin#include <netinet/in.h> 7154263Sshin#endif 7254263Sshin#include <netinet6/in6_var.h> 7354263Sshin#include <netinet/ip6.h> 7454263Sshin#include <netinet6/ip6_var.h> 7554263Sshin#include <netinet6/in6_gif.h> 7662587Sitojun#include <netinet6/ip6protosw.h> 7754263Sshin#endif /* INET6 */ 7854263Sshin 7962587Sitojun#include <netinet/ip_encap.h> 8054263Sshin#include <net/if_gif.h> 8154263Sshin 8254263Sshin#include <net/net_osdep.h> 8354263Sshin 8479106Sbrooks#define GIFNAME "gif" 8562587Sitojun 8679106Sbrooksstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 8789065Smsmithstatic LIST_HEAD(, gif_softc) gif_softc_list; 8879106Sbrooks 89127303Srwatson/* 90127303Srwatson * XXX: gif_called is a recursion counter to prevent misconfiguration to 91127303Srwatson * cause unbounded looping in the network stack. However, this is a flawed 92127303Srwatson * approach as it assumes non-reentrance in the stack. This should be 93127303Srwatson * changed to use packet tags to track recusion.. 94127303Srwatson */ 95127303Srwatsonstatic int gif_called = 0; 96127303Srwatson 9783998Sbrooksvoid (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 9883998Sbrooksvoid (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 9983998Sbrooksvoid (*ng_gif_attach_p)(struct ifnet *ifp); 10083998Sbrooksvoid (*ng_gif_detach_p)(struct ifnet *ifp); 10183998Sbrooks 10292725Salfredint gif_clone_create(struct if_clone *, int); 10397289Sbrooksvoid gif_clone_destroy(struct ifnet *); 10479106Sbrooks 10592081Smuxstruct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", 10697289Sbrooks gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT); 10779106Sbrooks 10892725Salfredstatic int gifmodevent(module_t, int, void *); 10979106Sbrooks 11091270SbrooksSYSCTL_DECL(_net_link); 11191270SbrooksSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 11291270Sbrooks "Generic Tunnel Interface"); 11362587Sitojun#ifndef MAX_GIF_NEST 11462587Sitojun/* 11591270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels. 11662587Sitojun * Since, setting a large value to this macro with a careless configuration 11762587Sitojun * may introduce system crash, we don't allow any nestings by default. 11862587Sitojun * If you need to configure nested gif tunnels, you can define this macro 11995023Ssuz * in your kernel configuration file. However, if you do so, please be 12062587Sitojun * careful to configure the tunnels so that it won't make a loop. 12162587Sitojun */ 12262587Sitojun#define MAX_GIF_NEST 1 12362587Sitojun#endif 12462587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST; 12591270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 12691270Sbrooks &max_gif_nesting, 0, "Max nested tunnels"); 12762587Sitojun 12891270Sbrooks/* 12991270Sbrooks * By default, we disallow creation of multiple tunnels between the same 13091270Sbrooks * pair of addresses. Some applications require this functionality so 13191270Sbrooks * we allow control over this check here. 13291270Sbrooks */ 13391270Sbrooks#ifdef XBONEHACK 13491270Sbrooksstatic int parallel_tunnels = 1; 13591270Sbrooks#else 13691270Sbrooksstatic int parallel_tunnels = 0; 13791270Sbrooks#endif 13891270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 13991270Sbrooks ¶llel_tunnels, 0, "Allow parallel tunnels?"); 14091270Sbrooks 14179106Sbrooksint 14279106Sbrooksgif_clone_create(ifc, unit) 14379106Sbrooks struct if_clone *ifc; 14492081Smux int unit; 14554263Sshin{ 14678064Sume struct gif_softc *sc; 14754263Sshin 148111119Simp sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK); 14979106Sbrooks bzero(sc, sizeof(struct gif_softc)); 15079106Sbrooks 15179106Sbrooks sc->gif_if.if_softc = sc; 152121816Sbrooks if_initname(&sc->gif_if, ifc->ifc_name, unit); 15379106Sbrooks 154105293Sume gifattach0(sc); 155105293Sume 156105293Sume LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 157105293Sume return (0); 158105293Sume} 159105293Sume 160105293Sumevoid 161105293Sumegifattach0(sc) 162105293Sume struct gif_softc *sc; 163105293Sume{ 164105293Sume 16579106Sbrooks sc->encap_cookie4 = sc->encap_cookie6 = NULL; 16662587Sitojun 167105293Sume sc->gif_if.if_addrlen = 0; 16879106Sbrooks sc->gif_if.if_mtu = GIF_MTU; 16979106Sbrooks sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 17078064Sume#if 0 17179106Sbrooks /* turn off ingress filter */ 17279106Sbrooks sc->gif_if.if_flags |= IFF_LINK2; 17378064Sume#endif 17479106Sbrooks sc->gif_if.if_ioctl = gif_ioctl; 17579106Sbrooks sc->gif_if.if_output = gif_output; 17679106Sbrooks sc->gif_if.if_type = IFT_GIF; 17779106Sbrooks sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 17879106Sbrooks if_attach(&sc->gif_if); 17979106Sbrooks bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 18083998Sbrooks if (ng_gif_attach_p != NULL) 18183998Sbrooks (*ng_gif_attach_p)(&sc->gif_if); 18279106Sbrooks} 18379106Sbrooks 18497289Sbrooksvoid 18579106Sbrooksgif_clone_destroy(ifp) 18679106Sbrooks struct ifnet *ifp; 18779106Sbrooks{ 18879106Sbrooks int err; 18979106Sbrooks struct gif_softc *sc = ifp->if_softc; 19079106Sbrooks 191105293Sume gif_delete_tunnel(&sc->gif_if); 192105293Sume LIST_REMOVE(sc, gif_list); 193105293Sume#ifdef INET6 194105293Sume if (sc->encap_cookie6 != NULL) { 195105293Sume err = encap_detach(sc->encap_cookie6); 196105293Sume KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 197105293Sume } 198105293Sume#endif 199105293Sume#ifdef INET 20079106Sbrooks if (sc->encap_cookie4 != NULL) { 20179106Sbrooks err = encap_detach(sc->encap_cookie4); 20279106Sbrooks KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 20379106Sbrooks } 204105293Sume#endif 20579106Sbrooks 20683998Sbrooks if (ng_gif_detach_p != NULL) 20783998Sbrooks (*ng_gif_detach_p)(ifp); 20879106Sbrooks bpfdetach(ifp); 20979106Sbrooks if_detach(ifp); 21079106Sbrooks 21179106Sbrooks free(sc, M_GIF); 21279106Sbrooks} 21379106Sbrooks 21479106Sbrooksstatic int 21579106Sbrooksgifmodevent(mod, type, data) 21679106Sbrooks module_t mod; 21779106Sbrooks int type; 21879106Sbrooks void *data; 21979106Sbrooks{ 22079106Sbrooks 22179106Sbrooks switch (type) { 22279106Sbrooks case MOD_LOAD: 22383997Sbrooks LIST_INIT(&gif_softc_list); 22479106Sbrooks if_clone_attach(&gif_cloner); 22579106Sbrooks 22679106Sbrooks#ifdef INET6 22779106Sbrooks ip6_gif_hlim = GIF_HLIM; 22862587Sitojun#endif 22979106Sbrooks 23079106Sbrooks break; 23179106Sbrooks case MOD_UNLOAD: 23279106Sbrooks if_clone_detach(&gif_cloner); 23379106Sbrooks 23483997Sbrooks while (!LIST_EMPTY(&gif_softc_list)) 23583997Sbrooks gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if); 23679106Sbrooks 23779106Sbrooks#ifdef INET6 23879106Sbrooks ip6_gif_hlim = 0; 23962587Sitojun#endif 24079106Sbrooks break; 24154263Sshin } 24279106Sbrooks return 0; 24354263Sshin} 24454263Sshin 24579106Sbrooksstatic moduledata_t gif_mod = { 24679106Sbrooks "if_gif", 24779106Sbrooks gifmodevent, 24879106Sbrooks 0 24979106Sbrooks}; 25054263Sshin 25179106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 25283997SbrooksMODULE_VERSION(if_gif, 1); 25379106Sbrooks 254105293Sumeint 25562587Sitojungif_encapcheck(m, off, proto, arg) 25662587Sitojun const struct mbuf *m; 25762587Sitojun int off; 25862587Sitojun int proto; 25962587Sitojun void *arg; 26062587Sitojun{ 26162587Sitojun struct ip ip; 26262587Sitojun struct gif_softc *sc; 26362587Sitojun 26462587Sitojun sc = (struct gif_softc *)arg; 26562587Sitojun if (sc == NULL) 26662587Sitojun return 0; 26762587Sitojun 26862587Sitojun if ((sc->gif_if.if_flags & IFF_UP) == 0) 26962587Sitojun return 0; 27062587Sitojun 27162587Sitojun /* no physical address */ 27262587Sitojun if (!sc->gif_psrc || !sc->gif_pdst) 27362587Sitojun return 0; 27462587Sitojun 27562587Sitojun switch (proto) { 27662587Sitojun#ifdef INET 27762587Sitojun case IPPROTO_IPV4: 27862587Sitojun break; 27962587Sitojun#endif 28062587Sitojun#ifdef INET6 28162587Sitojun case IPPROTO_IPV6: 28262587Sitojun break; 28362587Sitojun#endif 28462587Sitojun default: 28562587Sitojun return 0; 28662587Sitojun } 28762587Sitojun 288105339Sume /* Bail on short packets */ 289105339Sume if (m->m_pkthdr.len < sizeof(ip)) 290105339Sume return 0; 291105339Sume 29291327Sbrooks m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 29362587Sitojun 29462587Sitojun switch (ip.ip_v) { 29562587Sitojun#ifdef INET 29662587Sitojun case 4: 29762587Sitojun if (sc->gif_psrc->sa_family != AF_INET || 29862587Sitojun sc->gif_pdst->sa_family != AF_INET) 29962587Sitojun return 0; 30062587Sitojun return gif_encapcheck4(m, off, proto, arg); 30162587Sitojun#endif 30262587Sitojun#ifdef INET6 30362587Sitojun case 6: 304105293Sume if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 305105293Sume return 0; 30662587Sitojun if (sc->gif_psrc->sa_family != AF_INET6 || 30762587Sitojun sc->gif_pdst->sa_family != AF_INET6) 30862587Sitojun return 0; 30962587Sitojun return gif_encapcheck6(m, off, proto, arg); 31062587Sitojun#endif 31162587Sitojun default: 31262587Sitojun return 0; 31362587Sitojun } 31462587Sitojun} 31562587Sitojun 31654263Sshinint 31754263Sshingif_output(ifp, m, dst, rt) 31854263Sshin struct ifnet *ifp; 31954263Sshin struct mbuf *m; 32054263Sshin struct sockaddr *dst; 32154263Sshin struct rtentry *rt; /* added in net2 */ 32254263Sshin{ 32378064Sume struct gif_softc *sc = (struct gif_softc*)ifp; 32454263Sshin int error = 0; 32554263Sshin 326101182Srwatson#ifdef MAC 327101182Srwatson error = mac_check_ifnet_transmit(ifp, m); 328101739Srwatson if (error) { 329101739Srwatson m_freem(m); 330101739Srwatson goto end; 331101739Srwatson } 332101182Srwatson#endif 333101182Srwatson 33454263Sshin /* 33554263Sshin * gif may cause infinite recursion calls when misconfigured. 33654263Sshin * We'll prevent this by introducing upper limit. 337103273Ssobomax * XXX: this mechanism may introduce another problem about 338103273Ssobomax * mutual exclusion of the variable CALLED, especially if we 339103273Ssobomax * use kernel thread. 34054263Sshin */ 341127303Srwatson if (++gif_called > max_gif_nesting) { 34254263Sshin log(LOG_NOTICE, 34354263Sshin "gif_output: recursively called too many times(%d)\n", 344127303Srwatson gif_called); 34554263Sshin m_freem(m); 34654263Sshin error = EIO; /* is there better errno? */ 34754263Sshin goto end; 34854263Sshin } 34962587Sitojun 35054263Sshin m->m_flags &= ~(M_BCAST|M_MCAST); 35154263Sshin if (!(ifp->if_flags & IFF_UP) || 35254263Sshin sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 35354263Sshin m_freem(m); 35454263Sshin error = ENETDOWN; 35554263Sshin goto end; 35654263Sshin } 35754263Sshin 35854263Sshin if (ifp->if_bpf) { 35978064Sume u_int32_t af = dst->sa_family; 360123922Ssam bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 36154263Sshin } 36262587Sitojun ifp->if_opackets++; 36354263Sshin ifp->if_obytes += m->m_pkthdr.len; 36454263Sshin 36578064Sume /* inner AF-specific encapsulation */ 36678064Sume 36762587Sitojun /* XXX should we check if our outer source is legal? */ 36862587Sitojun 36978064Sume /* dispatch to output logic based on outer AF */ 37054263Sshin switch (sc->gif_psrc->sa_family) { 37154263Sshin#ifdef INET 37254263Sshin case AF_INET: 373105340Sume error = in_gif_output(ifp, dst->sa_family, m); 37454263Sshin break; 37554263Sshin#endif 37654263Sshin#ifdef INET6 37754263Sshin case AF_INET6: 378105340Sume error = in6_gif_output(ifp, dst->sa_family, m); 37954263Sshin break; 38054263Sshin#endif 38154263Sshin default: 38262587Sitojun m_freem(m); 38354263Sshin error = ENETDOWN; 38478064Sume goto end; 38554263Sshin } 38654263Sshin 38754263Sshin end: 388127303Srwatson gif_called = 0; /* reset recursion counter */ 38978064Sume if (error) 39078064Sume ifp->if_oerrors++; 39154263Sshin return error; 39254263Sshin} 39354263Sshin 39454263Sshinvoid 395105338Sumegif_input(m, af, ifp) 39654263Sshin struct mbuf *m; 39754263Sshin int af; 398105338Sume struct ifnet *ifp; 39954263Sshin{ 40069152Sjlemon int isr; 40154263Sshin 402105338Sume if (ifp == NULL) { 40354263Sshin /* just in case */ 40454263Sshin m_freem(m); 40554263Sshin return; 40654263Sshin } 40754263Sshin 408105338Sume m->m_pkthdr.rcvif = ifp; 409101182Srwatson 410101182Srwatson#ifdef MAC 411105338Sume mac_create_mbuf_from_ifnet(ifp, m); 412101182Srwatson#endif 413101182Srwatson 414105338Sume if (ifp->if_bpf) { 41578064Sume u_int32_t af1 = af; 416123922Ssam bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 41754263Sshin } 41854263Sshin 41983998Sbrooks if (ng_gif_input_p != NULL) { 420105338Sume (*ng_gif_input_p)(ifp, &m, af); 42183998Sbrooks if (m == NULL) 42283998Sbrooks return; 42383998Sbrooks } 42483998Sbrooks 42554263Sshin /* 42654263Sshin * Put the packet to the network layer input queue according to the 42754263Sshin * specified address family. 42854263Sshin * Note: older versions of gif_input directly called network layer 42995023Ssuz * input functions, e.g. ip6_input, here. We changed the policy to 43054263Sshin * prevent too many recursive calls of such input functions, which 43195023Ssuz * might cause kernel panic. But the change may introduce another 43254263Sshin * problem; if the input queue is full, packets are discarded. 43395023Ssuz * The kernel stack overflow really happened, and we believed 43495023Ssuz * queue-full rarely occurs, so we changed the policy. 43554263Sshin */ 43654263Sshin switch (af) { 43754263Sshin#ifdef INET 43854263Sshin case AF_INET: 43954263Sshin isr = NETISR_IP; 44054263Sshin break; 44154263Sshin#endif 44254263Sshin#ifdef INET6 44354263Sshin case AF_INET6: 44454263Sshin isr = NETISR_IPV6; 44554263Sshin break; 44654263Sshin#endif 44754263Sshin default: 44883998Sbrooks if (ng_gif_input_orphan_p != NULL) 449105338Sume (*ng_gif_input_orphan_p)(ifp, m, af); 45083998Sbrooks else 45183998Sbrooks m_freem(m); 45254263Sshin return; 45354263Sshin } 45454263Sshin 455105338Sume ifp->if_ipackets++; 456105338Sume ifp->if_ibytes += m->m_pkthdr.len; 457111888Sjlemon netisr_dispatch(isr, m); 45854263Sshin} 45954263Sshin 46062587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 46154263Sshinint 46254263Sshingif_ioctl(ifp, cmd, data) 46354263Sshin struct ifnet *ifp; 46454263Sshin u_long cmd; 46554263Sshin caddr_t data; 46654263Sshin{ 46754263Sshin struct gif_softc *sc = (struct gif_softc*)ifp; 46854263Sshin struct ifreq *ifr = (struct ifreq*)data; 46954263Sshin int error = 0, size; 47062587Sitojun struct sockaddr *dst, *src; 471105339Sume#ifdef SIOCSIFMTU /* xxx */ 472105339Sume u_long mtu; 473105339Sume#endif 474105339Sume 47554263Sshin switch (cmd) { 47654263Sshin case SIOCSIFADDR: 477105293Sume ifp->if_flags |= IFF_UP; 47854263Sshin break; 47962587Sitojun 48054263Sshin case SIOCSIFDSTADDR: 48154263Sshin break; 48254263Sshin 48354263Sshin case SIOCADDMULTI: 48454263Sshin case SIOCDELMULTI: 48554263Sshin break; 48654263Sshin 48762587Sitojun#ifdef SIOCSIFMTU /* xxx */ 48854263Sshin case SIOCGIFMTU: 48954263Sshin break; 49062587Sitojun 49154263Sshin case SIOCSIFMTU: 492105339Sume mtu = ifr->ifr_mtu; 493105339Sume if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 494105339Sume return (EINVAL); 495105339Sume ifp->if_mtu = mtu; 49654263Sshin break; 49762587Sitojun#endif /* SIOCSIFMTU */ 49854263Sshin 499105339Sume#ifdef INET 50054263Sshin case SIOCSIFPHYADDR: 501105339Sume#endif 50254263Sshin#ifdef INET6 50354263Sshin case SIOCSIFPHYADDR_IN6: 50454263Sshin#endif /* INET6 */ 50578064Sume case SIOCSLIFPHYADDR: 50662587Sitojun switch (cmd) { 50778064Sume#ifdef INET 50862587Sitojun case SIOCSIFPHYADDR: 50954263Sshin src = (struct sockaddr *) 51054263Sshin &(((struct in_aliasreq *)data)->ifra_addr); 51154263Sshin dst = (struct sockaddr *) 51254263Sshin &(((struct in_aliasreq *)data)->ifra_dstaddr); 51362587Sitojun break; 51478064Sume#endif 51562587Sitojun#ifdef INET6 51662587Sitojun case SIOCSIFPHYADDR_IN6: 51762587Sitojun src = (struct sockaddr *) 51862587Sitojun &(((struct in6_aliasreq *)data)->ifra_addr); 51962587Sitojun dst = (struct sockaddr *) 52062587Sitojun &(((struct in6_aliasreq *)data)->ifra_dstaddr); 52162587Sitojun break; 52262587Sitojun#endif 52378064Sume case SIOCSLIFPHYADDR: 52478064Sume src = (struct sockaddr *) 52578064Sume &(((struct if_laddrreq *)data)->addr); 52678064Sume dst = (struct sockaddr *) 52778064Sume &(((struct if_laddrreq *)data)->dstaddr); 528105293Sume break; 52991327Sbrooks default: 530105293Sume return EINVAL; 53162587Sitojun } 53254263Sshin 53378064Sume /* sa_family must be equal */ 53478064Sume if (src->sa_family != dst->sa_family) 53578064Sume return EINVAL; 53678064Sume 53778064Sume /* validate sa_len */ 53878064Sume switch (src->sa_family) { 53978064Sume#ifdef INET 54078064Sume case AF_INET: 54178064Sume if (src->sa_len != sizeof(struct sockaddr_in)) 54278064Sume return EINVAL; 54378064Sume break; 54478064Sume#endif 54578064Sume#ifdef INET6 54678064Sume case AF_INET6: 54778064Sume if (src->sa_len != sizeof(struct sockaddr_in6)) 54878064Sume return EINVAL; 54978064Sume break; 55078064Sume#endif 55178064Sume default: 55278064Sume return EAFNOSUPPORT; 55378064Sume } 55478064Sume switch (dst->sa_family) { 55578064Sume#ifdef INET 55678064Sume case AF_INET: 55778064Sume if (dst->sa_len != sizeof(struct sockaddr_in)) 55878064Sume return EINVAL; 55978064Sume break; 56078064Sume#endif 56178064Sume#ifdef INET6 56278064Sume case AF_INET6: 56378064Sume if (dst->sa_len != sizeof(struct sockaddr_in6)) 56478064Sume return EINVAL; 56578064Sume break; 56678064Sume#endif 56778064Sume default: 56878064Sume return EAFNOSUPPORT; 56978064Sume } 57078064Sume 57178064Sume /* check sa_family looks sane for the cmd */ 57278064Sume switch (cmd) { 57378064Sume case SIOCSIFPHYADDR: 57478064Sume if (src->sa_family == AF_INET) 57578064Sume break; 57678064Sume return EAFNOSUPPORT; 57778064Sume#ifdef INET6 57878064Sume case SIOCSIFPHYADDR_IN6: 57978064Sume if (src->sa_family == AF_INET6) 58078064Sume break; 58178064Sume return EAFNOSUPPORT; 58278064Sume#endif /* INET6 */ 58378064Sume case SIOCSLIFPHYADDR: 58478064Sume /* checks done in the above */ 58578064Sume break; 58678064Sume } 58778064Sume 588105293Sume error = gif_set_tunnel(&sc->gif_if, src, dst); 58962587Sitojun break; 59062587Sitojun 59162587Sitojun#ifdef SIOCDIFPHYADDR 59262587Sitojun case SIOCDIFPHYADDR: 593105293Sume gif_delete_tunnel(&sc->gif_if); 59454263Sshin break; 59562587Sitojun#endif 59662587Sitojun 59754263Sshin case SIOCGIFPSRCADDR: 59854263Sshin#ifdef INET6 59954263Sshin case SIOCGIFPSRCADDR_IN6: 60054263Sshin#endif /* INET6 */ 60154263Sshin if (sc->gif_psrc == NULL) { 60254263Sshin error = EADDRNOTAVAIL; 60354263Sshin goto bad; 60454263Sshin } 60554263Sshin src = sc->gif_psrc; 60678064Sume switch (cmd) { 60754263Sshin#ifdef INET 60878064Sume case SIOCGIFPSRCADDR: 60954263Sshin dst = &ifr->ifr_addr; 61078064Sume size = sizeof(ifr->ifr_addr); 61154263Sshin break; 61254263Sshin#endif /* INET */ 61354263Sshin#ifdef INET6 61478064Sume case SIOCGIFPSRCADDR_IN6: 61554263Sshin dst = (struct sockaddr *) 61654263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 61778064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 61854263Sshin break; 61954263Sshin#endif /* INET6 */ 62054263Sshin default: 62154263Sshin error = EADDRNOTAVAIL; 62254263Sshin goto bad; 62354263Sshin } 62478064Sume if (src->sa_len > size) 62578064Sume return EINVAL; 62678064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 62754263Sshin break; 62862587Sitojun 62954263Sshin case SIOCGIFPDSTADDR: 63054263Sshin#ifdef INET6 63154263Sshin case SIOCGIFPDSTADDR_IN6: 63254263Sshin#endif /* INET6 */ 63354263Sshin if (sc->gif_pdst == NULL) { 63454263Sshin error = EADDRNOTAVAIL; 63554263Sshin goto bad; 63654263Sshin } 63754263Sshin src = sc->gif_pdst; 63878064Sume switch (cmd) { 63954263Sshin#ifdef INET 64078064Sume case SIOCGIFPDSTADDR: 64154263Sshin dst = &ifr->ifr_addr; 64278064Sume size = sizeof(ifr->ifr_addr); 64354263Sshin break; 64454263Sshin#endif /* INET */ 64554263Sshin#ifdef INET6 64678064Sume case SIOCGIFPDSTADDR_IN6: 64754263Sshin dst = (struct sockaddr *) 64854263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 64978064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 65054263Sshin break; 65154263Sshin#endif /* INET6 */ 65254263Sshin default: 65354263Sshin error = EADDRNOTAVAIL; 65454263Sshin goto bad; 65554263Sshin } 65678064Sume if (src->sa_len > size) 65778064Sume return EINVAL; 65878064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 65954263Sshin break; 66054263Sshin 66178064Sume case SIOCGLIFPHYADDR: 66278064Sume if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 66378064Sume error = EADDRNOTAVAIL; 66478064Sume goto bad; 66578064Sume } 66678064Sume 66778064Sume /* copy src */ 66878064Sume src = sc->gif_psrc; 66978064Sume dst = (struct sockaddr *) 67078064Sume &(((struct if_laddrreq *)data)->addr); 67178064Sume size = sizeof(((struct if_laddrreq *)data)->addr); 67278064Sume if (src->sa_len > size) 67378064Sume return EINVAL; 67478064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 67578064Sume 67678064Sume /* copy dst */ 67778064Sume src = sc->gif_pdst; 67878064Sume dst = (struct sockaddr *) 67978064Sume &(((struct if_laddrreq *)data)->dstaddr); 68078064Sume size = sizeof(((struct if_laddrreq *)data)->dstaddr); 68178064Sume if (src->sa_len > size) 68278064Sume return EINVAL; 68378064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 68478064Sume break; 68578064Sume 68654263Sshin case SIOCSIFFLAGS: 68762587Sitojun /* if_ioctl() takes care of it */ 68854263Sshin break; 68954263Sshin 69054263Sshin default: 69154263Sshin error = EINVAL; 69254263Sshin break; 69354263Sshin } 69454263Sshin bad: 69554263Sshin return error; 69654263Sshin} 69779106Sbrooks 698105293Sumeint 699105293Sumegif_set_tunnel(ifp, src, dst) 700105293Sume struct ifnet *ifp; 701105293Sume struct sockaddr *src; 702105293Sume struct sockaddr *dst; 703105293Sume{ 704105293Sume struct gif_softc *sc = (struct gif_softc *)ifp; 705105293Sume struct gif_softc *sc2; 706105293Sume struct sockaddr *osrc, *odst, *sa; 707105293Sume int s; 708105293Sume int error = 0; 709105293Sume 710105293Sume s = splnet(); 711105293Sume 712105293Sume LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 713105293Sume if (sc2 == sc) 714105293Sume continue; 715105293Sume if (!sc2->gif_pdst || !sc2->gif_psrc) 716105293Sume continue; 717105293Sume if (sc2->gif_pdst->sa_family != dst->sa_family || 718105293Sume sc2->gif_pdst->sa_len != dst->sa_len || 719105293Sume sc2->gif_psrc->sa_family != src->sa_family || 720105293Sume sc2->gif_psrc->sa_len != src->sa_len) 721105293Sume continue; 722105293Sume 723105293Sume /* 724105293Sume * Disallow parallel tunnels unless instructed 725105293Sume * otherwise. 726105293Sume */ 727105293Sume if (!parallel_tunnels && 728105293Sume bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 729105293Sume bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 730105293Sume error = EADDRNOTAVAIL; 731105293Sume goto bad; 732105293Sume } 733105293Sume 734105293Sume /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 735105293Sume } 736105293Sume 737105293Sume /* XXX we can detach from both, but be polite just in case */ 738105293Sume if (sc->gif_psrc) 739105293Sume switch (sc->gif_psrc->sa_family) { 740105293Sume#ifdef INET 741105293Sume case AF_INET: 742105293Sume (void)in_gif_detach(sc); 743105293Sume break; 744105293Sume#endif 745105293Sume#ifdef INET6 746105293Sume case AF_INET6: 747105293Sume (void)in6_gif_detach(sc); 748105293Sume break; 749105293Sume#endif 750105293Sume } 751105293Sume 752105293Sume osrc = sc->gif_psrc; 753111119Simp sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 754105293Sume bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 755105293Sume sc->gif_psrc = sa; 756105293Sume 757105293Sume odst = sc->gif_pdst; 758111119Simp sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 759105293Sume bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 760105293Sume sc->gif_pdst = sa; 761105293Sume 762105293Sume switch (sc->gif_psrc->sa_family) { 763105293Sume#ifdef INET 764105293Sume case AF_INET: 765105293Sume error = in_gif_attach(sc); 766105293Sume break; 767105293Sume#endif 768105293Sume#ifdef INET6 769105293Sume case AF_INET6: 770105293Sume error = in6_gif_attach(sc); 771105293Sume break; 772105293Sume#endif 773105293Sume } 774105293Sume if (error) { 775105293Sume /* rollback */ 776105293Sume free((caddr_t)sc->gif_psrc, M_IFADDR); 777105293Sume free((caddr_t)sc->gif_pdst, M_IFADDR); 778105293Sume sc->gif_psrc = osrc; 779105293Sume sc->gif_pdst = odst; 780105293Sume goto bad; 781105293Sume } 782105293Sume 783105293Sume if (osrc) 784105293Sume free((caddr_t)osrc, M_IFADDR); 785105293Sume if (odst) 786105293Sume free((caddr_t)odst, M_IFADDR); 787105293Sume 788105293Sume if (sc->gif_psrc && sc->gif_pdst) 789105293Sume ifp->if_flags |= IFF_RUNNING; 790105293Sume else 791105293Sume ifp->if_flags &= ~IFF_RUNNING; 792105293Sume splx(s); 793105293Sume 794105293Sume return 0; 795105293Sume 796105293Sume bad: 797105293Sume if (sc->gif_psrc && sc->gif_pdst) 798105293Sume ifp->if_flags |= IFF_RUNNING; 799105293Sume else 800105293Sume ifp->if_flags &= ~IFF_RUNNING; 801105293Sume splx(s); 802105293Sume 803105293Sume return error; 804105293Sume} 805105293Sume 80679106Sbrooksvoid 807105293Sumegif_delete_tunnel(ifp) 808105293Sume struct ifnet *ifp; 80979106Sbrooks{ 810105293Sume struct gif_softc *sc = (struct gif_softc *)ifp; 811105293Sume int s; 81279106Sbrooks 813105293Sume s = splnet(); 814105293Sume 81579106Sbrooks if (sc->gif_psrc) { 81679106Sbrooks free((caddr_t)sc->gif_psrc, M_IFADDR); 81779106Sbrooks sc->gif_psrc = NULL; 81879106Sbrooks } 81979106Sbrooks if (sc->gif_pdst) { 82079106Sbrooks free((caddr_t)sc->gif_pdst, M_IFADDR); 82179106Sbrooks sc->gif_pdst = NULL; 82279106Sbrooks } 823105293Sume /* it is safe to detach from both */ 824105293Sume#ifdef INET 825105293Sume (void)in_gif_detach(sc); 826105293Sume#endif 827105293Sume#ifdef INET6 828105293Sume (void)in6_gif_detach(sc); 829105293Sume#endif 830105293Sume 831105293Sume if (sc->gif_psrc && sc->gif_pdst) 832105293Sume ifp->if_flags |= IFF_RUNNING; 833105293Sume else 834105293Sume ifp->if_flags &= ~IFF_RUNNING; 835105293Sume splx(s); 83679106Sbrooks} 837