if_gif.c revision 111119
162587Sitojun/* $FreeBSD: head/sys/net/if_gif.c 111119 2003-02-19 05:47:46Z imp $ */ 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 8983998Sbrooksvoid (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 9083998Sbrooksvoid (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 9183998Sbrooksvoid (*ng_gif_attach_p)(struct ifnet *ifp); 9283998Sbrooksvoid (*ng_gif_detach_p)(struct ifnet *ifp); 9383998Sbrooks 9492725Salfredint gif_clone_create(struct if_clone *, int); 9597289Sbrooksvoid gif_clone_destroy(struct ifnet *); 9679106Sbrooks 9792081Smuxstruct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", 9897289Sbrooks gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT); 9979106Sbrooks 10092725Salfredstatic int gifmodevent(module_t, int, void *); 10179106Sbrooks 10291270SbrooksSYSCTL_DECL(_net_link); 10391270SbrooksSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 10491270Sbrooks "Generic Tunnel Interface"); 10562587Sitojun#ifndef MAX_GIF_NEST 10662587Sitojun/* 10791270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels. 10862587Sitojun * Since, setting a large value to this macro with a careless configuration 10962587Sitojun * may introduce system crash, we don't allow any nestings by default. 11062587Sitojun * If you need to configure nested gif tunnels, you can define this macro 11195023Ssuz * in your kernel configuration file. However, if you do so, please be 11262587Sitojun * careful to configure the tunnels so that it won't make a loop. 11362587Sitojun */ 11462587Sitojun#define MAX_GIF_NEST 1 11562587Sitojun#endif 11662587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST; 11791270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 11891270Sbrooks &max_gif_nesting, 0, "Max nested tunnels"); 11962587Sitojun 12091270Sbrooks/* 12191270Sbrooks * By default, we disallow creation of multiple tunnels between the same 12291270Sbrooks * pair of addresses. Some applications require this functionality so 12391270Sbrooks * we allow control over this check here. 12491270Sbrooks */ 12591270Sbrooks#ifdef XBONEHACK 12691270Sbrooksstatic int parallel_tunnels = 1; 12791270Sbrooks#else 12891270Sbrooksstatic int parallel_tunnels = 0; 12991270Sbrooks#endif 13091270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 13191270Sbrooks ¶llel_tunnels, 0, "Allow parallel tunnels?"); 13291270Sbrooks 13379106Sbrooksint 13479106Sbrooksgif_clone_create(ifc, unit) 13579106Sbrooks struct if_clone *ifc; 13692081Smux int unit; 13754263Sshin{ 13878064Sume struct gif_softc *sc; 13954263Sshin 140111119Simp sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK); 14179106Sbrooks bzero(sc, sizeof(struct gif_softc)); 14279106Sbrooks 14379106Sbrooks sc->gif_if.if_softc = sc; 14479106Sbrooks sc->gif_if.if_name = GIFNAME; 14592081Smux sc->gif_if.if_unit = unit; 14679106Sbrooks 147105293Sume gifattach0(sc); 148105293Sume 149105293Sume LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 150105293Sume return (0); 151105293Sume} 152105293Sume 153105293Sumevoid 154105293Sumegifattach0(sc) 155105293Sume struct gif_softc *sc; 156105293Sume{ 157105293Sume 15879106Sbrooks sc->encap_cookie4 = sc->encap_cookie6 = NULL; 15962587Sitojun 160105293Sume sc->gif_if.if_addrlen = 0; 16179106Sbrooks sc->gif_if.if_mtu = GIF_MTU; 16279106Sbrooks sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 16378064Sume#if 0 16479106Sbrooks /* turn off ingress filter */ 16579106Sbrooks sc->gif_if.if_flags |= IFF_LINK2; 16678064Sume#endif 16779106Sbrooks sc->gif_if.if_ioctl = gif_ioctl; 16879106Sbrooks sc->gif_if.if_output = gif_output; 16979106Sbrooks sc->gif_if.if_type = IFT_GIF; 17079106Sbrooks sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 17179106Sbrooks if_attach(&sc->gif_if); 17279106Sbrooks bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 17383998Sbrooks if (ng_gif_attach_p != NULL) 17483998Sbrooks (*ng_gif_attach_p)(&sc->gif_if); 17579106Sbrooks} 17679106Sbrooks 17797289Sbrooksvoid 17879106Sbrooksgif_clone_destroy(ifp) 17979106Sbrooks struct ifnet *ifp; 18079106Sbrooks{ 18179106Sbrooks int err; 18279106Sbrooks struct gif_softc *sc = ifp->if_softc; 18379106Sbrooks 184105293Sume gif_delete_tunnel(&sc->gif_if); 185105293Sume LIST_REMOVE(sc, gif_list); 186105293Sume#ifdef INET6 187105293Sume if (sc->encap_cookie6 != NULL) { 188105293Sume err = encap_detach(sc->encap_cookie6); 189105293Sume KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 190105293Sume } 191105293Sume#endif 192105293Sume#ifdef INET 19379106Sbrooks if (sc->encap_cookie4 != NULL) { 19479106Sbrooks err = encap_detach(sc->encap_cookie4); 19579106Sbrooks KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 19679106Sbrooks } 197105293Sume#endif 19879106Sbrooks 19983998Sbrooks if (ng_gif_detach_p != NULL) 20083998Sbrooks (*ng_gif_detach_p)(ifp); 20179106Sbrooks bpfdetach(ifp); 20279106Sbrooks if_detach(ifp); 20379106Sbrooks 20479106Sbrooks free(sc, M_GIF); 20579106Sbrooks} 20679106Sbrooks 20779106Sbrooksstatic int 20879106Sbrooksgifmodevent(mod, type, data) 20979106Sbrooks module_t mod; 21079106Sbrooks int type; 21179106Sbrooks void *data; 21279106Sbrooks{ 21379106Sbrooks 21479106Sbrooks switch (type) { 21579106Sbrooks case MOD_LOAD: 21683997Sbrooks LIST_INIT(&gif_softc_list); 21779106Sbrooks if_clone_attach(&gif_cloner); 21879106Sbrooks 21979106Sbrooks#ifdef INET6 22079106Sbrooks ip6_gif_hlim = GIF_HLIM; 22162587Sitojun#endif 22279106Sbrooks 22379106Sbrooks break; 22479106Sbrooks case MOD_UNLOAD: 22579106Sbrooks if_clone_detach(&gif_cloner); 22679106Sbrooks 22783997Sbrooks while (!LIST_EMPTY(&gif_softc_list)) 22883997Sbrooks gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if); 22979106Sbrooks 23079106Sbrooks#ifdef INET6 23179106Sbrooks ip6_gif_hlim = 0; 23262587Sitojun#endif 23379106Sbrooks break; 23454263Sshin } 23579106Sbrooks return 0; 23654263Sshin} 23754263Sshin 23879106Sbrooksstatic moduledata_t gif_mod = { 23979106Sbrooks "if_gif", 24079106Sbrooks gifmodevent, 24179106Sbrooks 0 24279106Sbrooks}; 24354263Sshin 24479106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 24583997SbrooksMODULE_VERSION(if_gif, 1); 24679106Sbrooks 247105293Sumeint 24862587Sitojungif_encapcheck(m, off, proto, arg) 24962587Sitojun const struct mbuf *m; 25062587Sitojun int off; 25162587Sitojun int proto; 25262587Sitojun void *arg; 25362587Sitojun{ 25462587Sitojun struct ip ip; 25562587Sitojun struct gif_softc *sc; 25662587Sitojun 25762587Sitojun sc = (struct gif_softc *)arg; 25862587Sitojun if (sc == NULL) 25962587Sitojun return 0; 26062587Sitojun 26162587Sitojun if ((sc->gif_if.if_flags & IFF_UP) == 0) 26262587Sitojun return 0; 26362587Sitojun 26462587Sitojun /* no physical address */ 26562587Sitojun if (!sc->gif_psrc || !sc->gif_pdst) 26662587Sitojun return 0; 26762587Sitojun 26862587Sitojun switch (proto) { 26962587Sitojun#ifdef INET 27062587Sitojun case IPPROTO_IPV4: 27162587Sitojun break; 27262587Sitojun#endif 27362587Sitojun#ifdef INET6 27462587Sitojun case IPPROTO_IPV6: 27562587Sitojun break; 27662587Sitojun#endif 27762587Sitojun default: 27862587Sitojun return 0; 27962587Sitojun } 28062587Sitojun 281105339Sume /* Bail on short packets */ 282105339Sume if (m->m_pkthdr.len < sizeof(ip)) 283105339Sume return 0; 284105339Sume 28591327Sbrooks m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 28662587Sitojun 28762587Sitojun switch (ip.ip_v) { 28862587Sitojun#ifdef INET 28962587Sitojun case 4: 29062587Sitojun if (sc->gif_psrc->sa_family != AF_INET || 29162587Sitojun sc->gif_pdst->sa_family != AF_INET) 29262587Sitojun return 0; 29362587Sitojun return gif_encapcheck4(m, off, proto, arg); 29462587Sitojun#endif 29562587Sitojun#ifdef INET6 29662587Sitojun case 6: 297105293Sume if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 298105293Sume return 0; 29962587Sitojun if (sc->gif_psrc->sa_family != AF_INET6 || 30062587Sitojun sc->gif_pdst->sa_family != AF_INET6) 30162587Sitojun return 0; 30262587Sitojun return gif_encapcheck6(m, off, proto, arg); 30362587Sitojun#endif 30462587Sitojun default: 30562587Sitojun return 0; 30662587Sitojun } 30762587Sitojun} 30862587Sitojun 30954263Sshinint 31054263Sshingif_output(ifp, m, dst, rt) 31154263Sshin struct ifnet *ifp; 31254263Sshin struct mbuf *m; 31354263Sshin struct sockaddr *dst; 31454263Sshin struct rtentry *rt; /* added in net2 */ 31554263Sshin{ 31678064Sume struct gif_softc *sc = (struct gif_softc*)ifp; 31754263Sshin int error = 0; 318103273Ssobomax static int called = 0; /* XXX: MUTEX */ 31954263Sshin 320101182Srwatson#ifdef MAC 321101182Srwatson error = mac_check_ifnet_transmit(ifp, m); 322101739Srwatson if (error) { 323101739Srwatson m_freem(m); 324101739Srwatson goto end; 325101739Srwatson } 326101182Srwatson#endif 327101182Srwatson 32854263Sshin /* 32954263Sshin * gif may cause infinite recursion calls when misconfigured. 33054263Sshin * We'll prevent this by introducing upper limit. 331103273Ssobomax * XXX: this mechanism may introduce another problem about 332103273Ssobomax * mutual exclusion of the variable CALLED, especially if we 333103273Ssobomax * use kernel thread. 33454263Sshin */ 335103273Ssobomax if (++called > max_gif_nesting) { 33654263Sshin log(LOG_NOTICE, 33754263Sshin "gif_output: recursively called too many times(%d)\n", 338103273Ssobomax called); 33954263Sshin m_freem(m); 34054263Sshin error = EIO; /* is there better errno? */ 34154263Sshin goto end; 34254263Sshin } 34362587Sitojun 34454263Sshin m->m_flags &= ~(M_BCAST|M_MCAST); 34554263Sshin if (!(ifp->if_flags & IFF_UP) || 34654263Sshin sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 34754263Sshin m_freem(m); 34854263Sshin error = ENETDOWN; 34954263Sshin goto end; 35054263Sshin } 35154263Sshin 35254263Sshin if (ifp->if_bpf) { 35354263Sshin /* 35454263Sshin * We need to prepend the address family as 35554263Sshin * a four byte field. Cons up a dummy header 35654263Sshin * to pacify bpf. This is safe because bpf 35754263Sshin * will only read from the mbuf (i.e., it won't 35854263Sshin * try to free it or keep a pointer a to it). 35954263Sshin */ 36054263Sshin struct mbuf m0; 36178064Sume u_int32_t af = dst->sa_family; 36254263Sshin 36354263Sshin m0.m_next = m; 36454263Sshin m0.m_len = 4; 36554263Sshin m0.m_data = (char *)⁡ 36662587Sitojun 367106939Ssam BPF_MTAP(ifp, &m0); 36854263Sshin } 36962587Sitojun ifp->if_opackets++; 37054263Sshin ifp->if_obytes += m->m_pkthdr.len; 37154263Sshin 37278064Sume /* inner AF-specific encapsulation */ 37378064Sume 37462587Sitojun /* XXX should we check if our outer source is legal? */ 37562587Sitojun 37678064Sume /* dispatch to output logic based on outer AF */ 37754263Sshin switch (sc->gif_psrc->sa_family) { 37854263Sshin#ifdef INET 37954263Sshin case AF_INET: 380105340Sume error = in_gif_output(ifp, dst->sa_family, m); 38154263Sshin break; 38254263Sshin#endif 38354263Sshin#ifdef INET6 38454263Sshin case AF_INET6: 385105340Sume error = in6_gif_output(ifp, dst->sa_family, m); 38654263Sshin break; 38754263Sshin#endif 38854263Sshin default: 38962587Sitojun m_freem(m); 39054263Sshin error = ENETDOWN; 39178064Sume goto end; 39254263Sshin } 39354263Sshin 39454263Sshin end: 395103273Ssobomax called = 0; /* reset recursion counter */ 39678064Sume if (error) 39778064Sume ifp->if_oerrors++; 39854263Sshin return error; 39954263Sshin} 40054263Sshin 40154263Sshinvoid 402105338Sumegif_input(m, af, ifp) 40354263Sshin struct mbuf *m; 40454263Sshin int af; 405105338Sume struct ifnet *ifp; 40654263Sshin{ 40769152Sjlemon int isr; 408105339Sume struct ifqueue *ifq = NULL; 40954263Sshin 410105338Sume if (ifp == NULL) { 41154263Sshin /* just in case */ 41254263Sshin m_freem(m); 41354263Sshin return; 41454263Sshin } 41554263Sshin 416105338Sume m->m_pkthdr.rcvif = ifp; 417101182Srwatson 418101182Srwatson#ifdef MAC 419105338Sume mac_create_mbuf_from_ifnet(ifp, m); 420101182Srwatson#endif 421101182Srwatson 422105338Sume if (ifp->if_bpf) { 42354263Sshin /* 42454263Sshin * We need to prepend the address family as 42554263Sshin * a four byte field. Cons up a dummy header 42654263Sshin * to pacify bpf. This is safe because bpf 42754263Sshin * will only read from the mbuf (i.e., it won't 42854263Sshin * try to free it or keep a pointer a to it). 42954263Sshin */ 43054263Sshin struct mbuf m0; 43178064Sume u_int32_t af1 = af; 43262587Sitojun 43354263Sshin m0.m_next = m; 43454263Sshin m0.m_len = 4; 43578064Sume m0.m_data = (char *)&af1; 43662587Sitojun 437106939Ssam BPF_MTAP(ifp, &m0); 43854263Sshin } 43954263Sshin 44083998Sbrooks if (ng_gif_input_p != NULL) { 441105338Sume (*ng_gif_input_p)(ifp, &m, af); 44283998Sbrooks if (m == NULL) 44383998Sbrooks return; 44483998Sbrooks } 44583998Sbrooks 44654263Sshin /* 44754263Sshin * Put the packet to the network layer input queue according to the 44854263Sshin * specified address family. 44954263Sshin * Note: older versions of gif_input directly called network layer 45095023Ssuz * input functions, e.g. ip6_input, here. We changed the policy to 45154263Sshin * prevent too many recursive calls of such input functions, which 45295023Ssuz * might cause kernel panic. But the change may introduce another 45354263Sshin * problem; if the input queue is full, packets are discarded. 45495023Ssuz * The kernel stack overflow really happened, and we believed 45595023Ssuz * queue-full rarely occurs, so we changed the policy. 45654263Sshin */ 45754263Sshin switch (af) { 45854263Sshin#ifdef INET 45954263Sshin case AF_INET: 46054263Sshin ifq = &ipintrq; 46154263Sshin isr = NETISR_IP; 46254263Sshin break; 46354263Sshin#endif 46454263Sshin#ifdef INET6 46554263Sshin case AF_INET6: 46654263Sshin ifq = &ip6intrq; 46754263Sshin isr = NETISR_IPV6; 46854263Sshin break; 46954263Sshin#endif 47054263Sshin default: 47183998Sbrooks if (ng_gif_input_orphan_p != NULL) 472105338Sume (*ng_gif_input_orphan_p)(ifp, m, af); 47383998Sbrooks else 47483998Sbrooks m_freem(m); 47554263Sshin return; 47654263Sshin } 47754263Sshin 478105338Sume ifp->if_ipackets++; 479105338Sume ifp->if_ibytes += m->m_pkthdr.len; 48069152Sjlemon (void) IF_HANDOFF(ifq, m, NULL); 48154263Sshin /* we need schednetisr since the address family may change */ 48254263Sshin schednetisr(isr); 48354263Sshin 48454263Sshin return; 48554263Sshin} 48654263Sshin 48762587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 48854263Sshinint 48954263Sshingif_ioctl(ifp, cmd, data) 49054263Sshin struct ifnet *ifp; 49154263Sshin u_long cmd; 49254263Sshin caddr_t data; 49354263Sshin{ 49454263Sshin struct gif_softc *sc = (struct gif_softc*)ifp; 49554263Sshin struct ifreq *ifr = (struct ifreq*)data; 49654263Sshin int error = 0, size; 49762587Sitojun struct sockaddr *dst, *src; 498105339Sume#ifdef SIOCSIFMTU /* xxx */ 499105339Sume u_long mtu; 500105339Sume#endif 501105339Sume 50254263Sshin switch (cmd) { 50354263Sshin case SIOCSIFADDR: 504105293Sume ifp->if_flags |= IFF_UP; 50554263Sshin break; 50662587Sitojun 50754263Sshin case SIOCSIFDSTADDR: 50854263Sshin break; 50954263Sshin 51054263Sshin case SIOCADDMULTI: 51154263Sshin case SIOCDELMULTI: 51254263Sshin break; 51354263Sshin 51462587Sitojun#ifdef SIOCSIFMTU /* xxx */ 51554263Sshin case SIOCGIFMTU: 51654263Sshin break; 51762587Sitojun 51854263Sshin case SIOCSIFMTU: 519105339Sume mtu = ifr->ifr_mtu; 520105339Sume if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 521105339Sume return (EINVAL); 522105339Sume ifp->if_mtu = mtu; 52354263Sshin break; 52462587Sitojun#endif /* SIOCSIFMTU */ 52554263Sshin 526105339Sume#ifdef INET 52754263Sshin case SIOCSIFPHYADDR: 528105339Sume#endif 52954263Sshin#ifdef INET6 53054263Sshin case SIOCSIFPHYADDR_IN6: 53154263Sshin#endif /* INET6 */ 53278064Sume case SIOCSLIFPHYADDR: 53362587Sitojun switch (cmd) { 53478064Sume#ifdef INET 53562587Sitojun case SIOCSIFPHYADDR: 53654263Sshin src = (struct sockaddr *) 53754263Sshin &(((struct in_aliasreq *)data)->ifra_addr); 53854263Sshin dst = (struct sockaddr *) 53954263Sshin &(((struct in_aliasreq *)data)->ifra_dstaddr); 54062587Sitojun break; 54178064Sume#endif 54262587Sitojun#ifdef INET6 54362587Sitojun case SIOCSIFPHYADDR_IN6: 54462587Sitojun src = (struct sockaddr *) 54562587Sitojun &(((struct in6_aliasreq *)data)->ifra_addr); 54662587Sitojun dst = (struct sockaddr *) 54762587Sitojun &(((struct in6_aliasreq *)data)->ifra_dstaddr); 54862587Sitojun break; 54962587Sitojun#endif 55078064Sume case SIOCSLIFPHYADDR: 55178064Sume src = (struct sockaddr *) 55278064Sume &(((struct if_laddrreq *)data)->addr); 55378064Sume dst = (struct sockaddr *) 55478064Sume &(((struct if_laddrreq *)data)->dstaddr); 555105293Sume break; 55691327Sbrooks default: 557105293Sume return EINVAL; 55862587Sitojun } 55954263Sshin 56078064Sume /* sa_family must be equal */ 56178064Sume if (src->sa_family != dst->sa_family) 56278064Sume return EINVAL; 56378064Sume 56478064Sume /* validate sa_len */ 56578064Sume switch (src->sa_family) { 56678064Sume#ifdef INET 56778064Sume case AF_INET: 56878064Sume if (src->sa_len != sizeof(struct sockaddr_in)) 56978064Sume return EINVAL; 57078064Sume break; 57178064Sume#endif 57278064Sume#ifdef INET6 57378064Sume case AF_INET6: 57478064Sume if (src->sa_len != sizeof(struct sockaddr_in6)) 57578064Sume return EINVAL; 57678064Sume break; 57778064Sume#endif 57878064Sume default: 57978064Sume return EAFNOSUPPORT; 58078064Sume } 58178064Sume switch (dst->sa_family) { 58278064Sume#ifdef INET 58378064Sume case AF_INET: 58478064Sume if (dst->sa_len != sizeof(struct sockaddr_in)) 58578064Sume return EINVAL; 58678064Sume break; 58778064Sume#endif 58878064Sume#ifdef INET6 58978064Sume case AF_INET6: 59078064Sume if (dst->sa_len != sizeof(struct sockaddr_in6)) 59178064Sume return EINVAL; 59278064Sume break; 59378064Sume#endif 59478064Sume default: 59578064Sume return EAFNOSUPPORT; 59678064Sume } 59778064Sume 59878064Sume /* check sa_family looks sane for the cmd */ 59978064Sume switch (cmd) { 60078064Sume case SIOCSIFPHYADDR: 60178064Sume if (src->sa_family == AF_INET) 60278064Sume break; 60378064Sume return EAFNOSUPPORT; 60478064Sume#ifdef INET6 60578064Sume case SIOCSIFPHYADDR_IN6: 60678064Sume if (src->sa_family == AF_INET6) 60778064Sume break; 60878064Sume return EAFNOSUPPORT; 60978064Sume#endif /* INET6 */ 61078064Sume case SIOCSLIFPHYADDR: 61178064Sume /* checks done in the above */ 61278064Sume break; 61378064Sume } 61478064Sume 615105293Sume error = gif_set_tunnel(&sc->gif_if, src, dst); 61662587Sitojun break; 61762587Sitojun 61862587Sitojun#ifdef SIOCDIFPHYADDR 61962587Sitojun case SIOCDIFPHYADDR: 620105293Sume gif_delete_tunnel(&sc->gif_if); 62154263Sshin break; 62262587Sitojun#endif 62362587Sitojun 62454263Sshin case SIOCGIFPSRCADDR: 62554263Sshin#ifdef INET6 62654263Sshin case SIOCGIFPSRCADDR_IN6: 62754263Sshin#endif /* INET6 */ 62854263Sshin if (sc->gif_psrc == NULL) { 62954263Sshin error = EADDRNOTAVAIL; 63054263Sshin goto bad; 63154263Sshin } 63254263Sshin src = sc->gif_psrc; 63378064Sume switch (cmd) { 63454263Sshin#ifdef INET 63578064Sume case SIOCGIFPSRCADDR: 63654263Sshin dst = &ifr->ifr_addr; 63778064Sume size = sizeof(ifr->ifr_addr); 63854263Sshin break; 63954263Sshin#endif /* INET */ 64054263Sshin#ifdef INET6 64178064Sume case SIOCGIFPSRCADDR_IN6: 64254263Sshin dst = (struct sockaddr *) 64354263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 64478064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 64554263Sshin break; 64654263Sshin#endif /* INET6 */ 64754263Sshin default: 64854263Sshin error = EADDRNOTAVAIL; 64954263Sshin goto bad; 65054263Sshin } 65178064Sume if (src->sa_len > size) 65278064Sume return EINVAL; 65378064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 65454263Sshin break; 65562587Sitojun 65654263Sshin case SIOCGIFPDSTADDR: 65754263Sshin#ifdef INET6 65854263Sshin case SIOCGIFPDSTADDR_IN6: 65954263Sshin#endif /* INET6 */ 66054263Sshin if (sc->gif_pdst == NULL) { 66154263Sshin error = EADDRNOTAVAIL; 66254263Sshin goto bad; 66354263Sshin } 66454263Sshin src = sc->gif_pdst; 66578064Sume switch (cmd) { 66654263Sshin#ifdef INET 66778064Sume case SIOCGIFPDSTADDR: 66854263Sshin dst = &ifr->ifr_addr; 66978064Sume size = sizeof(ifr->ifr_addr); 67054263Sshin break; 67154263Sshin#endif /* INET */ 67254263Sshin#ifdef INET6 67378064Sume case SIOCGIFPDSTADDR_IN6: 67454263Sshin dst = (struct sockaddr *) 67554263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 67678064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 67754263Sshin break; 67854263Sshin#endif /* INET6 */ 67954263Sshin default: 68054263Sshin error = EADDRNOTAVAIL; 68154263Sshin goto bad; 68254263Sshin } 68378064Sume if (src->sa_len > size) 68478064Sume return EINVAL; 68578064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 68654263Sshin break; 68754263Sshin 68878064Sume case SIOCGLIFPHYADDR: 68978064Sume if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 69078064Sume error = EADDRNOTAVAIL; 69178064Sume goto bad; 69278064Sume } 69378064Sume 69478064Sume /* copy src */ 69578064Sume src = sc->gif_psrc; 69678064Sume dst = (struct sockaddr *) 69778064Sume &(((struct if_laddrreq *)data)->addr); 69878064Sume size = sizeof(((struct if_laddrreq *)data)->addr); 69978064Sume if (src->sa_len > size) 70078064Sume return EINVAL; 70178064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 70278064Sume 70378064Sume /* copy dst */ 70478064Sume src = sc->gif_pdst; 70578064Sume dst = (struct sockaddr *) 70678064Sume &(((struct if_laddrreq *)data)->dstaddr); 70778064Sume size = sizeof(((struct if_laddrreq *)data)->dstaddr); 70878064Sume if (src->sa_len > size) 70978064Sume return EINVAL; 71078064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 71178064Sume break; 71278064Sume 71354263Sshin case SIOCSIFFLAGS: 71462587Sitojun /* if_ioctl() takes care of it */ 71554263Sshin break; 71654263Sshin 71754263Sshin default: 71854263Sshin error = EINVAL; 71954263Sshin break; 72054263Sshin } 72154263Sshin bad: 72254263Sshin return error; 72354263Sshin} 72479106Sbrooks 725105293Sumeint 726105293Sumegif_set_tunnel(ifp, src, dst) 727105293Sume struct ifnet *ifp; 728105293Sume struct sockaddr *src; 729105293Sume struct sockaddr *dst; 730105293Sume{ 731105293Sume struct gif_softc *sc = (struct gif_softc *)ifp; 732105293Sume struct gif_softc *sc2; 733105293Sume struct sockaddr *osrc, *odst, *sa; 734105293Sume int s; 735105293Sume int error = 0; 736105293Sume 737105293Sume s = splnet(); 738105293Sume 739105293Sume LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 740105293Sume if (sc2 == sc) 741105293Sume continue; 742105293Sume if (!sc2->gif_pdst || !sc2->gif_psrc) 743105293Sume continue; 744105293Sume if (sc2->gif_pdst->sa_family != dst->sa_family || 745105293Sume sc2->gif_pdst->sa_len != dst->sa_len || 746105293Sume sc2->gif_psrc->sa_family != src->sa_family || 747105293Sume sc2->gif_psrc->sa_len != src->sa_len) 748105293Sume continue; 749105293Sume 750105293Sume /* 751105293Sume * Disallow parallel tunnels unless instructed 752105293Sume * otherwise. 753105293Sume */ 754105293Sume if (!parallel_tunnels && 755105293Sume bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 756105293Sume bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 757105293Sume error = EADDRNOTAVAIL; 758105293Sume goto bad; 759105293Sume } 760105293Sume 761105293Sume /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 762105293Sume } 763105293Sume 764105293Sume /* XXX we can detach from both, but be polite just in case */ 765105293Sume if (sc->gif_psrc) 766105293Sume switch (sc->gif_psrc->sa_family) { 767105293Sume#ifdef INET 768105293Sume case AF_INET: 769105293Sume (void)in_gif_detach(sc); 770105293Sume break; 771105293Sume#endif 772105293Sume#ifdef INET6 773105293Sume case AF_INET6: 774105293Sume (void)in6_gif_detach(sc); 775105293Sume break; 776105293Sume#endif 777105293Sume } 778105293Sume 779105293Sume osrc = sc->gif_psrc; 780111119Simp sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 781105293Sume bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 782105293Sume sc->gif_psrc = sa; 783105293Sume 784105293Sume odst = sc->gif_pdst; 785111119Simp sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 786105293Sume bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 787105293Sume sc->gif_pdst = sa; 788105293Sume 789105293Sume switch (sc->gif_psrc->sa_family) { 790105293Sume#ifdef INET 791105293Sume case AF_INET: 792105293Sume error = in_gif_attach(sc); 793105293Sume break; 794105293Sume#endif 795105293Sume#ifdef INET6 796105293Sume case AF_INET6: 797105293Sume error = in6_gif_attach(sc); 798105293Sume break; 799105293Sume#endif 800105293Sume } 801105293Sume if (error) { 802105293Sume /* rollback */ 803105293Sume free((caddr_t)sc->gif_psrc, M_IFADDR); 804105293Sume free((caddr_t)sc->gif_pdst, M_IFADDR); 805105293Sume sc->gif_psrc = osrc; 806105293Sume sc->gif_pdst = odst; 807105293Sume goto bad; 808105293Sume } 809105293Sume 810105293Sume if (osrc) 811105293Sume free((caddr_t)osrc, M_IFADDR); 812105293Sume if (odst) 813105293Sume free((caddr_t)odst, M_IFADDR); 814105293Sume 815105293Sume if (sc->gif_psrc && sc->gif_pdst) 816105293Sume ifp->if_flags |= IFF_RUNNING; 817105293Sume else 818105293Sume ifp->if_flags &= ~IFF_RUNNING; 819105293Sume splx(s); 820105293Sume 821105293Sume return 0; 822105293Sume 823105293Sume bad: 824105293Sume if (sc->gif_psrc && sc->gif_pdst) 825105293Sume ifp->if_flags |= IFF_RUNNING; 826105293Sume else 827105293Sume ifp->if_flags &= ~IFF_RUNNING; 828105293Sume splx(s); 829105293Sume 830105293Sume return error; 831105293Sume} 832105293Sume 83379106Sbrooksvoid 834105293Sumegif_delete_tunnel(ifp) 835105293Sume struct ifnet *ifp; 83679106Sbrooks{ 837105293Sume struct gif_softc *sc = (struct gif_softc *)ifp; 838105293Sume int s; 83979106Sbrooks 840105293Sume s = splnet(); 841105293Sume 84279106Sbrooks if (sc->gif_psrc) { 84379106Sbrooks free((caddr_t)sc->gif_psrc, M_IFADDR); 84479106Sbrooks sc->gif_psrc = NULL; 84579106Sbrooks } 84679106Sbrooks if (sc->gif_pdst) { 84779106Sbrooks free((caddr_t)sc->gif_pdst, M_IFADDR); 84879106Sbrooks sc->gif_pdst = NULL; 84979106Sbrooks } 850105293Sume /* it is safe to detach from both */ 851105293Sume#ifdef INET 852105293Sume (void)in_gif_detach(sc); 853105293Sume#endif 854105293Sume#ifdef INET6 855105293Sume (void)in6_gif_detach(sc); 856105293Sume#endif 857105293Sume 858105293Sume if (sc->gif_psrc && sc->gif_pdst) 859105293Sume ifp->if_flags |= IFF_RUNNING; 860105293Sume else 861105293Sume ifp->if_flags &= ~IFF_RUNNING; 862105293Sume splx(s); 86379106Sbrooks} 864