if_gif.c revision 253261
1185377Ssam/* $FreeBSD: head/sys/net/if_gif.c 253261 2013-07-12 12:18:07Z hrs $ */ 2187831Ssam/* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ */ 3185377Ssam 4185377Ssam/*- 5185377Ssam * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6185377Ssam * All rights reserved. 7185377Ssam * 8185377Ssam * Redistribution and use in source and binary forms, with or without 9185377Ssam * modification, are permitted provided that the following conditions 10185377Ssam * are met: 11185377Ssam * 1. Redistributions of source code must retain the above copyright 12185377Ssam * notice, this list of conditions and the following disclaimer. 13185377Ssam * 2. Redistributions in binary form must reproduce the above copyright 14185377Ssam * notice, this list of conditions and the following disclaimer in the 15185377Ssam * documentation and/or other materials provided with the distribution. 16185377Ssam * 3. Neither the name of the project nor the names of its contributors 17185907Ssam * may be used to endorse or promote products derived from this software 18185377Ssam * without specific prior written permission. 19185377Ssam * 20185377Ssam * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21185377Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22185377Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23185377Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24185377Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25185377Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26185377Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27185377Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28185377Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29185377Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30185377Ssam * SUCH DAMAGE. 31185377Ssam */ 32185377Ssam 33185377Ssam#include "opt_inet.h" 34185377Ssam#include "opt_inet6.h" 35185377Ssam 36185377Ssam#include <sys/param.h> 37185377Ssam#include <sys/systm.h> 38185377Ssam#include <sys/jail.h> 39185377Ssam#include <sys/kernel.h> 40185377Ssam#include <sys/malloc.h> 41185377Ssam#include <sys/mbuf.h> 42185377Ssam#include <sys/module.h> 43185377Ssam#include <sys/socket.h> 44185377Ssam#include <sys/sockio.h> 45185377Ssam#include <sys/errno.h> 46185377Ssam#include <sys/time.h> 47185377Ssam#include <sys/sysctl.h> 48185377Ssam#include <sys/syslog.h> 49185377Ssam#include <sys/priv.h> 50185377Ssam#include <sys/proc.h> 51185377Ssam#include <sys/protosw.h> 52185377Ssam#include <sys/conf.h> 53185377Ssam#include <machine/cpu.h> 54185377Ssam 55185377Ssam#include <net/if.h> 56185377Ssam#include <net/if_clone.h> 57185377Ssam#include <net/if_types.h> 58185377Ssam#include <net/netisr.h> 59185377Ssam#include <net/route.h> 60185377Ssam#include <net/bpf.h> 61185377Ssam#include <net/vnet.h> 62185377Ssam 63185377Ssam#include <netinet/in.h> 64185377Ssam#include <netinet/in_systm.h> 65185377Ssam#include <netinet/ip.h> 66185377Ssam#ifdef INET 67185377Ssam#include <netinet/in_var.h> 68185377Ssam#include <netinet/in_gif.h> 69185377Ssam#include <netinet/ip_var.h> 70185377Ssam#endif /* INET */ 71185377Ssam 72185377Ssam#ifdef INET6 73185377Ssam#ifndef INET 74185380Ssam#include <netinet/in.h> 75185380Ssam#endif 76185380Ssam#include <netinet6/in6_var.h> 77185380Ssam#include <netinet/ip6.h> 78185380Ssam#include <netinet6/ip6_var.h> 79185380Ssam#include <netinet6/scope6_var.h> 80185380Ssam#include <netinet6/in6_gif.h> 81185380Ssam#include <netinet6/ip6protosw.h> 82185380Ssam#endif /* INET6 */ 83185380Ssam 84185380Ssam#include <netinet/ip_encap.h> 85185380Ssam#include <net/ethernet.h> 86185380Ssam#include <net/if_bridgevar.h> 87185380Ssam#include <net/if_gif.h> 88185380Ssam 89185380Ssam#include <security/mac/mac_framework.h> 90185380Ssam 91185380Ssamstatic const char gifname[] = "gif"; 92185380Ssam 93185380Ssam/* 94185380Ssam * gif_mtx protects the global gif_softc_list. 95185380Ssam */ 96185380Ssamstatic struct mtx gif_mtx; 97185380Ssamstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 98185380Ssamstatic VNET_DEFINE(LIST_HEAD(, gif_softc), gif_softc_list); 99185380Ssam#define V_gif_softc_list VNET(gif_softc_list) 100185380Ssam 101185380Ssamvoid (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 102185380Ssamvoid (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 103185380Ssamvoid (*ng_gif_attach_p)(struct ifnet *ifp); 104185380Ssamvoid (*ng_gif_detach_p)(struct ifnet *ifp); 105185380Ssam 106185380Ssamstatic void gif_start(struct ifnet *); 107185377Ssamstatic int gif_clone_create(struct if_clone *, int, caddr_t); 108185377Ssamstatic void gif_clone_destroy(struct ifnet *); 109185377Ssamstatic struct if_clone *gif_cloner; 110185377Ssam 111185377Ssamstatic int gifmodevent(module_t, int, void *); 112185377Ssam 113185377SsamSYSCTL_DECL(_net_link); 114185377Ssamstatic SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 115185377Ssam "Generic Tunnel Interface"); 116185377Ssam#ifndef MAX_GIF_NEST 117185377Ssam/* 118185377Ssam * This macro controls the default upper limitation on nesting of gif tunnels. 119185377Ssam * Since, setting a large value to this macro with a careless configuration 120185377Ssam * may introduce system crash, we don't allow any nestings by default. 121185380Ssam * If you need to configure nested gif tunnels, you can define this macro 122185380Ssam * in your kernel configuration file. However, if you do so, please be 123185380Ssam * careful to configure the tunnels so that it won't make a loop. 124185380Ssam */ 125185377Ssam#define MAX_GIF_NEST 1 126185377Ssam#endif 127185377Ssamstatic VNET_DEFINE(int, max_gif_nesting) = MAX_GIF_NEST; 128185377Ssam#define V_max_gif_nesting VNET(max_gif_nesting) 129185377SsamSYSCTL_VNET_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 130185377Ssam &VNET_NAME(max_gif_nesting), 0, "Max nested tunnels"); 131185377Ssam 132185377Ssam/* 133185380Ssam * By default, we disallow creation of multiple tunnels between the same 134185380Ssam * pair of addresses. Some applications require this functionality so 135185380Ssam * we allow control over this check here. 136185380Ssam */ 137185377Ssam#ifdef XBONEHACK 138185377Ssamstatic VNET_DEFINE(int, parallel_tunnels) = 1; 139185377Ssam#else 140185377Ssamstatic VNET_DEFINE(int, parallel_tunnels) = 0; 141185377Ssam#endif 142185377Ssam#define V_parallel_tunnels VNET(parallel_tunnels) 143185377SsamSYSCTL_VNET_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 144185377Ssam &VNET_NAME(parallel_tunnels), 0, "Allow parallel tunnels?"); 145185377Ssam 146185377Ssam/* copy from src/sys/net/if_ethersubr.c */ 147185377Ssamstatic const u_char etherbroadcastaddr[ETHER_ADDR_LEN] = 148185377Ssam { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 149185377Ssam#ifndef ETHER_IS_BROADCAST 150185377Ssam#define ETHER_IS_BROADCAST(addr) \ 151185377Ssam (bcmp(etherbroadcastaddr, (addr), ETHER_ADDR_LEN) == 0) 152185377Ssam#endif 153185377Ssam 154185377Ssamstatic int 155185377Ssamgif_clone_create(ifc, unit, params) 156185377Ssam struct if_clone *ifc; 157185377Ssam int unit; 158185377Ssam caddr_t params; 159185377Ssam{ 160185377Ssam struct gif_softc *sc; 161185377Ssam 162185377Ssam sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO); 163185377Ssam sc->gif_fibnum = curthread->td_proc->p_fibnum; 164185377Ssam GIF2IFP(sc) = if_alloc(IFT_GIF); 165185377Ssam if (GIF2IFP(sc) == NULL) { 166185377Ssam free(sc, M_GIF); 167185377Ssam return (ENOSPC); 168185377Ssam } 169185377Ssam 170185377Ssam GIF_LOCK_INIT(sc); 171185377Ssam 172185377Ssam GIF2IFP(sc)->if_softc = sc; 173185377Ssam if_initname(GIF2IFP(sc), gifname, unit); 174185377Ssam 175185377Ssam sc->encap_cookie4 = sc->encap_cookie6 = NULL; 176185377Ssam sc->gif_options = 0; 177185377Ssam 178185377Ssam GIF2IFP(sc)->if_addrlen = 0; 179185377Ssam GIF2IFP(sc)->if_mtu = GIF_MTU; 180185377Ssam GIF2IFP(sc)->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 181185377Ssam#if 0 182185377Ssam /* turn off ingress filter */ 183185377Ssam GIF2IFP(sc)->if_flags |= IFF_LINK2; 184185377Ssam#endif 185185377Ssam GIF2IFP(sc)->if_ioctl = gif_ioctl; 186185377Ssam GIF2IFP(sc)->if_start = gif_start; 187185377Ssam GIF2IFP(sc)->if_output = gif_output; 188185377Ssam GIF2IFP(sc)->if_snd.ifq_maxlen = ifqmaxlen; 189185377Ssam if_attach(GIF2IFP(sc)); 190185377Ssam bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 191185377Ssam if (ng_gif_attach_p != NULL) 192185377Ssam (*ng_gif_attach_p)(GIF2IFP(sc)); 193185377Ssam 194185377Ssam mtx_lock(&gif_mtx); 195185377Ssam LIST_INSERT_HEAD(&V_gif_softc_list, sc, gif_list); 196185377Ssam mtx_unlock(&gif_mtx); 197185377Ssam 198185377Ssam return (0); 199185377Ssam} 200185377Ssam 201185377Ssamstatic void 202185377Ssamgif_clone_destroy(ifp) 203185377Ssam struct ifnet *ifp; 204185377Ssam{ 205185377Ssam#if defined(INET) || defined(INET6) 206185377Ssam int err; 207185377Ssam#endif 208185377Ssam struct gif_softc *sc = ifp->if_softc; 209185377Ssam 210185377Ssam mtx_lock(&gif_mtx); 211185377Ssam LIST_REMOVE(sc, gif_list); 212185377Ssam mtx_unlock(&gif_mtx); 213185377Ssam 214185377Ssam gif_delete_tunnel(ifp); 215185377Ssam#ifdef INET6 216185377Ssam if (sc->encap_cookie6 != NULL) { 217185377Ssam err = encap_detach(sc->encap_cookie6); 218185377Ssam KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 219185377Ssam } 220185377Ssam#endif 221226760Sadrian#ifdef INET 222185377Ssam if (sc->encap_cookie4 != NULL) { 223226760Sadrian err = encap_detach(sc->encap_cookie4); 224185377Ssam KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 225185377Ssam } 226185377Ssam#endif 227185377Ssam 228185377Ssam if (ng_gif_detach_p != NULL) 229185377Ssam (*ng_gif_detach_p)(ifp); 230185377Ssam bpfdetach(ifp); 231185377Ssam if_detach(ifp); 232185377Ssam if_free(ifp); 233185377Ssam 234185377Ssam GIF_LOCK_DESTROY(sc); 235185377Ssam 236185377Ssam free(sc, M_GIF); 237185377Ssam} 238185377Ssam 239185377Ssamstatic void 240185377Ssamvnet_gif_init(const void *unused __unused) 241185377Ssam{ 242185377Ssam 243185377Ssam LIST_INIT(&V_gif_softc_list); 244185377Ssam} 245185377SsamVNET_SYSINIT(vnet_gif_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, vnet_gif_init, 246185377Ssam NULL); 247185380Ssam 248185380Ssamstatic int 249185380Ssamgifmodevent(mod, type, data) 250185380Ssam module_t mod; 251185377Ssam int type; 252185377Ssam void *data; 253185377Ssam{ 254185377Ssam 255185377Ssam switch (type) { 256185377Ssam case MOD_LOAD: 257185377Ssam mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF); 258185377Ssam gif_cloner = if_clone_simple(gifname, gif_clone_create, 259185377Ssam gif_clone_destroy, 0); 260185377Ssam break; 261185377Ssam 262185377Ssam case MOD_UNLOAD: 263185377Ssam if_clone_detach(gif_cloner); 264185377Ssam mtx_destroy(&gif_mtx); 265185377Ssam break; 266219419Sadrian default: 267219419Sadrian return EOPNOTSUPP; 268219419Sadrian } 269219419Sadrian return 0; 270219419Sadrian} 271219419Sadrian 272219419Sadrianstatic moduledata_t gif_mod = { 273185377Ssam "if_gif", 274185377Ssam gifmodevent, 275185377Ssam 0 276185377Ssam}; 277185377Ssam 278185377SsamDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 279185377SsamMODULE_VERSION(if_gif, 1); 280185377Ssam 281185377Ssamint 282185377Ssamgif_encapcheck(m, off, proto, arg) 283185377Ssam const struct mbuf *m; 284185377Ssam int off; 285185377Ssam int proto; 286185377Ssam void *arg; 287185377Ssam{ 288185377Ssam struct ip ip; 289185377Ssam struct gif_softc *sc; 290185377Ssam 291185377Ssam sc = (struct gif_softc *)arg; 292185377Ssam if (sc == NULL) 293185377Ssam return 0; 294185377Ssam 295185377Ssam if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0) 296185377Ssam return 0; 297185377Ssam 298185377Ssam /* no physical address */ 299185377Ssam if (!sc->gif_psrc || !sc->gif_pdst) 300185377Ssam return 0; 301187831Ssam 302185377Ssam switch (proto) { 303185377Ssam#ifdef INET 304185377Ssam case IPPROTO_IPV4: 305185377Ssam break; 306187831Ssam#endif 307185377Ssam#ifdef INET6 308185377Ssam case IPPROTO_IPV6: 309185377Ssam break; 310185377Ssam#endif 311185377Ssam case IPPROTO_ETHERIP: 312185377Ssam break; 313185377Ssam 314185377Ssam default: 315185377Ssam return 0; 316185377Ssam } 317185377Ssam 318185377Ssam /* Bail on short packets */ 319185377Ssam if (m->m_pkthdr.len < sizeof(ip)) 320185377Ssam return 0; 321185377Ssam 322185377Ssam m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 323185377Ssam 324185377Ssam switch (ip.ip_v) { 325185377Ssam#ifdef INET 326185377Ssam case 4: 327185377Ssam if (sc->gif_psrc->sa_family != AF_INET || 328185377Ssam sc->gif_pdst->sa_family != AF_INET) 329185377Ssam return 0; 330185377Ssam return gif_encapcheck4(m, off, proto, arg); 331185377Ssam#endif 332185377Ssam#ifdef INET6 333185377Ssam case 6: 334185377Ssam if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 335185377Ssam return 0; 336185377Ssam if (sc->gif_psrc->sa_family != AF_INET6 || 337185377Ssam sc->gif_pdst->sa_family != AF_INET6) 338185377Ssam return 0; 339185377Ssam return gif_encapcheck6(m, off, proto, arg); 340185377Ssam#endif 341185377Ssam default: 342185377Ssam return 0; 343185377Ssam } 344185377Ssam} 345185377Ssam#ifdef INET 346185377Ssam#define GIF_HDR_LEN (ETHER_HDR_LEN + sizeof (struct ip)) 347185377Ssam#endif 348185377Ssam#ifdef INET6 349185377Ssam#define GIF_HDR_LEN6 (ETHER_HDR_LEN + sizeof (struct ip6_hdr)) 350185377Ssam#endif 351185377Ssam 352185377Ssamstatic void 353185377Ssamgif_start(struct ifnet *ifp) 354185377Ssam{ 355185377Ssam struct gif_softc *sc; 356185377Ssam struct mbuf *m; 357185377Ssam uint32_t af; 358185377Ssam int error = 0; 359185377Ssam 360185377Ssam sc = ifp->if_softc; 361185377Ssam GIF_LOCK(sc); 362185377Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 363185377Ssam while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 364185377Ssam 365185377Ssam IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 366185377Ssam if (m == 0) 367185377Ssam break; 368185377Ssam 369185377Ssam#ifdef ALTQ 370185377Ssam /* Take out those altq bytes we add in gif_output */ 371185377Ssam#ifdef INET 372185377Ssam if (sc->gif_psrc->sa_family == AF_INET) 373185377Ssam m->m_pkthdr.len -= GIF_HDR_LEN; 374185377Ssam#endif 375185377Ssam#ifdef INET6 376185377Ssam if (sc->gif_psrc->sa_family == AF_INET6) 377185377Ssam m->m_pkthdr.len -= GIF_HDR_LEN6; 378185377Ssam#endif 379185377Ssam#endif 380185377Ssam /* 381185377Ssam * Now pull back the af that we 382185377Ssam * stashed in the csum_data. 383185377Ssam */ 384185377Ssam af = m->m_pkthdr.csum_data; 385185377Ssam 386185377Ssam if (ifp->if_bridge) 387185377Ssam af = AF_LINK; 388185377Ssam 389185377Ssam BPF_MTAP2(ifp, &af, sizeof(af), m); 390185377Ssam ifp->if_opackets++; 391185377Ssam 392185377Ssam/* Done by IFQ_HANDOFF */ 393185377Ssam/* ifp->if_obytes += m->m_pkthdr.len;*/ 394185377Ssam /* override to IPPROTO_ETHERIP for bridged traffic */ 395185377Ssam 396185377Ssam M_SETFIB(m, sc->gif_fibnum); 397185377Ssam /* inner AF-specific encapsulation */ 398185377Ssam /* XXX should we check if our outer source is legal? */ 399185377Ssam /* dispatch to output logic based on outer AF */ 400185377Ssam switch (sc->gif_psrc->sa_family) { 401185377Ssam#ifdef INET 402185377Ssam case AF_INET: 403185377Ssam error = in_gif_output(ifp, af, m); 404185377Ssam break; 405185377Ssam#endif 406185377Ssam#ifdef INET6 407185377Ssam case AF_INET6: 408185377Ssam error = in6_gif_output(ifp, af, m); 409185377Ssam break; 410185377Ssam#endif 411185377Ssam default: 412185377Ssam m_freem(m); 413185377Ssam error = ENETDOWN; 414185377Ssam } 415185377Ssam if (error) 416185377Ssam ifp->if_oerrors++; 417185377Ssam 418185377Ssam } 419185377Ssam ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 420185377Ssam GIF_UNLOCK(sc); 421185377Ssam return; 422185377Ssam} 423185380Ssam 424185377Ssamint 425185377Ssamgif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 426185377Ssam struct route *ro) 427185380Ssam{ 428185377Ssam struct gif_softc *sc = ifp->if_softc; 429185380Ssam struct m_tag *mtag; 430187831Ssam int error = 0; 431185377Ssam int gif_called; 432187831Ssam uint32_t af; 433185380Ssam#ifdef MAC 434185380Ssam error = mac_ifnet_check_transmit(ifp, m); 435185380Ssam if (error) { 436185377Ssam m_freem(m); 437185377Ssam goto end; 438187831Ssam } 439185377Ssam#endif 440185377Ssam if ((ifp->if_flags & IFF_MONITOR) != 0) { 441185377Ssam error = ENETDOWN; 442185377Ssam m_freem(m); 443185377Ssam goto end; 444185377Ssam } 445185377Ssam 446185377Ssam /* 447185377Ssam * gif may cause infinite recursion calls when misconfigured. 448185377Ssam * We'll prevent this by detecting loops. 449185377Ssam * 450185377Ssam * High nesting level may cause stack exhaustion. 451185377Ssam * We'll prevent this by introducing upper limit. 452185377Ssam */ 453185377Ssam gif_called = 1; 454185377Ssam mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, NULL); 455185377Ssam while (mtag != NULL) { 456185377Ssam if (*(struct ifnet **)(mtag + 1) == ifp) { 457185377Ssam log(LOG_NOTICE, 458185377Ssam "gif_output: loop detected on %s\n", 459188866Ssam (*(struct ifnet **)(mtag + 1))->if_xname); 460218409Sadrian m_freem(m); 461185377Ssam error = EIO; /* is there better errno? */ 462185377Ssam goto end; 463185377Ssam } 464185377Ssam mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag); 465185377Ssam gif_called++; 466185377Ssam } 467185377Ssam if (gif_called > V_max_gif_nesting) { 468185377Ssam log(LOG_NOTICE, 469188866Ssam "gif_output: recursively called too many times(%d)\n", 470185377Ssam gif_called); 471185377Ssam m_freem(m); 472185377Ssam error = EIO; /* is there better errno? */ 473185377Ssam goto end; 474185377Ssam } 475185377Ssam mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *), 476185377Ssam M_NOWAIT); 477185377Ssam if (mtag == NULL) { 478185377Ssam m_freem(m); 479185377Ssam error = ENOMEM; 480185377Ssam goto end; 481185377Ssam } 482185377Ssam *(struct ifnet **)(mtag + 1) = ifp; 483185377Ssam m_tag_prepend(m, mtag); 484185377Ssam 485185377Ssam m->m_flags &= ~(M_BCAST|M_MCAST); 486185377Ssam /* BPF writes need to be handled specially. */ 487185377Ssam if (dst->sa_family == AF_UNSPEC) 488185377Ssam bcopy(dst->sa_data, &af, sizeof(af)); 489185377Ssam else 490185377Ssam af = dst->sa_family; 491185377Ssam /* 492185377Ssam * Now save the af in the inbound pkt csum 493185377Ssam * data, this is a cheat since we are using 494185377Ssam * the inbound csum_data field to carry the 495185377Ssam * af over to the gif_start() routine, avoiding 496185377Ssam * using yet another mtag. 497185377Ssam */ 498185377Ssam m->m_pkthdr.csum_data = af; 499185377Ssam if (!(ifp->if_flags & IFF_UP) || 500185377Ssam sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 501185377Ssam m_freem(m); 502185377Ssam error = ENETDOWN; 503185377Ssam goto end; 504185377Ssam } 505185377Ssam#ifdef ALTQ 506185377Ssam /* 507185377Ssam * Make altq aware of the bytes we will add 508185377Ssam * when we actually send it. 509185377Ssam */ 510185377Ssam#ifdef INET 511185377Ssam if (sc->gif_psrc->sa_family == AF_INET) 512185377Ssam m->m_pkthdr.len += GIF_HDR_LEN; 513185377Ssam#endif 514185377Ssam#ifdef INET6 515185377Ssam if (sc->gif_psrc->sa_family == AF_INET6) 516185377Ssam m->m_pkthdr.len += GIF_HDR_LEN6; 517185377Ssam#endif 518185377Ssam#endif 519185377Ssam /* 520185377Ssam * Queue message on interface, update output statistics if 521185377Ssam * successful, and start output if interface not yet active. 522185377Ssam */ 523185377Ssam IFQ_HANDOFF(ifp, m, error); 524185377Ssam end: 525185377Ssam if (error) 526185377Ssam ifp->if_oerrors++; 527185377Ssam return (error); 528185377Ssam} 529185377Ssam 530185377Ssamvoid 531185377Ssamgif_input(m, af, ifp) 532185377Ssam struct mbuf *m; 533185377Ssam int af; 534185377Ssam struct ifnet *ifp; 535185377Ssam{ 536185377Ssam int isr, n; 537185377Ssam struct gif_softc *sc; 538185377Ssam struct etherip_header *eip; 539185377Ssam struct ether_header *eh; 540185377Ssam struct ifnet *oldifp; 541185377Ssam 542185377Ssam if (ifp == NULL) { 543185377Ssam /* just in case */ 544185377Ssam m_freem(m); 545185377Ssam return; 546185377Ssam } 547185377Ssam sc = ifp->if_softc; 548185377Ssam m->m_pkthdr.rcvif = ifp; 549185377Ssam 550185377Ssam#ifdef MAC 551185377Ssam mac_ifnet_create_mbuf(ifp, m); 552185377Ssam#endif 553185377Ssam 554185377Ssam if (bpf_peers_present(ifp->if_bpf)) { 555185377Ssam u_int32_t af1 = af; 556185377Ssam bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 557185377Ssam } 558185377Ssam 559185377Ssam if ((ifp->if_flags & IFF_MONITOR) != 0) { 560185377Ssam ifp->if_ipackets++; 561185377Ssam ifp->if_ibytes += m->m_pkthdr.len; 562185377Ssam m_freem(m); 563185377Ssam return; 564185377Ssam } 565185377Ssam 566185377Ssam if (ng_gif_input_p != NULL) { 567185377Ssam (*ng_gif_input_p)(ifp, &m, af); 568185377Ssam if (m == NULL) 569185377Ssam return; 570185377Ssam } 571185377Ssam 572185377Ssam /* 573185377Ssam * Put the packet to the network layer input queue according to the 574185377Ssam * specified address family. 575185377Ssam * Note: older versions of gif_input directly called network layer 576185377Ssam * input functions, e.g. ip6_input, here. We changed the policy to 577228817Sadrian * prevent too many recursive calls of such input functions, which 578185377Ssam * might cause kernel panic. But the change may introduce another 579185377Ssam * problem; if the input queue is full, packets are discarded. 580185377Ssam * The kernel stack overflow really happened, and we believed 581185377Ssam * queue-full rarely occurs, so we changed the policy. 582185377Ssam */ 583185377Ssam switch (af) { 584185377Ssam#ifdef INET 585185377Ssam case AF_INET: 586185377Ssam isr = NETISR_IP; 587185377Ssam break; 588185377Ssam#endif 589185377Ssam#ifdef INET6 590185377Ssam case AF_INET6: 591185377Ssam isr = NETISR_IPV6; 592185377Ssam break; 593185377Ssam#endif 594185377Ssam case AF_LINK: 595185377Ssam n = sizeof(struct etherip_header) + sizeof(struct ether_header); 596185377Ssam if (n > m->m_len) { 597185377Ssam m = m_pullup(m, n); 598185377Ssam if (m == NULL) { 599187831Ssam ifp->if_ierrors++; 600185377Ssam return; 601185377Ssam } 602185377Ssam } 603185377Ssam 604185377Ssam eip = mtod(m, struct etherip_header *); 605185377Ssam /* 606185377Ssam * GIF_ACCEPT_REVETHIP (enabled by default) intentionally 607185377Ssam * accepts an EtherIP packet with revered version field in 608187831Ssam * the header. This is a knob for backward compatibility 609185377Ssam * with FreeBSD 7.2R or prior. 610185377Ssam */ 611187831Ssam if (sc->gif_options & GIF_ACCEPT_REVETHIP) { 612185377Ssam if (eip->eip_resvl != ETHERIP_VERSION 613185377Ssam && eip->eip_ver != ETHERIP_VERSION) { 614185377Ssam /* discard unknown versions */ 615185377Ssam m_freem(m); 616185377Ssam return; 617185377Ssam } 618185377Ssam } else { 619185377Ssam if (eip->eip_ver != ETHERIP_VERSION) { 620185377Ssam /* discard unknown versions */ 621185377Ssam m_freem(m); 622185377Ssam return; 623185377Ssam } 624185377Ssam } 625185377Ssam m_adj(m, sizeof(struct etherip_header)); 626185377Ssam 627185377Ssam m->m_flags &= ~(M_BCAST|M_MCAST); 628185377Ssam m->m_pkthdr.rcvif = ifp; 629185377Ssam 630185377Ssam if (ifp->if_bridge) { 631185377Ssam oldifp = ifp; 632185377Ssam eh = mtod(m, struct ether_header *); 633185377Ssam if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 634185377Ssam if (ETHER_IS_BROADCAST(eh->ether_dhost)) 635185377Ssam m->m_flags |= M_BCAST; 636222644Sadrian else 637222644Sadrian m->m_flags |= M_MCAST; 638222644Sadrian ifp->if_imcasts++; 639222644Sadrian } 640222644Sadrian BRIDGE_INPUT(ifp, m); 641222644Sadrian 642222644Sadrian if (m != NULL && ifp != oldifp) { 643222644Sadrian /* 644222644Sadrian * The bridge gave us back itself or one of the 645222644Sadrian * members for which the frame is addressed. 646222644Sadrian */ 647222644Sadrian ether_demux(ifp, m); 648222644Sadrian return; 649222644Sadrian } 650185377Ssam } 651185377Ssam if (m != NULL) 652185377Ssam m_freem(m); 653185377Ssam return; 654185377Ssam 655185377Ssam default: 656185377Ssam if (ng_gif_input_orphan_p != NULL) 657185377Ssam (*ng_gif_input_orphan_p)(ifp, m, af); 658185377Ssam else 659185377Ssam m_freem(m); 660185377Ssam return; 661185377Ssam } 662185377Ssam 663185377Ssam ifp->if_ipackets++; 664185377Ssam ifp->if_ibytes += m->m_pkthdr.len; 665185377Ssam M_SETFIB(m, ifp->if_fib); 666185377Ssam netisr_dispatch(isr, m); 667185377Ssam} 668185377Ssam 669185377Ssam/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 670185377Ssamint 671185377Ssamgif_ioctl(ifp, cmd, data) 672185377Ssam struct ifnet *ifp; 673185377Ssam u_long cmd; 674185377Ssam caddr_t data; 675185377Ssam{ 676185377Ssam struct gif_softc *sc = ifp->if_softc; 677185377Ssam struct ifreq *ifr = (struct ifreq*)data; 678185377Ssam int error = 0, size; 679185377Ssam u_int options; 680185377Ssam struct sockaddr *dst, *src; 681185377Ssam#ifdef SIOCSIFMTU /* xxx */ 682185377Ssam u_long mtu; 683185377Ssam#endif 684185377Ssam 685185377Ssam switch (cmd) { 686185377Ssam case SIOCSIFADDR: 687185377Ssam ifp->if_flags |= IFF_UP; 688185377Ssam break; 689185377Ssam 690185380Ssam case SIOCSIFDSTADDR: 691185380Ssam break; 692185377Ssam 693185377Ssam case SIOCADDMULTI: 694185377Ssam case SIOCDELMULTI: 695185377Ssam break; 696185377Ssam 697185377Ssam#ifdef SIOCSIFMTU /* xxx */ 698185377Ssam case SIOCGIFMTU: 699185377Ssam break; 700185377Ssam 701185377Ssam case SIOCSIFMTU: 702185377Ssam mtu = ifr->ifr_mtu; 703185377Ssam if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 704185377Ssam return (EINVAL); 705185377Ssam ifp->if_mtu = mtu; 706185377Ssam break; 707185377Ssam#endif /* SIOCSIFMTU */ 708185377Ssam 709185377Ssam#ifdef INET 710185377Ssam case SIOCSIFPHYADDR: 711185377Ssam#endif 712185377Ssam#ifdef INET6 713185377Ssam case SIOCSIFPHYADDR_IN6: 714185377Ssam#endif /* INET6 */ 715185377Ssam case SIOCSLIFPHYADDR: 716185377Ssam switch (cmd) { 717185377Ssam#ifdef INET 718185377Ssam case SIOCSIFPHYADDR: 719185377Ssam src = (struct sockaddr *) 720185377Ssam &(((struct in_aliasreq *)data)->ifra_addr); 721185377Ssam dst = (struct sockaddr *) 722185377Ssam &(((struct in_aliasreq *)data)->ifra_dstaddr); 723185377Ssam break; 724185377Ssam#endif 725185377Ssam#ifdef INET6 726185377Ssam case SIOCSIFPHYADDR_IN6: 727185377Ssam src = (struct sockaddr *) 728185380Ssam &(((struct in6_aliasreq *)data)->ifra_addr); 729185380Ssam dst = (struct sockaddr *) 730185380Ssam &(((struct in6_aliasreq *)data)->ifra_dstaddr); 731185377Ssam break; 732185377Ssam#endif 733185377Ssam case SIOCSLIFPHYADDR: 734185377Ssam src = (struct sockaddr *) 735185377Ssam &(((struct if_laddrreq *)data)->addr); 736185377Ssam dst = (struct sockaddr *) 737185377Ssam &(((struct if_laddrreq *)data)->dstaddr); 738185377Ssam break; 739185377Ssam default: 740185377Ssam return EINVAL; 741185377Ssam } 742185377Ssam 743185377Ssam /* sa_family must be equal */ 744185377Ssam if (src->sa_family != dst->sa_family) 745185377Ssam return EINVAL; 746185380Ssam 747185380Ssam /* validate sa_len */ 748185377Ssam switch (src->sa_family) { 749185377Ssam#ifdef INET 750185377Ssam case AF_INET: 751185377Ssam if (src->sa_len != sizeof(struct sockaddr_in)) 752185377Ssam return EINVAL; 753185377Ssam break; 754185377Ssam#endif 755185377Ssam#ifdef INET6 756185377Ssam case AF_INET6: 757185380Ssam if (src->sa_len != sizeof(struct sockaddr_in6)) 758185380Ssam return EINVAL; 759185377Ssam break; 760185377Ssam#endif 761185377Ssam default: 762185377Ssam return EAFNOSUPPORT; 763185377Ssam } 764185377Ssam switch (dst->sa_family) { 765185377Ssam#ifdef INET 766185377Ssam case AF_INET: 767185377Ssam if (dst->sa_len != sizeof(struct sockaddr_in)) 768185377Ssam return EINVAL; 769185377Ssam break; 770185377Ssam#endif 771185377Ssam#ifdef INET6 772185377Ssam case AF_INET6: 773185377Ssam if (dst->sa_len != sizeof(struct sockaddr_in6)) 774185377Ssam return EINVAL; 775185377Ssam break; 776185377Ssam#endif 777185377Ssam default: 778185377Ssam return EAFNOSUPPORT; 779185377Ssam } 780185377Ssam 781185377Ssam /* check sa_family looks sane for the cmd */ 782185377Ssam switch (cmd) { 783185377Ssam case SIOCSIFPHYADDR: 784185377Ssam if (src->sa_family == AF_INET) 785185377Ssam break; 786185377Ssam return EAFNOSUPPORT; 787185377Ssam#ifdef INET6 788185377Ssam case SIOCSIFPHYADDR_IN6: 789185377Ssam if (src->sa_family == AF_INET6) 790185377Ssam break; 791185377Ssam return EAFNOSUPPORT; 792185377Ssam#endif /* INET6 */ 793185377Ssam case SIOCSLIFPHYADDR: 794185377Ssam /* checks done in the above */ 795185377Ssam break; 796185377Ssam } 797185377Ssam 798185377Ssam error = gif_set_tunnel(GIF2IFP(sc), src, dst); 799185377Ssam break; 800185377Ssam 801185377Ssam#ifdef SIOCDIFPHYADDR 802185377Ssam case SIOCDIFPHYADDR: 803185377Ssam gif_delete_tunnel(GIF2IFP(sc)); 804185377Ssam break; 805185377Ssam#endif 806185377Ssam 807185377Ssam case SIOCGIFPSRCADDR: 808185377Ssam#ifdef INET6 809185377Ssam case SIOCGIFPSRCADDR_IN6: 810185377Ssam#endif /* INET6 */ 811185377Ssam if (sc->gif_psrc == NULL) { 812185377Ssam error = EADDRNOTAVAIL; 813185377Ssam goto bad; 814185377Ssam } 815185377Ssam src = sc->gif_psrc; 816185377Ssam switch (cmd) { 817185377Ssam#ifdef INET 818185377Ssam case SIOCGIFPSRCADDR: 819185377Ssam dst = &ifr->ifr_addr; 820185377Ssam size = sizeof(ifr->ifr_addr); 821185377Ssam break; 822185377Ssam#endif /* INET */ 823185377Ssam#ifdef INET6 824185907Ssam case SIOCGIFPSRCADDR_IN6: 825185377Ssam dst = (struct sockaddr *) 826185377Ssam &(((struct in6_ifreq *)data)->ifr_addr); 827185377Ssam size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 828185377Ssam break; 829185377Ssam#endif /* INET6 */ 830185377Ssam default: 831185377Ssam error = EADDRNOTAVAIL; 832185377Ssam goto bad; 833185377Ssam } 834185377Ssam if (src->sa_len > size) 835185377Ssam return EINVAL; 836185377Ssam bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 837185377Ssam#ifdef INET6 838185377Ssam if (dst->sa_family == AF_INET6) { 839185377Ssam error = sa6_recoverscope((struct sockaddr_in6 *)dst); 840185377Ssam if (error != 0) 841185377Ssam return (error); 842185377Ssam } 843185377Ssam#endif 844185377Ssam break; 845185380Ssam 846239801Sadrian case SIOCGIFPDSTADDR: 847239801Sadrian#ifdef INET6 848239801Sadrian case SIOCGIFPDSTADDR_IN6: 849239801Sadrian#endif /* INET6 */ 850185377Ssam if (sc->gif_pdst == NULL) { 851185377Ssam error = EADDRNOTAVAIL; 852185377Ssam goto bad; 853185377Ssam } 854185377Ssam src = sc->gif_pdst; 855185377Ssam switch (cmd) { 856185377Ssam#ifdef INET 857185377Ssam case SIOCGIFPDSTADDR: 858185377Ssam dst = &ifr->ifr_addr; 859185377Ssam size = sizeof(ifr->ifr_addr); 860185377Ssam break; 861185377Ssam#endif /* INET */ 862185377Ssam#ifdef INET6 863185377Ssam case SIOCGIFPDSTADDR_IN6: 864185377Ssam dst = (struct sockaddr *) 865185377Ssam &(((struct in6_ifreq *)data)->ifr_addr); 866185377Ssam size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 867185377Ssam break; 868185377Ssam#endif /* INET6 */ 869185377Ssam default: 870185377Ssam error = EADDRNOTAVAIL; 871185377Ssam goto bad; 872185377Ssam } 873185377Ssam if (src->sa_len > size) 874185377Ssam return EINVAL; 875185377Ssam error = prison_if(curthread->td_ucred, src); 876185377Ssam if (error != 0) 877222027Sadrian return (error); 878185377Ssam error = prison_if(curthread->td_ucred, dst); 879185377Ssam if (error != 0) 880185377Ssam return (error); 881185377Ssam bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 882185377Ssam#ifdef INET6 883185377Ssam if (dst->sa_family == AF_INET6) { 884185377Ssam error = sa6_recoverscope((struct sockaddr_in6 *)dst); 885185377Ssam if (error != 0) 886185377Ssam return (error); 887185377Ssam } 888185377Ssam#endif 889185377Ssam break; 890185377Ssam 891185377Ssam case SIOCGLIFPHYADDR: 892185377Ssam if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 893185377Ssam error = EADDRNOTAVAIL; 894185377Ssam goto bad; 895185377Ssam } 896185377Ssam 897185377Ssam /* copy src */ 898185377Ssam src = sc->gif_psrc; 899185377Ssam dst = (struct sockaddr *) 900222277Sadrian &(((struct if_laddrreq *)data)->addr); 901185377Ssam size = sizeof(((struct if_laddrreq *)data)->addr); 902222277Sadrian if (src->sa_len > size) 903185377Ssam return EINVAL; 904185377Ssam bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 905222277Sadrian 906222277Sadrian /* copy dst */ 907222277Sadrian src = sc->gif_pdst; 908222277Sadrian dst = (struct sockaddr *) 909222277Sadrian &(((struct if_laddrreq *)data)->dstaddr); 910185377Ssam size = sizeof(((struct if_laddrreq *)data)->dstaddr); 911185377Ssam if (src->sa_len > size) 912185377Ssam return EINVAL; 913185377Ssam bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 914185377Ssam break; 915185377Ssam 916185377Ssam case SIOCSIFFLAGS: 917185377Ssam /* if_ioctl() takes care of it */ 918185377Ssam break; 919185377Ssam 920185377Ssam case GIFGOPTS: 921185377Ssam options = sc->gif_options; 922185377Ssam error = copyout(&options, ifr->ifr_data, 923185377Ssam sizeof(options)); 924185377Ssam break; 925185377Ssam 926185377Ssam case GIFSOPTS: 927185377Ssam if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0) 928185377Ssam break; 929185377Ssam error = copyin(ifr->ifr_data, &options, sizeof(options)); 930185377Ssam if (error) 931185377Ssam break; 932185377Ssam if (options & ~GIF_OPTMASK) 933185377Ssam error = EINVAL; 934185377Ssam else 935185377Ssam sc->gif_options = options; 936185377Ssam break; 937185377Ssam 938185377Ssam default: 939185377Ssam error = EINVAL; 940185377Ssam break; 941185377Ssam } 942185377Ssam bad: 943185377Ssam return error; 944185377Ssam} 945185377Ssam 946185377Ssam/* 947185377Ssam * XXXRW: There's a general event-ordering issue here: the code to check 948185377Ssam * if a given tunnel is already present happens before we perform a 949185377Ssam * potentially blocking setup of the tunnel. This code needs to be 950185377Ssam * re-ordered so that the check and replacement can be atomic using 951185377Ssam * a mutex. 952185377Ssam */ 953185377Ssamint 954219771Sadriangif_set_tunnel(ifp, src, dst) 955185377Ssam struct ifnet *ifp; 956185377Ssam struct sockaddr *src; 957239801Sadrian struct sockaddr *dst; 958239801Sadrian{ 959239801Sadrian struct gif_softc *sc = ifp->if_softc; 960239801Sadrian struct gif_softc *sc2; 961239801Sadrian struct sockaddr *osrc, *odst, *sa; 962239801Sadrian int error = 0; 963240001Sadrian 964240001Sadrian mtx_lock(&gif_mtx); 965240001Sadrian LIST_FOREACH(sc2, &V_gif_softc_list, gif_list) { 966240001Sadrian if (sc2 == sc) 967240001Sadrian continue; 968240001Sadrian if (!sc2->gif_pdst || !sc2->gif_psrc) 969240001Sadrian continue; 970239801Sadrian if (sc2->gif_pdst->sa_family != dst->sa_family || 971239801Sadrian sc2->gif_pdst->sa_len != dst->sa_len || 972239801Sadrian sc2->gif_psrc->sa_family != src->sa_family || 973239801Sadrian sc2->gif_psrc->sa_len != src->sa_len) 974239801Sadrian continue; 975239801Sadrian 976239801Sadrian /* 977239801Sadrian * Disallow parallel tunnels unless instructed 978239801Sadrian * otherwise. 979239801Sadrian */ 980239801Sadrian if (!V_parallel_tunnels && 981239801Sadrian bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 982239801Sadrian bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 983239801Sadrian error = EADDRNOTAVAIL; 984185380Ssam mtx_unlock(&gif_mtx); 985185377Ssam goto bad; 986185377Ssam } 987185377Ssam 988185377Ssam /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 989185377Ssam } 990185377Ssam mtx_unlock(&gif_mtx); 991185377Ssam 992185377Ssam /* XXX we can detach from both, but be polite just in case */ 993185377Ssam if (sc->gif_psrc) 994185377Ssam switch (sc->gif_psrc->sa_family) { 995185377Ssam#ifdef INET 996185377Ssam case AF_INET: 997185377Ssam (void)in_gif_detach(sc); 998185377Ssam break; 999185377Ssam#endif 1000185377Ssam#ifdef INET6 1001185377Ssam case AF_INET6: 1002185377Ssam (void)in6_gif_detach(sc); 1003185377Ssam break; 1004185377Ssam#endif 1005185377Ssam } 1006185377Ssam 1007185377Ssam osrc = sc->gif_psrc; 1008185377Ssam sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 1009185377Ssam bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 1010185377Ssam sc->gif_psrc = sa; 1011185377Ssam 1012185377Ssam odst = sc->gif_pdst; 1013185377Ssam sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 1014185377Ssam bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 1015185377Ssam sc->gif_pdst = sa; 1016185377Ssam 1017185377Ssam switch (sc->gif_psrc->sa_family) { 1018222277Sadrian#ifdef INET 1019222277Sadrian case AF_INET: 1020185377Ssam error = in_gif_attach(sc); 1021185377Ssam break; 1022185377Ssam#endif 1023185377Ssam#ifdef INET6 1024185377Ssam case AF_INET6: 1025185377Ssam /* 1026185377Ssam * Check validity of the scope zone ID of the addresses, and 1027185377Ssam * convert it into the kernel internal form if necessary. 1028185377Ssam */ 1029185377Ssam error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_psrc, 0); 1030222265Sadrian if (error != 0) 1031185377Ssam break; 1032185377Ssam error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_pdst, 0); 1033185377Ssam if (error != 0) 1034185377Ssam break; 1035185377Ssam error = in6_gif_attach(sc); 1036185377Ssam break; 1037185377Ssam#endif 1038185377Ssam } 1039185377Ssam if (error) { 1040185377Ssam /* rollback */ 1041185377Ssam free((caddr_t)sc->gif_psrc, M_IFADDR); 1042185377Ssam free((caddr_t)sc->gif_pdst, M_IFADDR); 1043185377Ssam sc->gif_psrc = osrc; 1044185377Ssam sc->gif_pdst = odst; 1045185377Ssam goto bad; 1046185377Ssam } 1047185377Ssam 1048185377Ssam if (osrc) 1049185377Ssam free((caddr_t)osrc, M_IFADDR); 1050185377Ssam if (odst) 1051185377Ssam free((caddr_t)odst, M_IFADDR); 1052185377Ssam 1053185377Ssam bad: 1054185377Ssam if (sc->gif_psrc && sc->gif_pdst) 1055185377Ssam ifp->if_drv_flags |= IFF_DRV_RUNNING; 1056185377Ssam else 1057185377Ssam ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1058185377Ssam 1059185377Ssam return error; 1060185377Ssam} 1061185377Ssam 1062185377Ssamvoid 1063185377Ssamgif_delete_tunnel(ifp) 1064185377Ssam struct ifnet *ifp; 1065185377Ssam{ 1066185377Ssam struct gif_softc *sc = ifp->if_softc; 1067185377Ssam 1068185377Ssam if (sc->gif_psrc) { 1069185377Ssam free((caddr_t)sc->gif_psrc, M_IFADDR); 1070185377Ssam sc->gif_psrc = NULL; 1071185377Ssam } 1072185377Ssam if (sc->gif_pdst) { 1073185377Ssam free((caddr_t)sc->gif_pdst, M_IFADDR); 1074185377Ssam sc->gif_pdst = NULL; 1075185377Ssam } 1076185377Ssam /* it is safe to detach from both */ 1077185377Ssam#ifdef INET 1078185377Ssam (void)in_gif_detach(sc); 1079185377Ssam#endif 1080185377Ssam#ifdef INET6 1081185377Ssam (void)in6_gif_detach(sc); 1082185377Ssam#endif 1083185377Ssam ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1084185377Ssam} 1085185377Ssam