1139823Simp/*- 254263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 354263Sshin * All rights reserved. 454263Sshin * 554263Sshin * Redistribution and use in source and binary forms, with or without 654263Sshin * modification, are permitted provided that the following conditions 754263Sshin * are met: 854263Sshin * 1. Redistributions of source code must retain the above copyright 954263Sshin * notice, this list of conditions and the following disclaimer. 1054263Sshin * 2. Redistributions in binary form must reproduce the above copyright 1154263Sshin * notice, this list of conditions and the following disclaimer in the 1254263Sshin * documentation and/or other materials provided with the distribution. 1354263Sshin * 3. Neither the name of the project nor the names of its contributors 1454263Sshin * may be used to endorse or promote products derived from this software 1554263Sshin * without specific prior written permission. 1654263Sshin * 1754263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1854263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1954263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2054263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2154263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2254263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2354263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2454263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2554263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2654263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2754263Sshin * SUCH DAMAGE. 28273087Sae * 29273087Sae * $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ 3054263Sshin */ 3154263Sshin 32273087Sae#include <sys/cdefs.h> 33273087Sae__FBSDID("$FreeBSD: stable/11/sys/net/if_gif.c 338937 2018-09-25 23:33:30Z jpaetzel $"); 34273087Sae 3554263Sshin#include "opt_inet.h" 3654263Sshin#include "opt_inet6.h" 3754263Sshin 3854263Sshin#include <sys/param.h> 3954263Sshin#include <sys/systm.h> 40219206Sbz#include <sys/jail.h> 4154263Sshin#include <sys/kernel.h> 42273087Sae#include <sys/lock.h> 4354263Sshin#include <sys/malloc.h> 4454263Sshin#include <sys/mbuf.h> 45129880Sphk#include <sys/module.h> 46273087Sae#include <sys/rmlock.h> 4754263Sshin#include <sys/socket.h> 4854263Sshin#include <sys/sockio.h> 49273087Sae#include <sys/sx.h> 5054263Sshin#include <sys/errno.h> 5154263Sshin#include <sys/time.h> 5291270Sbrooks#include <sys/sysctl.h> 5354263Sshin#include <sys/syslog.h> 54193664Shrs#include <sys/priv.h> 55178888Sjulian#include <sys/proc.h> 5662587Sitojun#include <sys/protosw.h> 5779106Sbrooks#include <sys/conf.h> 5854263Sshin#include <machine/cpu.h> 5954263Sshin 6054263Sshin#include <net/if.h> 61257176Sglebius#include <net/if_var.h> 62130933Sbrooks#include <net/if_clone.h> 6354263Sshin#include <net/if_types.h> 6454263Sshin#include <net/netisr.h> 6554263Sshin#include <net/route.h> 6654263Sshin#include <net/bpf.h> 67196019Srwatson#include <net/vnet.h> 6854263Sshin 6954263Sshin#include <netinet/in.h> 7054263Sshin#include <netinet/in_systm.h> 7178064Sume#include <netinet/ip.h> 72273087Sae#include <netinet/ip_ecn.h> 7378064Sume#ifdef INET 7454263Sshin#include <netinet/in_var.h> 7579106Sbrooks#include <netinet/ip_var.h> 7654263Sshin#endif /* INET */ 7754263Sshin 7854263Sshin#ifdef INET6 7954263Sshin#ifndef INET 8054263Sshin#include <netinet/in.h> 8154263Sshin#endif 8254263Sshin#include <netinet6/in6_var.h> 8354263Sshin#include <netinet/ip6.h> 84273087Sae#include <netinet6/ip6_ecn.h> 8554263Sshin#include <netinet6/ip6_var.h> 86148385Sume#include <netinet6/scope6_var.h> 8762587Sitojun#include <netinet6/ip6protosw.h> 8854263Sshin#endif /* INET6 */ 8954263Sshin 9062587Sitojun#include <netinet/ip_encap.h> 91153621Sthompsa#include <net/ethernet.h> 92153621Sthompsa#include <net/if_bridgevar.h> 9354263Sshin#include <net/if_gif.h> 9454263Sshin 95163606Srwatson#include <security/mac/mac_framework.h> 96163606Srwatson 97241610Sglebiusstatic const char gifname[] = "gif"; 9862587Sitojun 99127305Srwatson/* 100271917Shrs * gif_mtx protects a per-vnet gif_softc_list. 101127305Srwatson */ 102271917Shrsstatic VNET_DEFINE(struct mtx, gif_mtx); 103271917Shrs#define V_gif_mtx VNET(gif_mtx) 10479106Sbrooksstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 105215701Sdimstatic VNET_DEFINE(LIST_HEAD(, gif_softc), gif_softc_list); 106195727Srwatson#define V_gif_softc_list VNET(gif_softc_list) 107273087Saestatic struct sx gif_ioctl_sx; 108273087SaeSX_SYSINIT(gif_ioctl_sx, &gif_ioctl_sx, "gif_ioctl"); 109195699Srwatson 110271917Shrs#define GIF_LIST_LOCK_INIT(x) mtx_init(&V_gif_mtx, "gif_mtx", \ 111271917Shrs NULL, MTX_DEF) 112271917Shrs#define GIF_LIST_LOCK_DESTROY(x) mtx_destroy(&V_gif_mtx) 113271917Shrs#define GIF_LIST_LOCK(x) mtx_lock(&V_gif_mtx) 114271917Shrs#define GIF_LIST_UNLOCK(x) mtx_unlock(&V_gif_mtx) 115271917Shrs 11683998Sbrooksvoid (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 11783998Sbrooksvoid (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 11883998Sbrooksvoid (*ng_gif_attach_p)(struct ifnet *ifp); 11983998Sbrooksvoid (*ng_gif_detach_p)(struct ifnet *ifp); 12083998Sbrooks 121276907Saestatic int gif_check_nesting(struct ifnet *, struct mbuf *); 122273087Saestatic int gif_set_tunnel(struct ifnet *, struct sockaddr *, 123273087Sae struct sockaddr *); 124273087Saestatic void gif_delete_tunnel(struct ifnet *); 125273087Saestatic int gif_ioctl(struct ifnet *, u_long, caddr_t); 126273087Saestatic int gif_transmit(struct ifnet *, struct mbuf *); 127273087Saestatic void gif_qflush(struct ifnet *); 128160195Ssamstatic int gif_clone_create(struct if_clone *, int, caddr_t); 129128209Sbrooksstatic void gif_clone_destroy(struct ifnet *); 130271917Shrsstatic VNET_DEFINE(struct if_clone *, gif_cloner); 131271917Shrs#define V_gif_cloner VNET(gif_cloner) 13279106Sbrooks 13392725Salfredstatic int gifmodevent(module_t, int, void *); 13479106Sbrooks 13591270SbrooksSYSCTL_DECL(_net_link); 136227309Sedstatic SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 13791270Sbrooks "Generic Tunnel Interface"); 13862587Sitojun#ifndef MAX_GIF_NEST 13962587Sitojun/* 14091270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels. 14162587Sitojun * Since, setting a large value to this macro with a careless configuration 14262587Sitojun * may introduce system crash, we don't allow any nestings by default. 14362587Sitojun * If you need to configure nested gif tunnels, you can define this macro 14495023Ssuz * in your kernel configuration file. However, if you do so, please be 14562587Sitojun * careful to configure the tunnels so that it won't make a loop. 14662587Sitojun */ 14762587Sitojun#define MAX_GIF_NEST 1 14862587Sitojun#endif 149215701Sdimstatic VNET_DEFINE(int, max_gif_nesting) = MAX_GIF_NEST; 150195837Srwatson#define V_max_gif_nesting VNET(max_gif_nesting) 151274225SglebiusSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_VNET | CTLFLAG_RW, 152195699Srwatson &VNET_NAME(max_gif_nesting), 0, "Max nested tunnels"); 15362587Sitojun 15491270Sbrooks/* 15591270Sbrooks * By default, we disallow creation of multiple tunnels between the same 15691270Sbrooks * pair of addresses. Some applications require this functionality so 15791270Sbrooks * we allow control over this check here. 15891270Sbrooks */ 159195837Srwatson#ifdef XBONEHACK 160215701Sdimstatic VNET_DEFINE(int, parallel_tunnels) = 1; 161195837Srwatson#else 162215701Sdimstatic VNET_DEFINE(int, parallel_tunnels) = 0; 163195837Srwatson#endif 164195837Srwatson#define V_parallel_tunnels VNET(parallel_tunnels) 165274225SglebiusSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, 166274225Sglebius CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(parallel_tunnels), 0, 167274225Sglebius "Allow parallel tunnels?"); 16891270Sbrooks 169128209Sbrooksstatic int 170258167Saegif_clone_create(struct if_clone *ifc, int unit, caddr_t params) 17154263Sshin{ 17278064Sume struct gif_softc *sc; 17354263Sshin 174131672Sbms sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO); 175178888Sjulian sc->gif_fibnum = curthread->td_proc->p_fibnum; 176147256Sbrooks GIF2IFP(sc) = if_alloc(IFT_GIF); 177155037Sglebius GIF_LOCK_INIT(sc); 178147256Sbrooks GIF2IFP(sc)->if_softc = sc; 179241610Sglebius if_initname(GIF2IFP(sc), gifname, unit); 18079106Sbrooks 181147256Sbrooks GIF2IFP(sc)->if_addrlen = 0; 182147256Sbrooks GIF2IFP(sc)->if_mtu = GIF_MTU; 183147256Sbrooks GIF2IFP(sc)->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 18478064Sume#if 0 18579106Sbrooks /* turn off ingress filter */ 186147256Sbrooks GIF2IFP(sc)->if_flags |= IFF_LINK2; 18778064Sume#endif 188147256Sbrooks GIF2IFP(sc)->if_ioctl = gif_ioctl; 189273087Sae GIF2IFP(sc)->if_transmit = gif_transmit; 190273087Sae GIF2IFP(sc)->if_qflush = gif_qflush; 191147256Sbrooks GIF2IFP(sc)->if_output = gif_output; 192288575Shrs GIF2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE; 193288575Shrs GIF2IFP(sc)->if_capenable |= IFCAP_LINKSTATE; 194147256Sbrooks if_attach(GIF2IFP(sc)); 195147611Sdwmalone bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 19683998Sbrooks if (ng_gif_attach_p != NULL) 197147256Sbrooks (*ng_gif_attach_p)(GIF2IFP(sc)); 198155037Sglebius 199271917Shrs GIF_LIST_LOCK(); 200181803Sbz LIST_INSERT_HEAD(&V_gif_softc_list, sc, gif_list); 201271917Shrs GIF_LIST_UNLOCK(); 202155037Sglebius return (0); 20379106Sbrooks} 20479106Sbrooks 205127305Srwatsonstatic void 206258167Saegif_clone_destroy(struct ifnet *ifp) 20779106Sbrooks{ 208273087Sae struct gif_softc *sc; 20979106Sbrooks 210273087Sae sx_xlock(&gif_ioctl_sx); 211273087Sae sc = ifp->if_softc; 212273087Sae gif_delete_tunnel(ifp); 213271917Shrs GIF_LIST_LOCK(); 214151266Sthompsa LIST_REMOVE(sc, gif_list); 215271917Shrs GIF_LIST_UNLOCK(); 21683998Sbrooks if (ng_gif_detach_p != NULL) 21783998Sbrooks (*ng_gif_detach_p)(ifp); 21879106Sbrooks bpfdetach(ifp); 21979106Sbrooks if_detach(ifp); 220273087Sae ifp->if_softc = NULL; 221273087Sae sx_xunlock(&gif_ioctl_sx); 222273087Sae 223147256Sbrooks if_free(ifp); 224155037Sglebius GIF_LOCK_DESTROY(sc); 22579106Sbrooks free(sc, M_GIF); 22679106Sbrooks} 22779106Sbrooks 228195837Srwatsonstatic void 229195837Srwatsonvnet_gif_init(const void *unused __unused) 230190787Szec{ 231190787Szec 232190787Szec LIST_INIT(&V_gif_softc_list); 233271917Shrs GIF_LIST_LOCK_INIT(); 234271917Shrs V_gif_cloner = if_clone_simple(gifname, gif_clone_create, 235271917Shrs gif_clone_destroy, 0); 236190787Szec} 237271917ShrsVNET_SYSINIT(vnet_gif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 238271917Shrs vnet_gif_init, NULL); 239190787Szec 240271917Shrsstatic void 241271917Shrsvnet_gif_uninit(const void *unused __unused) 242271917Shrs{ 243271917Shrs 244271917Shrs if_clone_detach(V_gif_cloner); 245271917Shrs GIF_LIST_LOCK_DESTROY(); 246271917Shrs} 247271917ShrsVNET_SYSUNINIT(vnet_gif_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 248271917Shrs vnet_gif_uninit, NULL); 249271917Shrs 250190787Szecstatic int 251258167Saegifmodevent(module_t mod, int type, void *data) 25279106Sbrooks{ 25379106Sbrooks 25479106Sbrooks switch (type) { 25579106Sbrooks case MOD_LOAD: 25679106Sbrooks case MOD_UNLOAD: 25779106Sbrooks break; 258132199Sphk default: 259271917Shrs return (EOPNOTSUPP); 26054263Sshin } 261271917Shrs return (0); 26254263Sshin} 26354263Sshin 26479106Sbrooksstatic moduledata_t gif_mod = { 26579106Sbrooks "if_gif", 26679106Sbrooks gifmodevent, 267241394Skevlo 0 26879106Sbrooks}; 26954263Sshin 27079106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 27183997SbrooksMODULE_VERSION(if_gif, 1); 27279106Sbrooks 273105293Sumeint 274258167Saegif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 27562587Sitojun{ 276273087Sae GIF_RLOCK_TRACKER; 277286013Sae const struct ip *ip; 27862587Sitojun struct gif_softc *sc; 279273087Sae int ret; 28062587Sitojun 28162587Sitojun sc = (struct gif_softc *)arg; 282273087Sae if (sc == NULL || (GIF2IFP(sc)->if_flags & IFF_UP) == 0) 283273087Sae return (0); 28462587Sitojun 285273087Sae ret = 0; 286273087Sae GIF_RLOCK(sc); 28762587Sitojun 28862587Sitojun /* no physical address */ 289273087Sae if (sc->gif_family == 0) 290273087Sae goto done; 29162587Sitojun 29262587Sitojun switch (proto) { 29362587Sitojun#ifdef INET 29462587Sitojun case IPPROTO_IPV4: 29562587Sitojun#endif 29662587Sitojun#ifdef INET6 29762587Sitojun case IPPROTO_IPV6: 29862587Sitojun#endif 299153621Sthompsa case IPPROTO_ETHERIP: 300153621Sthompsa break; 30162587Sitojun default: 302273087Sae goto done; 30362587Sitojun } 30462587Sitojun 305105339Sume /* Bail on short packets */ 306286013Sae M_ASSERTPKTHDR(m); 307273087Sae if (m->m_pkthdr.len < sizeof(struct ip)) 308273087Sae goto done; 309105339Sume 310286013Sae ip = mtod(m, const struct ip *); 311286013Sae switch (ip->ip_v) { 31262587Sitojun#ifdef INET 31362587Sitojun case 4: 314273087Sae if (sc->gif_family != AF_INET) 315273087Sae goto done; 316273087Sae ret = in_gif_encapcheck(m, off, proto, arg); 317273087Sae break; 31862587Sitojun#endif 31962587Sitojun#ifdef INET6 32062587Sitojun case 6: 321105293Sume if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 322273087Sae goto done; 323273087Sae if (sc->gif_family != AF_INET6) 324273087Sae goto done; 325273087Sae ret = in6_gif_encapcheck(m, off, proto, arg); 326273087Sae break; 32762587Sitojun#endif 32862587Sitojun } 329273087Saedone: 330273087Sae GIF_RUNLOCK(sc); 331273087Sae return (ret); 33262587Sitojun} 333273087Sae 334273087Saestatic int 335273087Saegif_transmit(struct ifnet *ifp, struct mbuf *m) 336273087Sae{ 337273087Sae struct gif_softc *sc; 338273087Sae struct etherip_header *eth; 339236951Srrs#ifdef INET 340273087Sae struct ip *ip; 341236951Srrs#endif 342236951Srrs#ifdef INET6 343273087Sae struct ip6_hdr *ip6; 344273087Sae uint32_t t; 345236951Srrs#endif 346236951Srrs uint32_t af; 347273087Sae uint8_t proto, ecn; 348273087Sae int error; 349153621Sthompsa 350276907Sae#ifdef MAC 351276907Sae error = mac_ifnet_check_transmit(ifp, m); 352276907Sae if (error) { 353276907Sae m_freem(m); 354276907Sae goto err; 355276907Sae } 356276907Sae#endif 357273087Sae error = ENETDOWN; 358153621Sthompsa sc = ifp->if_softc; 359276907Sae if ((ifp->if_flags & IFF_MONITOR) != 0 || 360276907Sae (ifp->if_flags & IFF_UP) == 0 || 361276907Sae sc->gif_family == 0 || 362276907Sae (error = gif_check_nesting(ifp, m)) != 0) { 363273087Sae m_freem(m); 364273087Sae goto err; 365273087Sae } 366273087Sae /* Now pull back the af that we stashed in the csum_data. */ 367276907Sae if (ifp->if_bridge) 368276907Sae af = AF_LINK; 369276907Sae else 370276907Sae af = m->m_pkthdr.csum_data; 371276907Sae m->m_flags &= ~(M_BCAST|M_MCAST); 372276907Sae M_SETFIB(m, sc->gif_fibnum); 373273087Sae BPF_MTAP2(ifp, &af, sizeof(af), m); 374273087Sae if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 375273087Sae if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); 376273087Sae /* inner AF-specific encapsulation */ 377273087Sae ecn = 0; 378273087Sae switch (af) { 379236951Srrs#ifdef INET 380273087Sae case AF_INET: 381273087Sae proto = IPPROTO_IPV4; 382273087Sae if (m->m_len < sizeof(struct ip)) 383273087Sae m = m_pullup(m, sizeof(struct ip)); 384273087Sae if (m == NULL) { 385273087Sae error = ENOBUFS; 386273087Sae goto err; 387273087Sae } 388273087Sae ip = mtod(m, struct ip *); 389273087Sae ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: 390273087Sae ECN_NOCARE, &ecn, &ip->ip_tos); 391273087Sae break; 392236951Srrs#endif 393236951Srrs#ifdef INET6 394273087Sae case AF_INET6: 395273087Sae proto = IPPROTO_IPV6; 396273087Sae if (m->m_len < sizeof(struct ip6_hdr)) 397273087Sae m = m_pullup(m, sizeof(struct ip6_hdr)); 398273087Sae if (m == NULL) { 399273087Sae error = ENOBUFS; 400273087Sae goto err; 401273087Sae } 402273087Sae t = 0; 403273087Sae ip6 = mtod(m, struct ip6_hdr *); 404273087Sae ip6_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: 405273087Sae ECN_NOCARE, &t, &ip6->ip6_flow); 406273087Sae ecn = (ntohl(t) >> 20) & 0xff; 407273087Sae break; 408236951Srrs#endif 409273087Sae case AF_LINK: 410273087Sae proto = IPPROTO_ETHERIP; 411273087Sae M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT); 412273087Sae if (m == NULL) { 413273087Sae error = ENOBUFS; 414273087Sae goto err; 415273087Sae } 416273087Sae eth = mtod(m, struct etherip_header *); 417273087Sae eth->eip_resvh = 0; 418287607Shrs eth->eip_ver = ETHERIP_VERSION; 419287607Shrs eth->eip_resvl = 0; 420273087Sae break; 421273087Sae default: 422273087Sae error = EAFNOSUPPORT; 423273087Sae m_freem(m); 424273087Sae goto err; 425273087Sae } 426273087Sae /* XXX should we check if our outer source is legal? */ 427273087Sae /* dispatch to output logic based on outer AF */ 428273087Sae switch (sc->gif_family) { 429236951Srrs#ifdef INET 430273087Sae case AF_INET: 431273087Sae error = in_gif_output(ifp, m, proto, ecn); 432273087Sae break; 433236951Srrs#endif 434236951Srrs#ifdef INET6 435273087Sae case AF_INET6: 436273087Sae error = in6_gif_output(ifp, m, proto, ecn); 437273087Sae break; 438236951Srrs#endif 439273087Sae default: 440273087Sae m_freem(m); 441153621Sthompsa } 442273087Saeerr: 443273087Sae if (error) 444273087Sae if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 445273087Sae return (error); 446153621Sthompsa} 447153621Sthompsa 448273087Saestatic void 449273087Saegif_qflush(struct ifnet *ifp __unused) 450273087Sae{ 451273087Sae 452273087Sae} 453273087Sae 454276901Sae#define MTAG_GIF 1080679712 455276901Saestatic int 456276901Saegif_check_nesting(struct ifnet *ifp, struct mbuf *m) 457276901Sae{ 458276901Sae struct m_tag *mtag; 459276901Sae int count; 460276901Sae 461276901Sae /* 462276901Sae * gif may cause infinite recursion calls when misconfigured. 463276901Sae * We'll prevent this by detecting loops. 464276901Sae * 465276901Sae * High nesting level may cause stack exhaustion. 466276901Sae * We'll prevent this by introducing upper limit. 467276901Sae */ 468276901Sae count = 1; 469276901Sae mtag = NULL; 470276901Sae while ((mtag = m_tag_locate(m, MTAG_GIF, 0, mtag)) != NULL) { 471276901Sae if (*(struct ifnet **)(mtag + 1) == ifp) { 472276903Sae log(LOG_NOTICE, "%s: loop detected\n", if_name(ifp)); 473276901Sae return (EIO); 474276901Sae } 475276901Sae count++; 476276901Sae } 477276901Sae if (count > V_max_gif_nesting) { 478276901Sae log(LOG_NOTICE, 479276901Sae "%s: if_output recursively called too many times(%d)\n", 480276901Sae if_name(ifp), count); 481276901Sae return (EIO); 482276901Sae } 483276901Sae mtag = m_tag_alloc(MTAG_GIF, 0, sizeof(struct ifnet *), M_NOWAIT); 484276901Sae if (mtag == NULL) 485276901Sae return (ENOMEM); 486276901Sae *(struct ifnet **)(mtag + 1) = ifp; 487276901Sae m_tag_prepend(m, mtag); 488276901Sae return (0); 489276901Sae} 490276901Sae 49154263Sshinint 492249925Sglebiusgif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 493249925Sglebius struct route *ro) 49454263Sshin{ 495273087Sae uint32_t af; 496101182Srwatson 497249925Sglebius if (dst->sa_family == AF_UNSPEC) 498236951Srrs bcopy(dst->sa_data, &af, sizeof(af)); 499249925Sglebius else 500249925Sglebius af = dst->sa_family; 501273087Sae /* 502273087Sae * Now save the af in the inbound pkt csum data, this is a cheat since 503273087Sae * we are using the inbound csum_data field to carry the af over to 504273087Sae * the gif_transmit() routine, avoiding using yet another mtag. 505236951Srrs */ 506236955Srrs m->m_pkthdr.csum_data = af; 507273087Sae return (ifp->if_transmit(ifp, m)); 50854263Sshin} 50954263Sshin 51054263Sshinvoid 511273087Saegif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn) 51254263Sshin{ 513273087Sae struct etherip_header *eip; 514273087Sae#ifdef INET 515273087Sae struct ip *ip; 516273087Sae#endif 517273087Sae#ifdef INET6 518273087Sae struct ip6_hdr *ip6; 519273087Sae uint32_t t; 520273087Sae#endif 521198357Sbrueffer struct gif_softc *sc; 522176879Sthompsa struct ether_header *eh; 523176879Sthompsa struct ifnet *oldifp; 524273087Sae int isr, n, af; 52554263Sshin 526105338Sume if (ifp == NULL) { 52754263Sshin /* just in case */ 52854263Sshin m_freem(m); 52954263Sshin return; 53054263Sshin } 531198357Sbrueffer sc = ifp->if_softc; 532105338Sume m->m_pkthdr.rcvif = ifp; 533272770Sae m_clrprotoflags(m); 534273087Sae switch (proto) { 535273087Sae#ifdef INET 536273087Sae case IPPROTO_IPV4: 537273087Sae af = AF_INET; 538273087Sae if (m->m_len < sizeof(struct ip)) 539273087Sae m = m_pullup(m, sizeof(struct ip)); 540273087Sae if (m == NULL) 541273087Sae goto drop; 542273087Sae ip = mtod(m, struct ip *); 543273087Sae if (ip_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: 544273087Sae ECN_NOCARE, &ecn, &ip->ip_tos) == 0) { 545273087Sae m_freem(m); 546273087Sae goto drop; 547273087Sae } 548273087Sae break; 549273087Sae#endif 550273087Sae#ifdef INET6 551273087Sae case IPPROTO_IPV6: 552273087Sae af = AF_INET6; 553273087Sae if (m->m_len < sizeof(struct ip6_hdr)) 554273087Sae m = m_pullup(m, sizeof(struct ip6_hdr)); 555273087Sae if (m == NULL) 556273087Sae goto drop; 557273087Sae t = htonl((uint32_t)ecn << 20); 558273087Sae ip6 = mtod(m, struct ip6_hdr *); 559273087Sae if (ip6_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: 560273087Sae ECN_NOCARE, &t, &ip6->ip6_flow) == 0) { 561273087Sae m_freem(m); 562273087Sae goto drop; 563273087Sae } 564273087Sae break; 565273087Sae#endif 566273087Sae case IPPROTO_ETHERIP: 567273087Sae af = AF_LINK; 568273087Sae break; 569273087Sae default: 570273087Sae m_freem(m); 571273087Sae goto drop; 572273087Sae } 573101182Srwatson 574101182Srwatson#ifdef MAC 575172930Srwatson mac_ifnet_create_mbuf(ifp, m); 576101182Srwatson#endif 577101182Srwatson 578159180Scsjp if (bpf_peers_present(ifp->if_bpf)) { 579273087Sae uint32_t af1 = af; 580123922Ssam bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 58154263Sshin } 58254263Sshin 583253261Shrs if ((ifp->if_flags & IFF_MONITOR) != 0) { 584271867Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 585271867Sglebius if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 586253261Shrs m_freem(m); 587253261Shrs return; 588253261Shrs } 589253261Shrs 59083998Sbrooks if (ng_gif_input_p != NULL) { 591105338Sume (*ng_gif_input_p)(ifp, &m, af); 59283998Sbrooks if (m == NULL) 593273087Sae goto drop; 59483998Sbrooks } 59583998Sbrooks 59654263Sshin /* 59754263Sshin * Put the packet to the network layer input queue according to the 59854263Sshin * specified address family. 59954263Sshin * Note: older versions of gif_input directly called network layer 60095023Ssuz * input functions, e.g. ip6_input, here. We changed the policy to 60154263Sshin * prevent too many recursive calls of such input functions, which 60295023Ssuz * might cause kernel panic. But the change may introduce another 60354263Sshin * problem; if the input queue is full, packets are discarded. 60495023Ssuz * The kernel stack overflow really happened, and we believed 60595023Ssuz * queue-full rarely occurs, so we changed the policy. 60654263Sshin */ 60754263Sshin switch (af) { 60854263Sshin#ifdef INET 60954263Sshin case AF_INET: 61054263Sshin isr = NETISR_IP; 61154263Sshin break; 61254263Sshin#endif 61354263Sshin#ifdef INET6 61454263Sshin case AF_INET6: 61554263Sshin isr = NETISR_IPV6; 61654263Sshin break; 61754263Sshin#endif 618153621Sthompsa case AF_LINK: 619153621Sthompsa n = sizeof(struct etherip_header) + sizeof(struct ether_header); 620273087Sae if (n > m->m_len) 621153621Sthompsa m = m_pullup(m, n); 622273087Sae if (m == NULL) 623273087Sae goto drop; 624153621Sthompsa eip = mtod(m, struct etherip_header *); 625273087Sae if (eip->eip_ver != ETHERIP_VERSION) { 626287607Shrs /* discard unknown versions */ 627287607Shrs m_freem(m); 628287607Shrs goto drop; 629153621Sthompsa } 630153621Sthompsa m_adj(m, sizeof(struct etherip_header)); 631153621Sthompsa 632153621Sthompsa m->m_flags &= ~(M_BCAST|M_MCAST); 633153621Sthompsa m->m_pkthdr.rcvif = ifp; 634153621Sthompsa 635176879Sthompsa if (ifp->if_bridge) { 636176879Sthompsa oldifp = ifp; 637176879Sthompsa eh = mtod(m, struct ether_header *); 638176879Sthompsa if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 639176879Sthompsa if (ETHER_IS_BROADCAST(eh->ether_dhost)) 640176879Sthompsa m->m_flags |= M_BCAST; 641176879Sthompsa else 642176879Sthompsa m->m_flags |= M_MCAST; 643271867Sglebius if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); 644176879Sthompsa } 645153621Sthompsa BRIDGE_INPUT(ifp, m); 646176879Sthompsa 647176879Sthompsa if (m != NULL && ifp != oldifp) { 648176879Sthompsa /* 649176879Sthompsa * The bridge gave us back itself or one of the 650176879Sthompsa * members for which the frame is addressed. 651176879Sthompsa */ 652176879Sthompsa ether_demux(ifp, m); 653176879Sthompsa return; 654176879Sthompsa } 655176879Sthompsa } 656153621Sthompsa if (m != NULL) 657153621Sthompsa m_freem(m); 658153621Sthompsa return; 659153621Sthompsa 66054263Sshin default: 66183998Sbrooks if (ng_gif_input_orphan_p != NULL) 662105338Sume (*ng_gif_input_orphan_p)(ifp, m, af); 66383998Sbrooks else 66483998Sbrooks m_freem(m); 66554263Sshin return; 66654263Sshin } 66754263Sshin 668271867Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 669271867Sglebius if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 670223741Sbz M_SETFIB(m, ifp->if_fib); 671111888Sjlemon netisr_dispatch(isr, m); 672273087Sae return; 673273087Saedrop: 674273087Sae if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 67554263Sshin} 67654263Sshin 67762587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 67854263Sshinint 679258167Saegif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 68054263Sshin{ 681273087Sae GIF_RLOCK_TRACKER; 682273087Sae struct ifreq *ifr = (struct ifreq*)data; 68362587Sitojun struct sockaddr *dst, *src; 684273087Sae struct gif_softc *sc; 685273087Sae#ifdef INET 686273087Sae struct sockaddr_in *sin = NULL; 687105339Sume#endif 688273087Sae#ifdef INET6 689273087Sae struct sockaddr_in6 *sin6 = NULL; 690273087Sae#endif 691273087Sae u_int options; 692273087Sae int error; 693105339Sume 69454263Sshin switch (cmd) { 69554263Sshin case SIOCSIFADDR: 696105293Sume ifp->if_flags |= IFF_UP; 69754263Sshin case SIOCADDMULTI: 69854263Sshin case SIOCDELMULTI: 69954263Sshin case SIOCGIFMTU: 700273087Sae case SIOCSIFFLAGS: 701273087Sae return (0); 70254263Sshin case SIOCSIFMTU: 703273087Sae if (ifr->ifr_mtu < GIF_MTU_MIN || 704273087Sae ifr->ifr_mtu > GIF_MTU_MAX) 705105339Sume return (EINVAL); 706273087Sae else 707273087Sae ifp->if_mtu = ifr->ifr_mtu; 708273087Sae return (0); 709273087Sae } 710273087Sae sx_xlock(&gif_ioctl_sx); 711273087Sae sc = ifp->if_softc; 712273087Sae if (sc == NULL) { 713273087Sae error = ENXIO; 714273087Sae goto bad; 715273087Sae } 716273087Sae error = 0; 717273087Sae switch (cmd) { 71854263Sshin case SIOCSIFPHYADDR: 719273091Sae#ifdef INET6 72054263Sshin case SIOCSIFPHYADDR_IN6: 721273091Sae#endif 722273087Sae error = EINVAL; 72362587Sitojun switch (cmd) { 72478064Sume#ifdef INET 72562587Sitojun case SIOCSIFPHYADDR: 72654263Sshin src = (struct sockaddr *) 72754263Sshin &(((struct in_aliasreq *)data)->ifra_addr); 72854263Sshin dst = (struct sockaddr *) 72954263Sshin &(((struct in_aliasreq *)data)->ifra_dstaddr); 73062587Sitojun break; 73178064Sume#endif 73262587Sitojun#ifdef INET6 73362587Sitojun case SIOCSIFPHYADDR_IN6: 73462587Sitojun src = (struct sockaddr *) 73562587Sitojun &(((struct in6_aliasreq *)data)->ifra_addr); 73662587Sitojun dst = (struct sockaddr *) 73762587Sitojun &(((struct in6_aliasreq *)data)->ifra_dstaddr); 73862587Sitojun break; 73962587Sitojun#endif 74091327Sbrooks default: 741273087Sae goto bad; 74262587Sitojun } 74378064Sume /* sa_family must be equal */ 744273087Sae if (src->sa_family != dst->sa_family || 745273087Sae src->sa_len != dst->sa_len) 746273087Sae goto bad; 74778064Sume 74878064Sume /* validate sa_len */ 749287607Shrs /* check sa_family looks sane for the cmd */ 75078064Sume switch (src->sa_family) { 75178064Sume#ifdef INET 75278064Sume case AF_INET: 75378064Sume if (src->sa_len != sizeof(struct sockaddr_in)) 754273087Sae goto bad; 755287607Shrs if (cmd != SIOCSIFPHYADDR) { 756287607Shrs error = EAFNOSUPPORT; 757287607Shrs goto bad; 758287607Shrs } 759287607Shrs if (satosin(src)->sin_addr.s_addr == INADDR_ANY || 760287607Shrs satosin(dst)->sin_addr.s_addr == INADDR_ANY) { 761287607Shrs error = EADDRNOTAVAIL; 762287607Shrs goto bad; 763287607Shrs } 76478064Sume break; 76578064Sume#endif 76678064Sume#ifdef INET6 76778064Sume case AF_INET6: 76878064Sume if (src->sa_len != sizeof(struct sockaddr_in6)) 769273087Sae goto bad; 770287607Shrs if (cmd != SIOCSIFPHYADDR_IN6) { 771287607Shrs error = EAFNOSUPPORT; 772273087Sae goto bad; 773287607Shrs } 774287607Shrs error = EADDRNOTAVAIL; 775273087Sae if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr) 776273087Sae || 777273087Sae IN6_IS_ADDR_UNSPECIFIED(&satosin6(dst)->sin6_addr)) 778273087Sae goto bad; 779273087Sae /* 780273087Sae * Check validity of the scope zone ID of the 781273087Sae * addresses, and convert it into the kernel 782273087Sae * internal form if necessary. 783273087Sae */ 784273087Sae error = sa6_embedscope(satosin6(src), 0); 785273087Sae if (error != 0) 786273087Sae goto bad; 787273087Sae error = sa6_embedscope(satosin6(dst), 0); 788273087Sae if (error != 0) 789273087Sae goto bad; 790287607Shrs break; 791273087Sae#endif 792287607Shrs default: 793287607Shrs error = EAFNOSUPPORT; 794287607Shrs goto bad; 795287607Shrs } 796273087Sae error = gif_set_tunnel(ifp, src, dst); 79762587Sitojun break; 79862587Sitojun case SIOCDIFPHYADDR: 799273087Sae gif_delete_tunnel(ifp); 80054263Sshin break; 80154263Sshin case SIOCGIFPSRCADDR: 802273087Sae case SIOCGIFPDSTADDR: 803273091Sae#ifdef INET6 80454263Sshin case SIOCGIFPSRCADDR_IN6: 805273087Sae case SIOCGIFPDSTADDR_IN6: 806273091Sae#endif 807273087Sae if (sc->gif_family == 0) { 80854263Sshin error = EADDRNOTAVAIL; 809273087Sae break; 81054263Sshin } 811273087Sae GIF_RLOCK(sc); 81278064Sume switch (cmd) { 81354263Sshin#ifdef INET 81478064Sume case SIOCGIFPSRCADDR: 815273087Sae case SIOCGIFPDSTADDR: 816273087Sae if (sc->gif_family != AF_INET) { 817273087Sae error = EADDRNOTAVAIL; 818273087Sae break; 819273087Sae } 820273087Sae sin = (struct sockaddr_in *)&ifr->ifr_addr; 821273087Sae memset(sin, 0, sizeof(*sin)); 822273087Sae sin->sin_family = AF_INET; 823273087Sae sin->sin_len = sizeof(*sin); 82454263Sshin break; 825273087Sae#endif 82654263Sshin#ifdef INET6 82778064Sume case SIOCGIFPSRCADDR_IN6: 828273087Sae case SIOCGIFPDSTADDR_IN6: 829273087Sae if (sc->gif_family != AF_INET6) { 830273087Sae error = EADDRNOTAVAIL; 831273087Sae break; 832273087Sae } 833273087Sae sin6 = (struct sockaddr_in6 *) 83454263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 835273087Sae memset(sin6, 0, sizeof(*sin6)); 836273087Sae sin6->sin6_family = AF_INET6; 837273087Sae sin6->sin6_len = sizeof(*sin6); 83854263Sshin break; 839273087Sae#endif 84054263Sshin default: 841273087Sae error = EAFNOSUPPORT; 84254263Sshin } 843273087Sae if (error == 0) { 844273087Sae switch (cmd) { 845273087Sae#ifdef INET 846273087Sae case SIOCGIFPSRCADDR: 847273087Sae sin->sin_addr = sc->gif_iphdr->ip_src; 848273087Sae break; 849273087Sae case SIOCGIFPDSTADDR: 850273087Sae sin->sin_addr = sc->gif_iphdr->ip_dst; 851273087Sae break; 852273087Sae#endif 853148385Sume#ifdef INET6 854273087Sae case SIOCGIFPSRCADDR_IN6: 855273087Sae sin6->sin6_addr = sc->gif_ip6hdr->ip6_src; 856273087Sae break; 857273087Sae case SIOCGIFPDSTADDR_IN6: 858273087Sae sin6->sin6_addr = sc->gif_ip6hdr->ip6_dst; 859273087Sae break; 860148385Sume#endif 861273087Sae } 86254263Sshin } 863273087Sae GIF_RUNLOCK(sc); 864273087Sae if (error != 0) 865273087Sae break; 86678064Sume switch (cmd) { 86754263Sshin#ifdef INET 868273087Sae case SIOCGIFPSRCADDR: 86978064Sume case SIOCGIFPDSTADDR: 870273087Sae error = prison_if(curthread->td_ucred, 871273087Sae (struct sockaddr *)sin); 872273087Sae if (error != 0) 873273087Sae memset(sin, 0, sizeof(*sin)); 87454263Sshin break; 875273087Sae#endif 87654263Sshin#ifdef INET6 877273087Sae case SIOCGIFPSRCADDR_IN6: 87878064Sume case SIOCGIFPDSTADDR_IN6: 879273087Sae error = prison_if(curthread->td_ucred, 880273087Sae (struct sockaddr *)sin6); 881273087Sae if (error == 0) 882273087Sae error = sa6_recoverscope(sin6); 883148385Sume if (error != 0) 884273087Sae memset(sin6, 0, sizeof(*sin6)); 885273090Sae#endif 886148385Sume } 88754263Sshin break; 888282809Sae case SIOCGTUNFIB: 889282809Sae ifr->ifr_fib = sc->gif_fibnum; 890282809Sae break; 891282809Sae case SIOCSTUNFIB: 892282809Sae if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0) 893282809Sae break; 894282809Sae if (ifr->ifr_fib >= rt_numfibs) 895282809Sae error = EINVAL; 896282809Sae else 897282809Sae sc->gif_fibnum = ifr->ifr_fib; 898282809Sae break; 899193664Shrs case GIFGOPTS: 900193664Shrs options = sc->gif_options; 901332288Sbrooks error = copyout(&options, ifr_data_get_ptr(ifr), 902332288Sbrooks sizeof(options)); 903193664Shrs break; 904193664Shrs case GIFSOPTS: 905193664Shrs if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0) 906193664Shrs break; 907332288Sbrooks error = copyin(ifr_data_get_ptr(ifr), &options, 908332288Sbrooks sizeof(options)); 909193815Shrs if (error) 910193815Shrs break; 911193815Shrs if (options & ~GIF_OPTMASK) 912193815Shrs error = EINVAL; 913193815Shrs else 914193815Shrs sc->gif_options = options; 915193664Shrs break; 91654263Sshin default: 91754263Sshin error = EINVAL; 91854263Sshin break; 91954263Sshin } 920273087Saebad: 921273087Sae sx_xunlock(&gif_ioctl_sx); 922273087Sae return (error); 92354263Sshin} 92479106Sbrooks 925273087Saestatic void 926273087Saegif_detach(struct gif_softc *sc) 927105293Sume{ 928105293Sume 929273087Sae sx_assert(&gif_ioctl_sx, SA_XLOCKED); 930273087Sae if (sc->gif_ecookie != NULL) 931273087Sae encap_detach(sc->gif_ecookie); 932273087Sae sc->gif_ecookie = NULL; 933273087Sae} 934105293Sume 935273087Saestatic int 936273087Saegif_attach(struct gif_softc *sc, int af) 937273087Sae{ 938105293Sume 939273087Sae sx_assert(&gif_ioctl_sx, SA_XLOCKED); 940273087Sae switch (af) { 941273087Sae#ifdef INET 942273087Sae case AF_INET: 943273087Sae return (in_gif_attach(sc)); 944273087Sae#endif 945273087Sae#ifdef INET6 946273087Sae case AF_INET6: 947273087Sae return (in6_gif_attach(sc)); 948273087Sae#endif 949105293Sume } 950273087Sae return (EAFNOSUPPORT); 951273087Sae} 952105293Sume 953273087Saestatic int 954273087Saegif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) 955273087Sae{ 956273087Sae struct gif_softc *sc = ifp->if_softc; 957273087Sae struct gif_softc *tsc; 958105293Sume#ifdef INET 959273087Sae struct ip *ip; 960105293Sume#endif 961105293Sume#ifdef INET6 962273087Sae struct ip6_hdr *ip6; 963105293Sume#endif 964273087Sae void *hdr; 965273087Sae int error = 0; 966105293Sume 967273087Sae if (sc == NULL) 968273087Sae return (ENXIO); 969273087Sae /* Disallow parallel tunnels unless instructed otherwise. */ 970273087Sae if (V_parallel_tunnels == 0) { 971273087Sae GIF_LIST_LOCK(); 972273087Sae LIST_FOREACH(tsc, &V_gif_softc_list, gif_list) { 973273087Sae if (tsc == sc || tsc->gif_family != src->sa_family) 974273087Sae continue; 975105293Sume#ifdef INET 976273087Sae if (tsc->gif_family == AF_INET && 977273087Sae tsc->gif_iphdr->ip_src.s_addr == 978273087Sae satosin(src)->sin_addr.s_addr && 979273087Sae tsc->gif_iphdr->ip_dst.s_addr == 980273087Sae satosin(dst)->sin_addr.s_addr) { 981273087Sae error = EADDRNOTAVAIL; 982273087Sae GIF_LIST_UNLOCK(); 983273087Sae goto bad; 984273087Sae } 985273087Sae#endif 986273087Sae#ifdef INET6 987273087Sae if (tsc->gif_family == AF_INET6 && 988273087Sae IN6_ARE_ADDR_EQUAL(&tsc->gif_ip6hdr->ip6_src, 989273087Sae &satosin6(src)->sin6_addr) && 990273087Sae IN6_ARE_ADDR_EQUAL(&tsc->gif_ip6hdr->ip6_dst, 991273087Sae &satosin6(dst)->sin6_addr)) { 992273087Sae error = EADDRNOTAVAIL; 993273087Sae GIF_LIST_UNLOCK(); 994273087Sae goto bad; 995273087Sae } 996273087Sae#endif 997273087Sae } 998273087Sae GIF_LIST_UNLOCK(); 999273087Sae } 1000273087Sae switch (src->sa_family) { 1001273087Sae#ifdef INET 1002105293Sume case AF_INET: 1003273087Sae hdr = ip = malloc(sizeof(struct ip), M_GIF, 1004273087Sae M_WAITOK | M_ZERO); 1005273087Sae ip->ip_src.s_addr = satosin(src)->sin_addr.s_addr; 1006273087Sae ip->ip_dst.s_addr = satosin(dst)->sin_addr.s_addr; 1007105293Sume break; 1008105293Sume#endif 1009105293Sume#ifdef INET6 1010105293Sume case AF_INET6: 1011273087Sae hdr = ip6 = malloc(sizeof(struct ip6_hdr), M_GIF, 1012273087Sae M_WAITOK | M_ZERO); 1013273087Sae ip6->ip6_src = satosin6(src)->sin6_addr; 1014273087Sae ip6->ip6_dst = satosin6(dst)->sin6_addr; 1015273087Sae ip6->ip6_vfc = IPV6_VERSION; 1016105293Sume break; 1017105293Sume#endif 1018273087Sae default: 1019273087Sae return (EAFNOSUPPORT); 1020297793Spfg } 1021105293Sume 1022273087Sae if (sc->gif_family != src->sa_family) 1023273087Sae gif_detach(sc); 1024273087Sae if (sc->gif_family == 0 || 1025273087Sae sc->gif_family != src->sa_family) 1026273087Sae error = gif_attach(sc, src->sa_family); 1027105293Sume 1028273087Sae GIF_WLOCK(sc); 1029273087Sae if (sc->gif_family != 0) 1030273087Sae free(sc->gif_hdr, M_GIF); 1031273087Sae sc->gif_family = src->sa_family; 1032273087Sae sc->gif_hdr = hdr; 1033273087Sae GIF_WUNLOCK(sc); 1034273091Sae#if defined(INET) || defined(INET6) 1035273087Saebad: 1036273091Sae#endif 1037288575Shrs if (error == 0 && sc->gif_family != 0) { 1038148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1039288575Shrs if_link_state_change(ifp, LINK_STATE_UP); 1040288575Shrs } else { 1041148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1042288575Shrs if_link_state_change(ifp, LINK_STATE_DOWN); 1043288575Shrs } 1044273087Sae return (error); 1045105293Sume} 1046105293Sume 1047273087Saestatic void 1048258167Saegif_delete_tunnel(struct ifnet *ifp) 104979106Sbrooks{ 1050147256Sbrooks struct gif_softc *sc = ifp->if_softc; 1051273087Sae int family; 105279106Sbrooks 1053273087Sae if (sc == NULL) 1054273087Sae return; 1055273087Sae 1056273087Sae GIF_WLOCK(sc); 1057273087Sae family = sc->gif_family; 1058273087Sae sc->gif_family = 0; 1059273087Sae GIF_WUNLOCK(sc); 1060273087Sae if (family != 0) { 1061273087Sae gif_detach(sc); 1062273087Sae free(sc->gif_hdr, M_GIF); 106379106Sbrooks } 1064160018Syar ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1065288575Shrs if_link_state_change(ifp, LINK_STATE_DOWN); 106679106Sbrooks} 1067