if_gif.c revision 92081
162587Sitojun/* $FreeBSD: head/sys/net/if_gif.c 92081 2002-03-11 09:26:07Z mux $ */ 278064Sume/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 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" 3554263Sshin 3654263Sshin#include <sys/param.h> 3754263Sshin#include <sys/systm.h> 3854263Sshin#include <sys/kernel.h> 3954263Sshin#include <sys/malloc.h> 4054263Sshin#include <sys/mbuf.h> 4154263Sshin#include <sys/socket.h> 4254263Sshin#include <sys/sockio.h> 4354263Sshin#include <sys/errno.h> 4454263Sshin#include <sys/time.h> 4591270Sbrooks#include <sys/sysctl.h> 4654263Sshin#include <sys/syslog.h> 4762587Sitojun#include <sys/protosw.h> 4879106Sbrooks#include <sys/conf.h> 4954263Sshin#include <machine/cpu.h> 5054263Sshin 5154263Sshin#include <net/if.h> 5254263Sshin#include <net/if_types.h> 5354263Sshin#include <net/netisr.h> 5454263Sshin#include <net/route.h> 5554263Sshin#include <net/bpf.h> 5654263Sshin 5754263Sshin#include <netinet/in.h> 5854263Sshin#include <netinet/in_systm.h> 5978064Sume#include <netinet/ip.h> 6078064Sume#ifdef INET 6154263Sshin#include <netinet/in_var.h> 6254263Sshin#include <netinet/in_gif.h> 6379106Sbrooks#include <netinet/ip_var.h> 6454263Sshin#endif /* INET */ 6554263Sshin 6654263Sshin#ifdef INET6 6754263Sshin#ifndef INET 6854263Sshin#include <netinet/in.h> 6954263Sshin#endif 7054263Sshin#include <netinet6/in6_var.h> 7154263Sshin#include <netinet/ip6.h> 7254263Sshin#include <netinet6/ip6_var.h> 7354263Sshin#include <netinet6/in6_gif.h> 7462587Sitojun#include <netinet6/ip6protosw.h> 7554263Sshin#endif /* INET6 */ 7654263Sshin 7762587Sitojun#include <netinet/ip_encap.h> 7854263Sshin#include <net/if_gif.h> 7954263Sshin 8054263Sshin#include <net/net_osdep.h> 8154263Sshin 8279106Sbrooks#define GIFNAME "gif" 8362587Sitojun 8479106Sbrooksstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 8589065Smsmithstatic LIST_HEAD(, gif_softc) gif_softc_list; 8679106Sbrooks 8783998Sbrooksvoid (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 8883998Sbrooksvoid (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 8983998Sbrooksvoid (*ng_gif_attach_p)(struct ifnet *ifp); 9083998Sbrooksvoid (*ng_gif_detach_p)(struct ifnet *ifp); 9183998Sbrooks 9292081Smuxint gif_clone_create __P((struct if_clone *, int)); 9391647Sbrooksint gif_clone_destroy __P((struct ifnet *)); 9479106Sbrooks 9592081Smuxstruct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", 9692081Smux gif_clone_create, gif_clone_destroy, IF_MAXUNIT); 9779106Sbrooks 9879106Sbrooksstatic int gifmodevent __P((module_t, int, void *)); 9979106Sbrooksvoid gif_delete_tunnel __P((struct gif_softc *)); 10062587Sitojunstatic int gif_encapcheck __P((const struct mbuf *, int, int, void *)); 10179106Sbrooks 10262587Sitojun#ifdef INET 10379106Sbrooksextern struct domain inetdomain; 10482884Sjulianstruct protosw in_gif_protosw = 10579106Sbrooks{ SOCK_RAW, &inetdomain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, 10691327Sbrooks in_gif_input, (pr_output_t*)rip_output, 0, rip_ctloutput, 10779106Sbrooks 0, 10879106Sbrooks 0, 0, 0, 0, 10979106Sbrooks &rip_usrreqs 11079106Sbrooks}; 11162587Sitojun#endif 11262587Sitojun#ifdef INET6 11391327Sbrooksextern struct domain inet6domain; 11479106Sbrooksstruct ip6protosw in6_gif_protosw = 11579106Sbrooks{ SOCK_RAW, &inet6domain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, 11679106Sbrooks in6_gif_input, rip6_output, 0, rip6_ctloutput, 11779106Sbrooks 0, 11879106Sbrooks 0, 0, 0, 0, 11979106Sbrooks &rip6_usrreqs 12079106Sbrooks}; 12162587Sitojun#endif 12254263Sshin 12391270SbrooksSYSCTL_DECL(_net_link); 12491270SbrooksSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 12591270Sbrooks "Generic Tunnel Interface"); 12662587Sitojun#ifndef MAX_GIF_NEST 12762587Sitojun/* 12891270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels. 12962587Sitojun * Since, setting a large value to this macro with a careless configuration 13062587Sitojun * may introduce system crash, we don't allow any nestings by default. 13162587Sitojun * If you need to configure nested gif tunnels, you can define this macro 13262587Sitojun * in your kernel configuration file. However, if you do so, please be 13362587Sitojun * careful to configure the tunnels so that it won't make a loop. 13462587Sitojun */ 13562587Sitojun#define MAX_GIF_NEST 1 13662587Sitojun#endif 13762587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST; 13891270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 13991270Sbrooks &max_gif_nesting, 0, "Max nested tunnels"); 14062587Sitojun 14191270Sbrooks/* 14291270Sbrooks * By default, we disallow creation of multiple tunnels between the same 14391270Sbrooks * pair of addresses. Some applications require this functionality so 14491270Sbrooks * we allow control over this check here. 14591270Sbrooks */ 14691270Sbrooks#ifdef XBONEHACK 14791270Sbrooksstatic int parallel_tunnels = 1; 14891270Sbrooks#else 14991270Sbrooksstatic int parallel_tunnels = 0; 15091270Sbrooks#endif 15191270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 15291270Sbrooks ¶llel_tunnels, 0, "Allow parallel tunnels?"); 15391270Sbrooks 15479106Sbrooksint 15579106Sbrooksgif_clone_create(ifc, unit) 15679106Sbrooks struct if_clone *ifc; 15792081Smux int unit; 15854263Sshin{ 15978064Sume struct gif_softc *sc; 16054263Sshin 16179106Sbrooks sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK); 16279106Sbrooks bzero(sc, sizeof(struct gif_softc)); 16379106Sbrooks 16479106Sbrooks sc->gif_if.if_softc = sc; 16579106Sbrooks sc->gif_if.if_name = GIFNAME; 16692081Smux sc->gif_if.if_unit = unit; 16779106Sbrooks 16879106Sbrooks sc->encap_cookie4 = sc->encap_cookie6 = NULL; 16962587Sitojun#ifdef INET 17079106Sbrooks sc->encap_cookie4 = encap_attach_func(AF_INET, -1, 17179106Sbrooks gif_encapcheck, (struct protosw*)&in_gif_protosw, sc); 17279106Sbrooks if (sc->encap_cookie4 == NULL) { 17379106Sbrooks printf("%s: unable to attach encap4\n", if_name(&sc->gif_if)); 17479106Sbrooks free(sc, M_GIF); 17579106Sbrooks return (EIO); /* XXX */ 17679106Sbrooks } 17762587Sitojun#endif 17862587Sitojun#ifdef INET6 17979106Sbrooks sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, 18079106Sbrooks gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc); 18179106Sbrooks if (sc->encap_cookie6 == NULL) { 18279106Sbrooks if (sc->encap_cookie4) { 18379106Sbrooks encap_detach(sc->encap_cookie4); 18479106Sbrooks sc->encap_cookie4 = NULL; 18562587Sitojun } 18679106Sbrooks printf("%s: unable to attach encap6\n", if_name(&sc->gif_if)); 18779106Sbrooks free(sc, M_GIF); 18879106Sbrooks return (EIO); /* XXX */ 18979106Sbrooks } 19062587Sitojun#endif 19162587Sitojun 19279106Sbrooks sc->gif_if.if_mtu = GIF_MTU; 19379106Sbrooks sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 19478064Sume#if 0 19579106Sbrooks /* turn off ingress filter */ 19679106Sbrooks sc->gif_if.if_flags |= IFF_LINK2; 19778064Sume#endif 19879106Sbrooks sc->gif_if.if_ioctl = gif_ioctl; 19979106Sbrooks sc->gif_if.if_output = gif_output; 20079106Sbrooks sc->gif_if.if_type = IFT_GIF; 20179106Sbrooks sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 20279106Sbrooks if_attach(&sc->gif_if); 20379106Sbrooks bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 20483998Sbrooks if (ng_gif_attach_p != NULL) 20583998Sbrooks (*ng_gif_attach_p)(&sc->gif_if); 20683997Sbrooks LIST_INSERT_HEAD(&gif_softc_list, sc, gif_link); 20779106Sbrooks return (0); 20879106Sbrooks} 20979106Sbrooks 21091647Sbrooksint 21179106Sbrooksgif_clone_destroy(ifp) 21279106Sbrooks struct ifnet *ifp; 21379106Sbrooks{ 21479106Sbrooks int err; 21579106Sbrooks struct gif_softc *sc = ifp->if_softc; 21679106Sbrooks 21779106Sbrooks gif_delete_tunnel(sc); 21883997Sbrooks LIST_REMOVE(sc, gif_link); 21979106Sbrooks if (sc->encap_cookie4 != NULL) { 22079106Sbrooks err = encap_detach(sc->encap_cookie4); 22179106Sbrooks KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 22279106Sbrooks } 22379106Sbrooks if (sc->encap_cookie6 != NULL) { 22479106Sbrooks err = encap_detach(sc->encap_cookie6); 22579106Sbrooks KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 22679106Sbrooks } 22779106Sbrooks 22883998Sbrooks if (ng_gif_detach_p != NULL) 22983998Sbrooks (*ng_gif_detach_p)(ifp); 23079106Sbrooks bpfdetach(ifp); 23179106Sbrooks if_detach(ifp); 23279106Sbrooks 23379106Sbrooks free(sc, M_GIF); 23491647Sbrooks return (0); 23579106Sbrooks} 23679106Sbrooks 23779106Sbrooksstatic int 23879106Sbrooksgifmodevent(mod, type, data) 23979106Sbrooks module_t mod; 24079106Sbrooks int type; 24179106Sbrooks void *data; 24279106Sbrooks{ 24379106Sbrooks 24479106Sbrooks switch (type) { 24579106Sbrooks case MOD_LOAD: 24683997Sbrooks LIST_INIT(&gif_softc_list); 24779106Sbrooks if_clone_attach(&gif_cloner); 24879106Sbrooks 24979106Sbrooks#ifdef INET6 25079106Sbrooks ip6_gif_hlim = GIF_HLIM; 25162587Sitojun#endif 25279106Sbrooks 25379106Sbrooks break; 25479106Sbrooks case MOD_UNLOAD: 25579106Sbrooks if_clone_detach(&gif_cloner); 25679106Sbrooks 25783997Sbrooks while (!LIST_EMPTY(&gif_softc_list)) 25883997Sbrooks gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if); 25979106Sbrooks 26079106Sbrooks#ifdef INET6 26179106Sbrooks ip6_gif_hlim = 0; 26262587Sitojun#endif 26379106Sbrooks break; 26454263Sshin } 26579106Sbrooks return 0; 26654263Sshin} 26754263Sshin 26879106Sbrooksstatic moduledata_t gif_mod = { 26979106Sbrooks "if_gif", 27079106Sbrooks gifmodevent, 27179106Sbrooks 0 27279106Sbrooks}; 27354263Sshin 27479106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 27583997SbrooksMODULE_VERSION(if_gif, 1); 27679106Sbrooks 27762587Sitojunstatic int 27862587Sitojungif_encapcheck(m, off, proto, arg) 27962587Sitojun const struct mbuf *m; 28062587Sitojun int off; 28162587Sitojun int proto; 28262587Sitojun void *arg; 28362587Sitojun{ 28462587Sitojun struct ip ip; 28562587Sitojun struct gif_softc *sc; 28662587Sitojun 28762587Sitojun sc = (struct gif_softc *)arg; 28862587Sitojun if (sc == NULL) 28962587Sitojun return 0; 29062587Sitojun 29162587Sitojun if ((sc->gif_if.if_flags & IFF_UP) == 0) 29262587Sitojun return 0; 29362587Sitojun 29462587Sitojun /* no physical address */ 29562587Sitojun if (!sc->gif_psrc || !sc->gif_pdst) 29662587Sitojun return 0; 29762587Sitojun 29862587Sitojun switch (proto) { 29962587Sitojun#ifdef INET 30062587Sitojun case IPPROTO_IPV4: 30162587Sitojun break; 30262587Sitojun#endif 30362587Sitojun#ifdef INET6 30462587Sitojun case IPPROTO_IPV6: 30562587Sitojun break; 30662587Sitojun#endif 30762587Sitojun default: 30862587Sitojun return 0; 30962587Sitojun } 31062587Sitojun 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: 32362587Sitojun if (sc->gif_psrc->sa_family != AF_INET6 || 32462587Sitojun sc->gif_pdst->sa_family != AF_INET6) 32562587Sitojun return 0; 32662587Sitojun return gif_encapcheck6(m, off, proto, arg); 32762587Sitojun#endif 32862587Sitojun default: 32962587Sitojun return 0; 33062587Sitojun } 33162587Sitojun} 33262587Sitojun 33354263Sshinint 33454263Sshingif_output(ifp, m, dst, rt) 33554263Sshin struct ifnet *ifp; 33654263Sshin struct mbuf *m; 33754263Sshin struct sockaddr *dst; 33854263Sshin struct rtentry *rt; /* added in net2 */ 33954263Sshin{ 34078064Sume struct gif_softc *sc = (struct gif_softc*)ifp; 34154263Sshin int error = 0; 34254263Sshin static int called = 0; /* XXX: MUTEX */ 34354263Sshin 34454263Sshin /* 34554263Sshin * gif may cause infinite recursion calls when misconfigured. 34654263Sshin * We'll prevent this by introducing upper limit. 34754263Sshin * XXX: this mechanism may introduce another problem about 34854263Sshin * mutual exclusion of the variable CALLED, especially if we 34954263Sshin * use kernel thread. 35054263Sshin */ 35162587Sitojun if (++called > max_gif_nesting) { 35254263Sshin log(LOG_NOTICE, 35354263Sshin "gif_output: recursively called too many times(%d)\n", 35454263Sshin called); 35554263Sshin m_freem(m); 35654263Sshin error = EIO; /* is there better errno? */ 35754263Sshin goto end; 35854263Sshin } 35962587Sitojun 36054263Sshin m->m_flags &= ~(M_BCAST|M_MCAST); 36154263Sshin if (!(ifp->if_flags & IFF_UP) || 36254263Sshin sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 36354263Sshin m_freem(m); 36454263Sshin error = ENETDOWN; 36554263Sshin goto end; 36654263Sshin } 36754263Sshin 36854263Sshin if (ifp->if_bpf) { 36954263Sshin /* 37054263Sshin * We need to prepend the address family as 37154263Sshin * a four byte field. Cons up a dummy header 37254263Sshin * to pacify bpf. This is safe because bpf 37354263Sshin * will only read from the mbuf (i.e., it won't 37454263Sshin * try to free it or keep a pointer a to it). 37554263Sshin */ 37654263Sshin struct mbuf m0; 37778064Sume u_int32_t af = dst->sa_family; 37854263Sshin 37954263Sshin m0.m_next = m; 38054263Sshin m0.m_len = 4; 38154263Sshin m0.m_data = (char *)⁡ 38262587Sitojun 38354263Sshin bpf_mtap(ifp, &m0); 38454263Sshin } 38562587Sitojun ifp->if_opackets++; 38654263Sshin ifp->if_obytes += m->m_pkthdr.len; 38754263Sshin 38878064Sume /* inner AF-specific encapsulation */ 38978064Sume 39062587Sitojun /* XXX should we check if our outer source is legal? */ 39162587Sitojun 39278064Sume /* dispatch to output logic based on outer AF */ 39354263Sshin switch (sc->gif_psrc->sa_family) { 39454263Sshin#ifdef INET 39554263Sshin case AF_INET: 39654263Sshin error = in_gif_output(ifp, dst->sa_family, m, rt); 39754263Sshin break; 39854263Sshin#endif 39954263Sshin#ifdef INET6 40054263Sshin case AF_INET6: 40154263Sshin error = in6_gif_output(ifp, dst->sa_family, m, rt); 40254263Sshin break; 40354263Sshin#endif 40454263Sshin default: 40562587Sitojun m_freem(m); 40654263Sshin error = ENETDOWN; 40778064Sume goto end; 40854263Sshin } 40954263Sshin 41054263Sshin end: 41154263Sshin called = 0; /* reset recursion counter */ 41278064Sume if (error) 41378064Sume ifp->if_oerrors++; 41454263Sshin return error; 41554263Sshin} 41654263Sshin 41754263Sshinvoid 41854263Sshingif_input(m, af, gifp) 41954263Sshin struct mbuf *m; 42054263Sshin int af; 42154263Sshin struct ifnet *gifp; 42254263Sshin{ 42369152Sjlemon int isr; 42478064Sume struct ifqueue *ifq = 0; 42554263Sshin 42654263Sshin if (gifp == NULL) { 42754263Sshin /* just in case */ 42854263Sshin m_freem(m); 42954263Sshin return; 43054263Sshin } 43154263Sshin 43262587Sitojun m->m_pkthdr.rcvif = gifp; 43362587Sitojun 43454263Sshin if (gifp->if_bpf) { 43554263Sshin /* 43654263Sshin * We need to prepend the address family as 43754263Sshin * a four byte field. Cons up a dummy header 43854263Sshin * to pacify bpf. This is safe because bpf 43954263Sshin * will only read from the mbuf (i.e., it won't 44054263Sshin * try to free it or keep a pointer a to it). 44154263Sshin */ 44254263Sshin struct mbuf m0; 44378064Sume u_int32_t af1 = af; 44462587Sitojun 44554263Sshin m0.m_next = m; 44654263Sshin m0.m_len = 4; 44778064Sume m0.m_data = (char *)&af1; 44862587Sitojun 44954263Sshin bpf_mtap(gifp, &m0); 45054263Sshin } 45154263Sshin 45283998Sbrooks if (ng_gif_input_p != NULL) { 45383998Sbrooks (*ng_gif_input_p)(gifp, &m, af); 45483998Sbrooks if (m == NULL) 45583998Sbrooks return; 45683998Sbrooks } 45783998Sbrooks 45854263Sshin /* 45954263Sshin * Put the packet to the network layer input queue according to the 46054263Sshin * specified address family. 46154263Sshin * Note: older versions of gif_input directly called network layer 46254263Sshin * input functions, e.g. ip6_input, here. We changed the policy to 46354263Sshin * prevent too many recursive calls of such input functions, which 46454263Sshin * might cause kernel panic. But the change may introduce another 46554263Sshin * problem; if the input queue is full, packets are discarded. 46654263Sshin * We believed it rarely occurs and changed the policy. If we find 46754263Sshin * it occurs more times than we thought, we may change the policy 46854263Sshin * again. 46954263Sshin */ 47054263Sshin switch (af) { 47154263Sshin#ifdef INET 47254263Sshin case AF_INET: 47354263Sshin ifq = &ipintrq; 47454263Sshin isr = NETISR_IP; 47554263Sshin break; 47654263Sshin#endif 47754263Sshin#ifdef INET6 47854263Sshin case AF_INET6: 47954263Sshin ifq = &ip6intrq; 48054263Sshin isr = NETISR_IPV6; 48154263Sshin break; 48254263Sshin#endif 48354263Sshin default: 48483998Sbrooks if (ng_gif_input_orphan_p != NULL) 48583998Sbrooks (*ng_gif_input_orphan_p)(gifp, m, af); 48683998Sbrooks else 48783998Sbrooks m_freem(m); 48854263Sshin return; 48954263Sshin } 49054263Sshin 49169152Sjlemon gifp->if_ipackets++; 49269152Sjlemon gifp->if_ibytes += m->m_pkthdr.len; 49369152Sjlemon (void) IF_HANDOFF(ifq, m, NULL); 49454263Sshin /* we need schednetisr since the address family may change */ 49554263Sshin schednetisr(isr); 49654263Sshin 49754263Sshin return; 49854263Sshin} 49954263Sshin 50062587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 50154263Sshinint 50254263Sshingif_ioctl(ifp, cmd, data) 50354263Sshin struct ifnet *ifp; 50454263Sshin u_long cmd; 50554263Sshin caddr_t data; 50654263Sshin{ 50754263Sshin struct gif_softc *sc = (struct gif_softc*)ifp; 50854263Sshin struct ifreq *ifr = (struct ifreq*)data; 50954263Sshin int error = 0, size; 51062587Sitojun struct sockaddr *dst, *src; 51162587Sitojun struct sockaddr *sa; 51277658Syar int s; 51379106Sbrooks struct ifnet *ifp2; 51462587Sitojun struct gif_softc *sc2; 51562587Sitojun 51654263Sshin switch (cmd) { 51754263Sshin case SIOCSIFADDR: 51854263Sshin break; 51962587Sitojun 52054263Sshin case SIOCSIFDSTADDR: 52154263Sshin break; 52254263Sshin 52354263Sshin case SIOCADDMULTI: 52454263Sshin case SIOCDELMULTI: 52554263Sshin break; 52654263Sshin 52762587Sitojun#ifdef SIOCSIFMTU /* xxx */ 52854263Sshin case SIOCGIFMTU: 52954263Sshin break; 53062587Sitojun 53154263Sshin case SIOCSIFMTU: 53254263Sshin { 53354263Sshin u_long mtu; 53454263Sshin mtu = ifr->ifr_mtu; 53554263Sshin if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { 53654263Sshin return (EINVAL); 53754263Sshin } 53854263Sshin ifp->if_mtu = mtu; 53954263Sshin } 54054263Sshin break; 54162587Sitojun#endif /* SIOCSIFMTU */ 54254263Sshin 54354263Sshin case SIOCSIFPHYADDR: 54454263Sshin#ifdef INET6 54554263Sshin case SIOCSIFPHYADDR_IN6: 54654263Sshin#endif /* INET6 */ 54778064Sume case SIOCSLIFPHYADDR: 54862587Sitojun switch (cmd) { 54978064Sume#ifdef INET 55062587Sitojun case SIOCSIFPHYADDR: 55154263Sshin src = (struct sockaddr *) 55254263Sshin &(((struct in_aliasreq *)data)->ifra_addr); 55354263Sshin dst = (struct sockaddr *) 55454263Sshin &(((struct in_aliasreq *)data)->ifra_dstaddr); 55562587Sitojun break; 55678064Sume#endif 55762587Sitojun#ifdef INET6 55862587Sitojun case SIOCSIFPHYADDR_IN6: 55962587Sitojun src = (struct sockaddr *) 56062587Sitojun &(((struct in6_aliasreq *)data)->ifra_addr); 56162587Sitojun dst = (struct sockaddr *) 56262587Sitojun &(((struct in6_aliasreq *)data)->ifra_dstaddr); 56362587Sitojun break; 56462587Sitojun#endif 56578064Sume case SIOCSLIFPHYADDR: 56678064Sume src = (struct sockaddr *) 56778064Sume &(((struct if_laddrreq *)data)->addr); 56878064Sume dst = (struct sockaddr *) 56978064Sume &(((struct if_laddrreq *)data)->dstaddr); 57091327Sbrooks default: 57191327Sbrooks error = EADDRNOTAVAIL; 57291327Sbrooks goto bad; 57362587Sitojun } 57454263Sshin 57578064Sume /* sa_family must be equal */ 57678064Sume if (src->sa_family != dst->sa_family) 57778064Sume return EINVAL; 57878064Sume 57978064Sume /* validate sa_len */ 58078064Sume switch (src->sa_family) { 58178064Sume#ifdef INET 58278064Sume case AF_INET: 58378064Sume if (src->sa_len != sizeof(struct sockaddr_in)) 58478064Sume return EINVAL; 58578064Sume break; 58678064Sume#endif 58778064Sume#ifdef INET6 58878064Sume case AF_INET6: 58978064Sume if (src->sa_len != sizeof(struct sockaddr_in6)) 59078064Sume return EINVAL; 59178064Sume break; 59278064Sume#endif 59378064Sume default: 59478064Sume return EAFNOSUPPORT; 59578064Sume } 59678064Sume switch (dst->sa_family) { 59778064Sume#ifdef INET 59878064Sume case AF_INET: 59978064Sume if (dst->sa_len != sizeof(struct sockaddr_in)) 60078064Sume return EINVAL; 60178064Sume break; 60278064Sume#endif 60378064Sume#ifdef INET6 60478064Sume case AF_INET6: 60578064Sume if (dst->sa_len != sizeof(struct sockaddr_in6)) 60678064Sume return EINVAL; 60778064Sume break; 60878064Sume#endif 60978064Sume default: 61078064Sume return EAFNOSUPPORT; 61178064Sume } 61278064Sume 61378064Sume /* check sa_family looks sane for the cmd */ 61478064Sume switch (cmd) { 61578064Sume case SIOCSIFPHYADDR: 61678064Sume if (src->sa_family == AF_INET) 61778064Sume break; 61878064Sume return EAFNOSUPPORT; 61978064Sume#ifdef INET6 62078064Sume case SIOCSIFPHYADDR_IN6: 62178064Sume if (src->sa_family == AF_INET6) 62278064Sume break; 62378064Sume return EAFNOSUPPORT; 62478064Sume#endif /* INET6 */ 62578064Sume case SIOCSLIFPHYADDR: 62678064Sume /* checks done in the above */ 62778064Sume break; 62878064Sume } 62978064Sume 63079106Sbrooks TAILQ_FOREACH(ifp2, &ifnet, if_link) { 63179106Sbrooks if (strcmp(ifp2->if_name, GIFNAME) != 0) 63279106Sbrooks continue; 63379106Sbrooks sc2 = ifp2->if_softc; 63462587Sitojun if (sc2 == sc) 63562587Sitojun continue; 63662587Sitojun if (!sc2->gif_pdst || !sc2->gif_psrc) 63762587Sitojun continue; 63862587Sitojun if (sc2->gif_pdst->sa_family != dst->sa_family || 63962587Sitojun sc2->gif_pdst->sa_len != dst->sa_len || 64062587Sitojun sc2->gif_psrc->sa_family != src->sa_family || 64162587Sitojun sc2->gif_psrc->sa_len != src->sa_len) 64262587Sitojun continue; 64391270Sbrooks 64491270Sbrooks /* 64591270Sbrooks * Disallow parallel tunnels unless instructed 64691270Sbrooks * otherwise. 64791270Sbrooks */ 64891270Sbrooks if (!parallel_tunnels && 64991270Sbrooks bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 65062587Sitojun bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 65162587Sitojun error = EADDRNOTAVAIL; 65262587Sitojun goto bad; 65362587Sitojun } 65454263Sshin 65562587Sitojun /* can't configure multiple multi-dest interfaces */ 65662587Sitojun#define multidest(x) \ 65762587Sitojun (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY) 65857903Sshin#ifdef INET6 65962587Sitojun#define multidest6(x) \ 66062587Sitojun (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr)) 66157903Sshin#endif 66262587Sitojun if (dst->sa_family == AF_INET && 66362587Sitojun multidest(dst) && multidest(sc2->gif_pdst)) { 66462587Sitojun error = EADDRNOTAVAIL; 66562587Sitojun goto bad; 66662587Sitojun } 66762587Sitojun#ifdef INET6 66862587Sitojun if (dst->sa_family == AF_INET6 && 66962587Sitojun multidest6(dst) && multidest6(sc2->gif_pdst)) { 67062587Sitojun error = EADDRNOTAVAIL; 67162587Sitojun goto bad; 67262587Sitojun } 67362587Sitojun#endif 67462587Sitojun } 67557903Sshin 67662587Sitojun if (sc->gif_psrc) 67754263Sshin free((caddr_t)sc->gif_psrc, M_IFADDR); 67878064Sume sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 67978064Sume bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 68054263Sshin sc->gif_psrc = sa; 68154263Sshin 68262587Sitojun if (sc->gif_pdst) 68362587Sitojun free((caddr_t)sc->gif_pdst, M_IFADDR); 68478064Sume sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 68578064Sume bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 68654263Sshin sc->gif_pdst = sa; 68754263Sshin 68877658Syar ifp->if_flags |= IFF_RUNNING; 68977658Syar s = splimp(); 69077658Syar if_up(ifp); /* mark interface UP and send up RTM_IFINFO */ 69177658Syar splx(s); 69254263Sshin 69362587Sitojun error = 0; 69462587Sitojun break; 69562587Sitojun 69662587Sitojun#ifdef SIOCDIFPHYADDR 69762587Sitojun case SIOCDIFPHYADDR: 69862587Sitojun if (sc->gif_psrc) { 69962587Sitojun free((caddr_t)sc->gif_psrc, M_IFADDR); 70062587Sitojun sc->gif_psrc = NULL; 70157536Sshin } 70262587Sitojun if (sc->gif_pdst) { 70362587Sitojun free((caddr_t)sc->gif_pdst, M_IFADDR); 70462587Sitojun sc->gif_pdst = NULL; 70562587Sitojun } 70678064Sume /* change the IFF_{UP, RUNNING} flag as well? */ 70754263Sshin break; 70862587Sitojun#endif 70962587Sitojun 71054263Sshin case SIOCGIFPSRCADDR: 71154263Sshin#ifdef INET6 71254263Sshin case SIOCGIFPSRCADDR_IN6: 71354263Sshin#endif /* INET6 */ 71454263Sshin if (sc->gif_psrc == NULL) { 71554263Sshin error = EADDRNOTAVAIL; 71654263Sshin goto bad; 71754263Sshin } 71854263Sshin src = sc->gif_psrc; 71978064Sume switch (cmd) { 72054263Sshin#ifdef INET 72178064Sume case SIOCGIFPSRCADDR: 72254263Sshin dst = &ifr->ifr_addr; 72378064Sume size = sizeof(ifr->ifr_addr); 72454263Sshin break; 72554263Sshin#endif /* INET */ 72654263Sshin#ifdef INET6 72778064Sume case SIOCGIFPSRCADDR_IN6: 72854263Sshin dst = (struct sockaddr *) 72954263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 73078064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 73154263Sshin break; 73254263Sshin#endif /* INET6 */ 73354263Sshin default: 73454263Sshin error = EADDRNOTAVAIL; 73554263Sshin goto bad; 73654263Sshin } 73778064Sume if (src->sa_len > size) 73878064Sume return EINVAL; 73978064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 74054263Sshin break; 74162587Sitojun 74254263Sshin case SIOCGIFPDSTADDR: 74354263Sshin#ifdef INET6 74454263Sshin case SIOCGIFPDSTADDR_IN6: 74554263Sshin#endif /* INET6 */ 74654263Sshin if (sc->gif_pdst == NULL) { 74754263Sshin error = EADDRNOTAVAIL; 74854263Sshin goto bad; 74954263Sshin } 75054263Sshin src = sc->gif_pdst; 75178064Sume switch (cmd) { 75254263Sshin#ifdef INET 75378064Sume case SIOCGIFPDSTADDR: 75454263Sshin dst = &ifr->ifr_addr; 75578064Sume size = sizeof(ifr->ifr_addr); 75654263Sshin break; 75754263Sshin#endif /* INET */ 75854263Sshin#ifdef INET6 75978064Sume case SIOCGIFPDSTADDR_IN6: 76054263Sshin dst = (struct sockaddr *) 76154263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 76278064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 76354263Sshin break; 76454263Sshin#endif /* INET6 */ 76554263Sshin default: 76654263Sshin error = EADDRNOTAVAIL; 76754263Sshin goto bad; 76854263Sshin } 76978064Sume if (src->sa_len > size) 77078064Sume return EINVAL; 77178064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 77254263Sshin break; 77354263Sshin 77478064Sume case SIOCGLIFPHYADDR: 77578064Sume if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 77678064Sume error = EADDRNOTAVAIL; 77778064Sume goto bad; 77878064Sume } 77978064Sume 78078064Sume /* copy src */ 78178064Sume src = sc->gif_psrc; 78278064Sume dst = (struct sockaddr *) 78378064Sume &(((struct if_laddrreq *)data)->addr); 78478064Sume size = sizeof(((struct if_laddrreq *)data)->addr); 78578064Sume if (src->sa_len > size) 78678064Sume return EINVAL; 78778064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 78878064Sume 78978064Sume /* copy dst */ 79078064Sume src = sc->gif_pdst; 79178064Sume dst = (struct sockaddr *) 79278064Sume &(((struct if_laddrreq *)data)->dstaddr); 79378064Sume size = sizeof(((struct if_laddrreq *)data)->dstaddr); 79478064Sume if (src->sa_len > size) 79578064Sume return EINVAL; 79678064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 79778064Sume break; 79878064Sume 79954263Sshin case SIOCSIFFLAGS: 80062587Sitojun /* if_ioctl() takes care of it */ 80154263Sshin break; 80254263Sshin 80354263Sshin default: 80454263Sshin error = EINVAL; 80554263Sshin break; 80654263Sshin } 80754263Sshin bad: 80854263Sshin return error; 80954263Sshin} 81079106Sbrooks 81179106Sbrooksvoid 81279106Sbrooksgif_delete_tunnel(sc) 81379106Sbrooks struct gif_softc *sc; 81479106Sbrooks{ 81579106Sbrooks /* XXX: NetBSD protects this function with splsoftnet() */ 81679106Sbrooks 81779106Sbrooks if (sc->gif_psrc) { 81879106Sbrooks free((caddr_t)sc->gif_psrc, M_IFADDR); 81979106Sbrooks sc->gif_psrc = NULL; 82079106Sbrooks } 82179106Sbrooks if (sc->gif_pdst) { 82279106Sbrooks free((caddr_t)sc->gif_pdst, M_IFADDR); 82379106Sbrooks sc->gif_pdst = NULL; 82479106Sbrooks } 82579106Sbrooks /* change the IFF_UP flag as well? */ 82679106Sbrooks} 827