1 /* $NetBSD: if_gif.c,v 1.82 2013/03/01 18:25:56 joerg Exp $ */ 2 /* $KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.82 2013/03/01 18:25:56 joerg Exp $"); 35 36 #include "opt_inet.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/mbuf.h> 42 #include <sys/socket.h> 43 #include <sys/sockio.h> 44 #include <sys/errno.h> 45 #include <sys/ioctl.h> 46 #include <sys/time.h> 47 #include <sys/syslog.h> 48 #include <sys/proc.h> 49 #include <sys/protosw.h> 50 #include <sys/cpu.h> 51 #include <sys/intr.h> 52 53 #include <net/if.h> 54 #include <net/if_types.h> 55 #include <net/netisr.h> 56 #include <net/route.h> 57 #include <net/bpf.h> 58 59 #include <netinet/in.h> 60 #include <netinet/in_systm.h> 61 #include <netinet/ip.h> 62 #ifdef INET 63 #include <netinet/in_var.h> 64 #endif /* INET */ 65 #include <netinet/in_gif.h> 66 67 #ifdef INET6 68 #ifndef INET 69 #include <netinet/in.h> 70 #endif 71 #include <netinet6/in6_var.h> 72 #include <netinet/ip6.h> 73 #include <netinet6/ip6_var.h> 74 #include <netinet6/in6_gif.h> 75 #include <netinet6/ip6protosw.h> 76 #endif /* INET6 */ 77 78 #include <netinet/ip_encap.h> 79 #include <net/if_gif.h> 80 81 82 #include <net/net_osdep.h> 83 84 void gifattach(int); 85 static void gifintr(void *); 86 87 /* 88 * gif global variable definitions 89 */ 90 LIST_HEAD(, gif_softc) gif_softc_list; /* XXX should be static */ 91 92 static int gif_clone_create(struct if_clone *, int); 93 static int gif_clone_destroy(struct ifnet *); 94 95 static struct if_clone gif_cloner = 96 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); 97 98 #ifndef MAX_GIF_NEST 99 /* 100 * This macro controls the upper limitation on nesting of gif tunnels. 101 * Since, setting a large value to this macro with a careless configuration 102 * may introduce system crash, we don't allow any nestings by default. 103 * If you need to configure nested gif tunnels, you can define this macro 104 * in your kernel configuration file. However, if you do so, please be 105 * careful to configure the tunnels so that it won't make a loop. 106 */ 107 #define MAX_GIF_NEST 1 108 #endif 109 static int max_gif_nesting = MAX_GIF_NEST; 110 111 /* ARGSUSED */ 112 void 113 gifattach(int count) 114 { 115 116 LIST_INIT(&gif_softc_list); 117 if_clone_attach(&gif_cloner); 118 } 119 120 static int 121 gif_clone_create(struct if_clone *ifc, int unit) 122 { 123 struct gif_softc *sc; 124 125 sc = malloc(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK|M_ZERO); 126 127 if_initname(&sc->gif_if, ifc->ifc_name, unit); 128 129 gifattach0(sc); 130 131 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 132 return (0); 133 } 134 135 void 136 gifattach0(struct gif_softc *sc) 137 { 138 139 sc->encap_cookie4 = sc->encap_cookie6 = NULL; 140 141 sc->gif_if.if_addrlen = 0; 142 sc->gif_if.if_mtu = GIF_MTU; 143 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 144 sc->gif_if.if_ioctl = gif_ioctl; 145 sc->gif_if.if_output = gif_output; 146 sc->gif_if.if_type = IFT_GIF; 147 sc->gif_if.if_dlt = DLT_NULL; 148 sc->gif_if.if_softc = sc; 149 IFQ_SET_READY(&sc->gif_if.if_snd); 150 if_attach(&sc->gif_if); 151 if_alloc_sadl(&sc->gif_if); 152 bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 153 } 154 155 static int 156 gif_clone_destroy(struct ifnet *ifp) 157 { 158 struct gif_softc *sc = (void *) ifp; 159 160 gif_delete_tunnel(&sc->gif_if); 161 LIST_REMOVE(sc, gif_list); 162 #ifdef INET6 163 encap_detach(sc->encap_cookie6); 164 #endif 165 #ifdef INET 166 encap_detach(sc->encap_cookie4); 167 #endif 168 169 bpf_detach(ifp); 170 if_detach(ifp); 171 rtcache_free(&sc->gif_ro); 172 173 free(sc, M_DEVBUF); 174 175 return (0); 176 } 177 178 #ifdef GIF_ENCAPCHECK 179 int 180 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg) 181 { 182 struct ip ip; 183 struct gif_softc *sc; 184 185 sc = arg; 186 if (sc == NULL) 187 return 0; 188 189 if ((sc->gif_if.if_flags & IFF_UP) == 0) 190 return 0; 191 192 /* no physical address */ 193 if (!sc->gif_psrc || !sc->gif_pdst) 194 return 0; 195 196 switch (proto) { 197 #ifdef INET 198 case IPPROTO_IPV4: 199 break; 200 #endif 201 #ifdef INET6 202 case IPPROTO_IPV6: 203 break; 204 #endif 205 default: 206 return 0; 207 } 208 209 /* Bail on short packets */ 210 KASSERT(m->m_flags & M_PKTHDR); 211 if (m->m_pkthdr.len < sizeof(ip)) 212 return 0; 213 214 m_copydata(m, 0, sizeof(ip), &ip); 215 216 switch (ip.ip_v) { 217 #ifdef INET 218 case 4: 219 if (sc->gif_psrc->sa_family != AF_INET || 220 sc->gif_pdst->sa_family != AF_INET) 221 return 0; 222 return gif_encapcheck4(m, off, proto, arg); 223 #endif 224 #ifdef INET6 225 case 6: 226 if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 227 return 0; 228 if (sc->gif_psrc->sa_family != AF_INET6 || 229 sc->gif_pdst->sa_family != AF_INET6) 230 return 0; 231 return gif_encapcheck6(m, off, proto, arg); 232 #endif 233 default: 234 return 0; 235 } 236 } 237 #endif 238 239 int 240 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 241 struct rtentry *rt) 242 { 243 struct gif_softc *sc = ifp->if_softc; 244 int error = 0; 245 static int called = 0; /* XXX: MUTEX */ 246 ALTQ_DECL(struct altq_pktattr pktattr;) 247 int s; 248 249 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr); 250 251 /* 252 * gif may cause infinite recursion calls when misconfigured. 253 * We'll prevent this by introducing upper limit. 254 * XXX: this mechanism may introduce another problem about 255 * mutual exclusion of the variable CALLED, especially if we 256 * use kernel thread. 257 */ 258 if (++called > max_gif_nesting) { 259 log(LOG_NOTICE, 260 "gif_output: recursively called too many times(%d)\n", 261 called); 262 m_freem(m); 263 error = EIO; /* is there better errno? */ 264 goto end; 265 } 266 267 m->m_flags &= ~(M_BCAST|M_MCAST); 268 if (!(ifp->if_flags & IFF_UP) || 269 sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 270 m_freem(m); 271 error = ENETDOWN; 272 goto end; 273 } 274 275 /* XXX should we check if our outer source is legal? */ 276 277 /* use DLT_NULL encapsulation here to pass inner af type */ 278 M_PREPEND(m, sizeof(int), M_DONTWAIT); 279 if (!m) { 280 error = ENOBUFS; 281 goto end; 282 } 283 *mtod(m, int *) = dst->sa_family; 284 285 /* Clear checksum-offload flags. */ 286 m->m_pkthdr.csum_flags = 0; 287 m->m_pkthdr.csum_data = 0; 288 289 s = splnet(); 290 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error); 291 if (error) { 292 splx(s); 293 goto end; 294 } 295 splx(s); 296 297 softint_schedule(sc->gif_si); 298 error = 0; 299 300 end: 301 called = 0; /* reset recursion counter */ 302 if (error) 303 ifp->if_oerrors++; 304 return error; 305 } 306 307 static void 308 gifintr(void *arg) 309 { 310 struct gif_softc *sc; 311 struct ifnet *ifp; 312 struct mbuf *m; 313 int family; 314 int len; 315 int s; 316 int error; 317 318 sc = arg; 319 ifp = &sc->gif_if; 320 321 /* output processing */ 322 while (1) { 323 s = splnet(); 324 IFQ_DEQUEUE(&sc->gif_if.if_snd, m); 325 splx(s); 326 if (m == NULL) 327 break; 328 329 /* grab and chop off inner af type */ 330 if (sizeof(int) > m->m_len) { 331 m = m_pullup(m, sizeof(int)); 332 if (!m) { 333 ifp->if_oerrors++; 334 continue; 335 } 336 } 337 family = *mtod(m, int *); 338 bpf_mtap(ifp, m); 339 m_adj(m, sizeof(int)); 340 341 len = m->m_pkthdr.len; 342 343 /* dispatch to output logic based on outer AF */ 344 switch (sc->gif_psrc->sa_family) { 345 #ifdef INET 346 case AF_INET: 347 error = in_gif_output(ifp, family, m); 348 break; 349 #endif 350 #ifdef INET6 351 case AF_INET6: 352 error = in6_gif_output(ifp, family, m); 353 break; 354 #endif 355 default: 356 m_freem(m); 357 error = ENETDOWN; 358 break; 359 } 360 361 if (error) 362 ifp->if_oerrors++; 363 else { 364 ifp->if_opackets++; 365 ifp->if_obytes += len; 366 } 367 } 368 } 369 370 void 371 gif_input(struct mbuf *m, int af, struct ifnet *ifp) 372 { 373 int s, isr; 374 struct ifqueue *ifq = NULL; 375 376 if (ifp == NULL) { 377 /* just in case */ 378 m_freem(m); 379 return; 380 } 381 382 m->m_pkthdr.rcvif = ifp; 383 384 bpf_mtap_af(ifp, af, m); 385 386 /* 387 * Put the packet to the network layer input queue according to the 388 * specified address family. 389 * Note: older versions of gif_input directly called network layer 390 * input functions, e.g. ip6_input, here. We changed the policy to 391 * prevent too many recursive calls of such input functions, which 392 * might cause kernel panic. But the change may introduce another 393 * problem; if the input queue is full, packets are discarded. 394 * The kernel stack overflow really happened, and we believed 395 * queue-full rarely occurs, so we changed the policy. 396 */ 397 switch (af) { 398 #ifdef INET 399 case AF_INET: 400 ifq = &ipintrq; 401 isr = NETISR_IP; 402 break; 403 #endif 404 #ifdef INET6 405 case AF_INET6: 406 ifq = &ip6intrq; 407 isr = NETISR_IPV6; 408 break; 409 #endif 410 default: 411 m_freem(m); 412 return; 413 } 414 415 s = splnet(); 416 if (IF_QFULL(ifq)) { 417 IF_DROP(ifq); /* update statistics */ 418 m_freem(m); 419 splx(s); 420 return; 421 } 422 ifp->if_ipackets++; 423 ifp->if_ibytes += m->m_pkthdr.len; 424 IF_ENQUEUE(ifq, m); 425 /* we need schednetisr since the address family may change */ 426 schednetisr(isr); 427 splx(s); 428 } 429 430 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 431 int 432 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data) 433 { 434 struct gif_softc *sc = ifp->if_softc; 435 struct ifreq *ifr = (struct ifreq*)data; 436 int error = 0, size; 437 struct sockaddr *dst, *src; 438 439 switch (cmd) { 440 case SIOCINITIFADDR: 441 ifp->if_flags |= IFF_UP; 442 break; 443 444 case SIOCADDMULTI: 445 case SIOCDELMULTI: 446 switch (ifr->ifr_addr.sa_family) { 447 #ifdef INET 448 case AF_INET: /* IP supports Multicast */ 449 break; 450 #endif /* INET */ 451 #ifdef INET6 452 case AF_INET6: /* IP6 supports Multicast */ 453 break; 454 #endif /* INET6 */ 455 default: /* Other protocols doesn't support Multicast */ 456 error = EAFNOSUPPORT; 457 break; 458 } 459 break; 460 461 case SIOCSIFMTU: 462 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) 463 return EINVAL; 464 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 465 error = 0; 466 break; 467 468 #ifdef INET 469 case SIOCSIFPHYADDR: 470 #endif 471 #ifdef INET6 472 case SIOCSIFPHYADDR_IN6: 473 #endif /* INET6 */ 474 case SIOCSLIFPHYADDR: 475 switch (cmd) { 476 #ifdef INET 477 case SIOCSIFPHYADDR: 478 src = (struct sockaddr *) 479 &(((struct in_aliasreq *)data)->ifra_addr); 480 dst = (struct sockaddr *) 481 &(((struct in_aliasreq *)data)->ifra_dstaddr); 482 break; 483 #endif 484 #ifdef INET6 485 case SIOCSIFPHYADDR_IN6: 486 src = (struct sockaddr *) 487 &(((struct in6_aliasreq *)data)->ifra_addr); 488 dst = (struct sockaddr *) 489 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 490 break; 491 #endif 492 case SIOCSLIFPHYADDR: 493 src = (struct sockaddr *) 494 &(((struct if_laddrreq *)data)->addr); 495 dst = (struct sockaddr *) 496 &(((struct if_laddrreq *)data)->dstaddr); 497 break; 498 default: 499 return EINVAL; 500 } 501 502 /* sa_family must be equal */ 503 if (src->sa_family != dst->sa_family) 504 return EINVAL; 505 506 /* validate sa_len */ 507 switch (src->sa_family) { 508 #ifdef INET 509 case AF_INET: 510 if (src->sa_len != sizeof(struct sockaddr_in)) 511 return EINVAL; 512 break; 513 #endif 514 #ifdef INET6 515 case AF_INET6: 516 if (src->sa_len != sizeof(struct sockaddr_in6)) 517 return EINVAL; 518 break; 519 #endif 520 default: 521 return EAFNOSUPPORT; 522 } 523 switch (dst->sa_family) { 524 #ifdef INET 525 case AF_INET: 526 if (dst->sa_len != sizeof(struct sockaddr_in)) 527 return EINVAL; 528 break; 529 #endif 530 #ifdef INET6 531 case AF_INET6: 532 if (dst->sa_len != sizeof(struct sockaddr_in6)) 533 return EINVAL; 534 break; 535 #endif 536 default: 537 return EAFNOSUPPORT; 538 } 539 540 /* check sa_family looks sane for the cmd */ 541 switch (cmd) { 542 case SIOCSIFPHYADDR: 543 if (src->sa_family == AF_INET) 544 break; 545 return EAFNOSUPPORT; 546 #ifdef INET6 547 case SIOCSIFPHYADDR_IN6: 548 if (src->sa_family == AF_INET6) 549 break; 550 return EAFNOSUPPORT; 551 #endif /* INET6 */ 552 case SIOCSLIFPHYADDR: 553 /* checks done in the above */ 554 break; 555 } 556 557 error = gif_set_tunnel(&sc->gif_if, src, dst); 558 break; 559 560 #ifdef SIOCDIFPHYADDR 561 case SIOCDIFPHYADDR: 562 gif_delete_tunnel(&sc->gif_if); 563 break; 564 #endif 565 566 case SIOCGIFPSRCADDR: 567 #ifdef INET6 568 case SIOCGIFPSRCADDR_IN6: 569 #endif /* INET6 */ 570 if (sc->gif_psrc == NULL) { 571 error = EADDRNOTAVAIL; 572 goto bad; 573 } 574 src = sc->gif_psrc; 575 switch (cmd) { 576 #ifdef INET 577 case SIOCGIFPSRCADDR: 578 dst = &ifr->ifr_addr; 579 size = sizeof(ifr->ifr_addr); 580 break; 581 #endif /* INET */ 582 #ifdef INET6 583 case SIOCGIFPSRCADDR_IN6: 584 dst = (struct sockaddr *) 585 &(((struct in6_ifreq *)data)->ifr_addr); 586 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 587 break; 588 #endif /* INET6 */ 589 default: 590 error = EADDRNOTAVAIL; 591 goto bad; 592 } 593 if (src->sa_len > size) 594 return EINVAL; 595 memcpy(dst, src, src->sa_len); 596 break; 597 598 case SIOCGIFPDSTADDR: 599 #ifdef INET6 600 case SIOCGIFPDSTADDR_IN6: 601 #endif /* INET6 */ 602 if (sc->gif_pdst == NULL) { 603 error = EADDRNOTAVAIL; 604 goto bad; 605 } 606 src = sc->gif_pdst; 607 switch (cmd) { 608 #ifdef INET 609 case SIOCGIFPDSTADDR: 610 dst = &ifr->ifr_addr; 611 size = sizeof(ifr->ifr_addr); 612 break; 613 #endif /* INET */ 614 #ifdef INET6 615 case SIOCGIFPDSTADDR_IN6: 616 dst = (struct sockaddr *) 617 &(((struct in6_ifreq *)data)->ifr_addr); 618 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 619 break; 620 #endif /* INET6 */ 621 default: 622 error = EADDRNOTAVAIL; 623 goto bad; 624 } 625 if (src->sa_len > size) 626 return EINVAL; 627 memcpy(dst, src, src->sa_len); 628 break; 629 630 case SIOCGLIFPHYADDR: 631 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 632 error = EADDRNOTAVAIL; 633 goto bad; 634 } 635 636 /* copy src */ 637 src = sc->gif_psrc; 638 dst = (struct sockaddr *) 639 &(((struct if_laddrreq *)data)->addr); 640 size = sizeof(((struct if_laddrreq *)data)->addr); 641 if (src->sa_len > size) 642 return EINVAL; 643 memcpy(dst, src, src->sa_len); 644 645 /* copy dst */ 646 src = sc->gif_pdst; 647 dst = (struct sockaddr *) 648 &(((struct if_laddrreq *)data)->dstaddr); 649 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 650 if (src->sa_len > size) 651 return EINVAL; 652 memcpy(dst, src, src->sa_len); 653 break; 654 655 default: 656 return ifioctl_common(ifp, cmd, data); 657 } 658 bad: 659 return error; 660 } 661 662 int 663 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) 664 { 665 struct gif_softc *sc = ifp->if_softc; 666 struct gif_softc *sc2; 667 struct sockaddr *osrc, *odst; 668 int s; 669 int error; 670 671 s = splsoftnet(); 672 673 LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 674 if (sc2 == sc) 675 continue; 676 if (!sc2->gif_pdst || !sc2->gif_psrc) 677 continue; 678 /* can't configure same pair of address onto two gifs */ 679 if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 && 680 sockaddr_cmp(sc2->gif_psrc, src) == 0) { 681 error = EADDRNOTAVAIL; 682 goto bad; 683 } 684 685 /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 686 } 687 688 if (sc->gif_si) { 689 softint_disestablish(sc->gif_si); 690 sc->gif_si = NULL; 691 } 692 693 /* XXX we can detach from both, but be polite just in case */ 694 if (sc->gif_psrc) 695 switch (sc->gif_psrc->sa_family) { 696 #ifdef INET 697 case AF_INET: 698 (void)in_gif_detach(sc); 699 break; 700 #endif 701 #ifdef INET6 702 case AF_INET6: 703 (void)in6_gif_detach(sc); 704 break; 705 #endif 706 } 707 708 sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc); 709 if (sc->gif_si == NULL) { 710 error = ENOMEM; 711 goto bad; 712 } 713 714 osrc = sc->gif_psrc; 715 sc->gif_psrc = sockaddr_dup(src, M_WAITOK); 716 717 odst = sc->gif_pdst; 718 sc->gif_pdst = sockaddr_dup(dst, M_WAITOK); 719 720 switch (sc->gif_psrc->sa_family) { 721 #ifdef INET 722 case AF_INET: 723 error = in_gif_attach(sc); 724 break; 725 #endif 726 #ifdef INET6 727 case AF_INET6: 728 error = in6_gif_attach(sc); 729 break; 730 #endif 731 default: 732 error = EINVAL; 733 break; 734 } 735 if (error) { 736 /* rollback */ 737 sockaddr_free(sc->gif_psrc); 738 sockaddr_free(sc->gif_pdst); 739 sc->gif_psrc = osrc; 740 sc->gif_pdst = odst; 741 goto bad; 742 } 743 744 if (osrc) 745 sockaddr_free(osrc); 746 if (odst) 747 sockaddr_free(odst); 748 749 if (sc->gif_psrc && sc->gif_pdst) 750 ifp->if_flags |= IFF_RUNNING; 751 else 752 ifp->if_flags &= ~IFF_RUNNING; 753 splx(s); 754 755 return 0; 756 757 bad: 758 if (sc->gif_si) { 759 softint_disestablish(sc->gif_si); 760 sc->gif_si = NULL; 761 } 762 if (sc->gif_psrc && sc->gif_pdst) 763 ifp->if_flags |= IFF_RUNNING; 764 else 765 ifp->if_flags &= ~IFF_RUNNING; 766 splx(s); 767 768 return error; 769 } 770 771 void 772 gif_delete_tunnel(struct ifnet *ifp) 773 { 774 struct gif_softc *sc = ifp->if_softc; 775 int s; 776 777 s = splsoftnet(); 778 779 if (sc->gif_si) { 780 softint_disestablish(sc->gif_si); 781 sc->gif_si = NULL; 782 } 783 if (sc->gif_psrc) { 784 sockaddr_free(sc->gif_psrc); 785 sc->gif_psrc = NULL; 786 } 787 if (sc->gif_pdst) { 788 sockaddr_free(sc->gif_pdst); 789 sc->gif_pdst = NULL; 790 } 791 /* it is safe to detach from both */ 792 #ifdef INET 793 (void)in_gif_detach(sc); 794 #endif 795 #ifdef INET6 796 (void)in6_gif_detach(sc); 797 #endif 798 799 if (sc->gif_psrc && sc->gif_pdst) 800 ifp->if_flags |= IFF_RUNNING; 801 else 802 ifp->if_flags &= ~IFF_RUNNING; 803 splx(s); 804 } 805