1 /* $NetBSD: if_gif.c,v 1.105 2016/01/18 06:08:26 knakahara 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.105 2016/01/18 06:08:26 knakahara Exp $"); 35 36 #ifdef _KERNEL_OPT 37 #include "opt_inet.h" 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/mbuf.h> 44 #include <sys/socket.h> 45 #include <sys/sockio.h> 46 #include <sys/errno.h> 47 #include <sys/ioctl.h> 48 #include <sys/time.h> 49 #include <sys/socketvar.h> 50 #include <sys/syslog.h> 51 #include <sys/proc.h> 52 #include <sys/cpu.h> 53 #include <sys/intr.h> 54 #include <sys/kmem.h> 55 #include <sys/sysctl.h> 56 57 #include <net/if.h> 58 #include <net/if_types.h> 59 #include <net/netisr.h> 60 #include <net/route.h> 61 #include <net/bpf.h> 62 63 #include <netinet/in.h> 64 #include <netinet/in_systm.h> 65 #include <netinet/ip.h> 66 #ifdef INET 67 #include <netinet/in_var.h> 68 #endif /* INET */ 69 #include <netinet/in_gif.h> 70 71 #ifdef INET6 72 #ifndef INET 73 #include <netinet/in.h> 74 #endif 75 #include <netinet6/in6_var.h> 76 #include <netinet/ip6.h> 77 #include <netinet6/ip6_var.h> 78 #include <netinet6/in6_gif.h> 79 #endif /* INET6 */ 80 81 #include <netinet/ip_encap.h> 82 #include <net/if_gif.h> 83 84 #include <net/net_osdep.h> 85 86 #include "ioconf.h" 87 88 static void gifintr(void *); 89 90 /* 91 * gif global variable definitions 92 */ 93 LIST_HEAD(, gif_softc) gif_softc_list; /* XXX should be static */ 94 95 static void gif_sysctl_setup(struct sysctllog **); 96 97 static int gif_clone_create(struct if_clone *, int); 98 static int gif_clone_destroy(struct ifnet *); 99 static int gif_check_nesting(struct ifnet *, struct mbuf *); 100 101 static int gif_encap_attach(struct gif_softc *); 102 static int gif_encap_detach(struct gif_softc *); 103 104 static struct if_clone gif_cloner = 105 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); 106 107 #ifndef MAX_GIF_NEST 108 /* 109 * This macro controls the upper limitation on nesting of gif tunnels. 110 * Since, setting a large value to this macro with a careless configuration 111 * may introduce system crash, we don't allow any nestings by default. 112 * If you need to configure nested gif tunnels, you can define this macro 113 * in your kernel configuration file. However, if you do so, please be 114 * careful to configure the tunnels so that it won't make a loop. 115 */ 116 #define MAX_GIF_NEST 1 117 #endif 118 static int max_gif_nesting = MAX_GIF_NEST; 119 120 static void 121 gif_sysctl_setup(struct sysctllog **clog) 122 { 123 124 #ifdef INET 125 sysctl_createv(clog, 0, NULL, NULL, 126 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 127 CTLTYPE_INT, "gifttl", 128 SYSCTL_DESCR("Default TTL for a gif tunnel datagram"), 129 NULL, 0, &ip_gif_ttl, 0, 130 CTL_NET, PF_INET, IPPROTO_IP, 131 IPCTL_GIF_TTL, CTL_EOL); 132 #endif 133 #ifdef INET6 134 sysctl_createv(clog, 0, NULL, NULL, 135 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 136 CTLTYPE_INT, "gifhlim", 137 SYSCTL_DESCR("Default hop limit for a gif tunnel datagram"), 138 NULL, 0, &ip6_gif_hlim, 0, 139 CTL_NET, PF_INET6, IPPROTO_IPV6, 140 IPV6CTL_GIF_HLIM, CTL_EOL); 141 #endif 142 } 143 144 /* ARGSUSED */ 145 void 146 gifattach(int count) 147 { 148 149 LIST_INIT(&gif_softc_list); 150 if_clone_attach(&gif_cloner); 151 152 gif_sysctl_setup(NULL); 153 } 154 155 static int 156 gif_clone_create(struct if_clone *ifc, int unit) 157 { 158 struct gif_softc *sc; 159 160 sc = kmem_zalloc(sizeof(struct gif_softc), KM_SLEEP); 161 if (sc == NULL) 162 return ENOMEM; 163 164 if_initname(&sc->gif_if, ifc->ifc_name, unit); 165 166 gifattach0(sc); 167 168 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 169 return (0); 170 } 171 172 void 173 gifattach0(struct gif_softc *sc) 174 { 175 176 sc->encap_cookie4 = sc->encap_cookie6 = NULL; 177 178 sc->gif_if.if_addrlen = 0; 179 sc->gif_if.if_mtu = GIF_MTU; 180 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 181 sc->gif_if.if_ioctl = gif_ioctl; 182 sc->gif_if.if_output = gif_output; 183 sc->gif_if.if_type = IFT_GIF; 184 sc->gif_if.if_dlt = DLT_NULL; 185 sc->gif_if.if_softc = sc; 186 IFQ_SET_READY(&sc->gif_if.if_snd); 187 if_attach(&sc->gif_if); 188 if_alloc_sadl(&sc->gif_if); 189 bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 190 } 191 192 static int 193 gif_clone_destroy(struct ifnet *ifp) 194 { 195 struct gif_softc *sc = (void *) ifp; 196 197 LIST_REMOVE(sc, gif_list); 198 199 gif_delete_tunnel(&sc->gif_if); 200 bpf_detach(ifp); 201 if_detach(ifp); 202 rtcache_free(&sc->gif_ro); 203 204 kmem_free(sc, sizeof(struct gif_softc)); 205 206 return (0); 207 } 208 209 #ifdef GIF_ENCAPCHECK 210 int 211 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg) 212 { 213 struct ip ip; 214 struct gif_softc *sc; 215 216 sc = arg; 217 if (sc == NULL) 218 return 0; 219 220 if ((sc->gif_if.if_flags & IFF_UP) == 0) 221 return 0; 222 223 /* no physical address */ 224 if (!sc->gif_psrc || !sc->gif_pdst) 225 return 0; 226 227 switch (proto) { 228 #ifdef INET 229 case IPPROTO_IPV4: 230 break; 231 #endif 232 #ifdef INET6 233 case IPPROTO_IPV6: 234 break; 235 #endif 236 default: 237 return 0; 238 } 239 240 /* Bail on short packets */ 241 KASSERT(m->m_flags & M_PKTHDR); 242 if (m->m_pkthdr.len < sizeof(ip)) 243 return 0; 244 245 m_copydata(m, 0, sizeof(ip), &ip); 246 247 switch (ip.ip_v) { 248 #ifdef INET 249 case 4: 250 if (sc->gif_psrc->sa_family != AF_INET || 251 sc->gif_pdst->sa_family != AF_INET) 252 return 0; 253 return gif_encapcheck4(m, off, proto, arg); 254 #endif 255 #ifdef INET6 256 case 6: 257 if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 258 return 0; 259 if (sc->gif_psrc->sa_family != AF_INET6 || 260 sc->gif_pdst->sa_family != AF_INET6) 261 return 0; 262 return gif_encapcheck6(m, off, proto, arg); 263 #endif 264 default: 265 return 0; 266 } 267 } 268 #endif 269 270 /* 271 * gif may cause infinite recursion calls when misconfigured. 272 * We'll prevent this by introducing upper limit. 273 */ 274 static int 275 gif_check_nesting(struct ifnet *ifp, struct mbuf *m) 276 { 277 struct m_tag *mtag; 278 int *count; 279 280 mtag = m_tag_find(m, PACKET_TAG_TUNNEL_INFO, NULL); 281 if (mtag != NULL) { 282 count = (int *)(mtag + 1); 283 if (++(*count) > max_gif_nesting) { 284 log(LOG_NOTICE, 285 "%s: recursively called too many times(%d)\n", 286 if_name(ifp), 287 *count); 288 return EIO; 289 } 290 } else { 291 mtag = m_tag_get(PACKET_TAG_TUNNEL_INFO, sizeof(*count), 292 M_NOWAIT); 293 if (mtag != NULL) { 294 m_tag_prepend(m, mtag); 295 count = (int *)(mtag + 1); 296 *count = 0; 297 } else { 298 log(LOG_DEBUG, 299 "%s: m_tag_get() failed, recursion calls are not prevented.\n", 300 if_name(ifp)); 301 } 302 } 303 304 return 0; 305 } 306 307 int 308 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 309 struct rtentry *rt) 310 { 311 struct gif_softc *sc = ifp->if_softc; 312 int error = 0; 313 ALTQ_DECL(struct altq_pktattr pktattr;) 314 int s; 315 316 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr); 317 318 if ((error = gif_check_nesting(ifp, m)) != 0) { 319 m_free(m); 320 goto end; 321 } 322 323 m->m_flags &= ~(M_BCAST|M_MCAST); 324 if (!(ifp->if_flags & IFF_UP) || 325 sc->gif_psrc == NULL || sc->gif_pdst == NULL || 326 sc->gif_si == NULL) { 327 m_freem(m); 328 error = ENETDOWN; 329 goto end; 330 } 331 332 /* XXX should we check if our outer source is legal? */ 333 334 /* use DLT_NULL encapsulation here to pass inner af type */ 335 M_PREPEND(m, sizeof(int), M_DONTWAIT); 336 if (!m) { 337 error = ENOBUFS; 338 goto end; 339 } 340 *mtod(m, int *) = dst->sa_family; 341 342 /* Clear checksum-offload flags. */ 343 m->m_pkthdr.csum_flags = 0; 344 m->m_pkthdr.csum_data = 0; 345 346 s = splnet(); 347 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error); 348 if (error) { 349 splx(s); 350 goto end; 351 } 352 353 /* softint_schedule() must be called with kpreempt_disabled() */ 354 softint_schedule(sc->gif_si); 355 splx(s); 356 357 error = 0; 358 359 end: 360 if (error) 361 ifp->if_oerrors++; 362 return error; 363 } 364 365 static void 366 gifintr(void *arg) 367 { 368 struct gif_softc *sc; 369 struct ifnet *ifp; 370 struct mbuf *m; 371 int family; 372 int len; 373 int s; 374 int error; 375 376 sc = arg; 377 ifp = &sc->gif_if; 378 379 /* 380 * other CPUs does {set,delete}_tunnel after curcpu have done 381 * softint_schedule(). 382 */ 383 if (sc->gif_pdst == NULL || sc->gif_psrc == NULL) { 384 IFQ_PURGE(&ifp->if_snd); 385 return; 386 } 387 388 /* output processing */ 389 while (1) { 390 s = splnet(); 391 IFQ_DEQUEUE(&sc->gif_if.if_snd, m); 392 splx(s); 393 if (m == NULL) 394 break; 395 396 /* grab and chop off inner af type */ 397 if (sizeof(int) > m->m_len) { 398 m = m_pullup(m, sizeof(int)); 399 if (!m) { 400 ifp->if_oerrors++; 401 continue; 402 } 403 } 404 family = *mtod(m, int *); 405 bpf_mtap(ifp, m); 406 m_adj(m, sizeof(int)); 407 408 len = m->m_pkthdr.len; 409 410 /* dispatch to output logic based on outer AF */ 411 switch (sc->gif_psrc->sa_family) { 412 #ifdef INET 413 case AF_INET: 414 mutex_enter(softnet_lock); 415 error = in_gif_output(ifp, family, m); 416 mutex_exit(softnet_lock); 417 break; 418 #endif 419 #ifdef INET6 420 case AF_INET6: 421 mutex_enter(softnet_lock); 422 error = in6_gif_output(ifp, family, m); 423 mutex_exit(softnet_lock); 424 break; 425 #endif 426 default: 427 m_freem(m); 428 error = ENETDOWN; 429 break; 430 } 431 432 if (error) 433 ifp->if_oerrors++; 434 else { 435 ifp->if_opackets++; 436 ifp->if_obytes += len; 437 } 438 } 439 } 440 441 void 442 gif_input(struct mbuf *m, int af, struct ifnet *ifp) 443 { 444 pktqueue_t *pktq; 445 size_t pktlen; 446 int s; 447 448 if (ifp == NULL) { 449 /* just in case */ 450 m_freem(m); 451 return; 452 } 453 454 m->m_pkthdr.rcvif = ifp; 455 pktlen = m->m_pkthdr.len; 456 457 bpf_mtap_af(ifp, af, m); 458 459 /* 460 * Put the packet to the network layer input queue according to the 461 * specified address family. Note: we avoid direct call to the 462 * input function of the network layer in order to avoid recursion. 463 * This may be revisited in the future. 464 */ 465 switch (af) { 466 #ifdef INET 467 case AF_INET: 468 pktq = ip_pktq; 469 break; 470 #endif 471 #ifdef INET6 472 case AF_INET6: 473 pktq = ip6_pktq; 474 break; 475 #endif 476 default: 477 m_freem(m); 478 return; 479 } 480 481 s = splnet(); 482 if (__predict_true(pktq_enqueue(pktq, m, 0))) { 483 ifp->if_ibytes += pktlen; 484 ifp->if_ipackets++; 485 } else { 486 m_freem(m); 487 } 488 splx(s); 489 } 490 491 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 492 int 493 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data) 494 { 495 struct gif_softc *sc = ifp->if_softc; 496 struct ifreq *ifr = (struct ifreq*)data; 497 struct ifaddr *ifa = (struct ifaddr*)data; 498 int error = 0, size; 499 struct sockaddr *dst, *src; 500 501 switch (cmd) { 502 case SIOCINITIFADDR: 503 ifp->if_flags |= IFF_UP; 504 ifa->ifa_rtrequest = p2p_rtrequest; 505 break; 506 507 case SIOCADDMULTI: 508 case SIOCDELMULTI: 509 switch (ifr->ifr_addr.sa_family) { 510 #ifdef INET 511 case AF_INET: /* IP supports Multicast */ 512 break; 513 #endif /* INET */ 514 #ifdef INET6 515 case AF_INET6: /* IP6 supports Multicast */ 516 break; 517 #endif /* INET6 */ 518 default: /* Other protocols doesn't support Multicast */ 519 error = EAFNOSUPPORT; 520 break; 521 } 522 break; 523 524 case SIOCSIFMTU: 525 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) 526 return EINVAL; 527 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 528 error = 0; 529 break; 530 531 #ifdef INET 532 case SIOCSIFPHYADDR: 533 #endif 534 #ifdef INET6 535 case SIOCSIFPHYADDR_IN6: 536 #endif /* INET6 */ 537 case SIOCSLIFPHYADDR: 538 switch (cmd) { 539 #ifdef INET 540 case SIOCSIFPHYADDR: 541 src = (struct sockaddr *) 542 &(((struct in_aliasreq *)data)->ifra_addr); 543 dst = (struct sockaddr *) 544 &(((struct in_aliasreq *)data)->ifra_dstaddr); 545 break; 546 #endif 547 #ifdef INET6 548 case SIOCSIFPHYADDR_IN6: 549 src = (struct sockaddr *) 550 &(((struct in6_aliasreq *)data)->ifra_addr); 551 dst = (struct sockaddr *) 552 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 553 break; 554 #endif 555 case SIOCSLIFPHYADDR: 556 src = (struct sockaddr *) 557 &(((struct if_laddrreq *)data)->addr); 558 dst = (struct sockaddr *) 559 &(((struct if_laddrreq *)data)->dstaddr); 560 break; 561 default: 562 return EINVAL; 563 } 564 565 /* sa_family must be equal */ 566 if (src->sa_family != dst->sa_family) 567 return EINVAL; 568 569 /* validate sa_len */ 570 switch (src->sa_family) { 571 #ifdef INET 572 case AF_INET: 573 if (src->sa_len != sizeof(struct sockaddr_in)) 574 return EINVAL; 575 break; 576 #endif 577 #ifdef INET6 578 case AF_INET6: 579 if (src->sa_len != sizeof(struct sockaddr_in6)) 580 return EINVAL; 581 break; 582 #endif 583 default: 584 return EAFNOSUPPORT; 585 } 586 switch (dst->sa_family) { 587 #ifdef INET 588 case AF_INET: 589 if (dst->sa_len != sizeof(struct sockaddr_in)) 590 return EINVAL; 591 break; 592 #endif 593 #ifdef INET6 594 case AF_INET6: 595 if (dst->sa_len != sizeof(struct sockaddr_in6)) 596 return EINVAL; 597 break; 598 #endif 599 default: 600 return EAFNOSUPPORT; 601 } 602 603 /* check sa_family looks sane for the cmd */ 604 switch (cmd) { 605 case SIOCSIFPHYADDR: 606 if (src->sa_family == AF_INET) 607 break; 608 return EAFNOSUPPORT; 609 #ifdef INET6 610 case SIOCSIFPHYADDR_IN6: 611 if (src->sa_family == AF_INET6) 612 break; 613 return EAFNOSUPPORT; 614 #endif /* INET6 */ 615 case SIOCSLIFPHYADDR: 616 /* checks done in the above */ 617 break; 618 } 619 620 error = gif_set_tunnel(&sc->gif_if, src, dst); 621 break; 622 623 #ifdef SIOCDIFPHYADDR 624 case SIOCDIFPHYADDR: 625 gif_delete_tunnel(&sc->gif_if); 626 break; 627 #endif 628 629 case SIOCGIFPSRCADDR: 630 #ifdef INET6 631 case SIOCGIFPSRCADDR_IN6: 632 #endif /* INET6 */ 633 if (sc->gif_psrc == NULL) { 634 error = EADDRNOTAVAIL; 635 goto bad; 636 } 637 src = sc->gif_psrc; 638 switch (cmd) { 639 #ifdef INET 640 case SIOCGIFPSRCADDR: 641 dst = &ifr->ifr_addr; 642 size = sizeof(ifr->ifr_addr); 643 break; 644 #endif /* INET */ 645 #ifdef INET6 646 case SIOCGIFPSRCADDR_IN6: 647 dst = (struct sockaddr *) 648 &(((struct in6_ifreq *)data)->ifr_addr); 649 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 650 break; 651 #endif /* INET6 */ 652 default: 653 error = EADDRNOTAVAIL; 654 goto bad; 655 } 656 if (src->sa_len > size) 657 return EINVAL; 658 memcpy(dst, src, src->sa_len); 659 break; 660 661 case SIOCGIFPDSTADDR: 662 #ifdef INET6 663 case SIOCGIFPDSTADDR_IN6: 664 #endif /* INET6 */ 665 if (sc->gif_pdst == NULL) { 666 error = EADDRNOTAVAIL; 667 goto bad; 668 } 669 src = sc->gif_pdst; 670 switch (cmd) { 671 #ifdef INET 672 case SIOCGIFPDSTADDR: 673 dst = &ifr->ifr_addr; 674 size = sizeof(ifr->ifr_addr); 675 break; 676 #endif /* INET */ 677 #ifdef INET6 678 case SIOCGIFPDSTADDR_IN6: 679 dst = (struct sockaddr *) 680 &(((struct in6_ifreq *)data)->ifr_addr); 681 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 682 break; 683 #endif /* INET6 */ 684 default: 685 error = EADDRNOTAVAIL; 686 goto bad; 687 } 688 if (src->sa_len > size) 689 return EINVAL; 690 memcpy(dst, src, src->sa_len); 691 break; 692 693 case SIOCGLIFPHYADDR: 694 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 695 error = EADDRNOTAVAIL; 696 goto bad; 697 } 698 699 /* copy src */ 700 src = sc->gif_psrc; 701 dst = (struct sockaddr *) 702 &(((struct if_laddrreq *)data)->addr); 703 size = sizeof(((struct if_laddrreq *)data)->addr); 704 if (src->sa_len > size) 705 return EINVAL; 706 memcpy(dst, src, src->sa_len); 707 708 /* copy dst */ 709 src = sc->gif_pdst; 710 dst = (struct sockaddr *) 711 &(((struct if_laddrreq *)data)->dstaddr); 712 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 713 if (src->sa_len > size) 714 return EINVAL; 715 memcpy(dst, src, src->sa_len); 716 break; 717 718 default: 719 return ifioctl_common(ifp, cmd, data); 720 } 721 bad: 722 return error; 723 } 724 725 static int 726 gif_encap_attach(struct gif_softc *sc) 727 { 728 int error; 729 730 if (sc == NULL || sc->gif_psrc == NULL) 731 return EINVAL; 732 733 switch (sc->gif_psrc->sa_family) { 734 #ifdef INET 735 case AF_INET: 736 error = in_gif_attach(sc); 737 break; 738 #endif 739 #ifdef INET6 740 case AF_INET6: 741 error = in6_gif_attach(sc); 742 break; 743 #endif 744 default: 745 error = EINVAL; 746 break; 747 } 748 749 return error; 750 } 751 752 static int 753 gif_encap_detach(struct gif_softc *sc) 754 { 755 int error; 756 757 if (sc == NULL || sc->gif_psrc == NULL) 758 return EINVAL; 759 760 switch (sc->gif_psrc->sa_family) { 761 #ifdef INET 762 case AF_INET: 763 error = in_gif_detach(sc); 764 break; 765 #endif 766 #ifdef INET6 767 case AF_INET6: 768 error = in6_gif_detach(sc); 769 break; 770 #endif 771 default: 772 error = EINVAL; 773 break; 774 } 775 776 return error; 777 } 778 779 int 780 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) 781 { 782 struct gif_softc *sc = ifp->if_softc; 783 struct gif_softc *sc2; 784 struct sockaddr *osrc, *odst; 785 struct sockaddr *nsrc, *ndst; 786 void *osi; 787 int s; 788 int error; 789 790 s = splsoftnet(); 791 792 LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 793 if (sc2 == sc) 794 continue; 795 if (!sc2->gif_pdst || !sc2->gif_psrc) 796 continue; 797 /* can't configure same pair of address onto two gifs */ 798 if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 && 799 sockaddr_cmp(sc2->gif_psrc, src) == 0) { 800 /* continue to use the old configureation. */ 801 splx(s); 802 return EADDRNOTAVAIL; 803 } 804 805 /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 806 } 807 808 if ((nsrc = sockaddr_dup(src, M_WAITOK)) == NULL) { 809 splx(s); 810 return ENOMEM; 811 } 812 if ((ndst = sockaddr_dup(dst, M_WAITOK)) == NULL) { 813 sockaddr_free(nsrc); 814 splx(s); 815 return ENOMEM; 816 } 817 818 /* Firstly, clear old configurations. */ 819 if (sc->gif_si) { 820 osrc = sc->gif_psrc; 821 odst = sc->gif_pdst; 822 osi = sc->gif_si; 823 sc->gif_psrc = NULL; 824 sc->gif_pdst = NULL; 825 sc->gif_si = NULL; 826 /* 827 * At this point, gif_output() does not softint_schedule() 828 * any more. However, there are below 2 fears of other CPUs 829 * which would cause panic because of the race between 830 * softint_execute() and softint_disestablish(). 831 * (a) gif_output() has done softint_schedule(), and softint 832 * (gifintr()) is waiting for execution 833 * => This pattern is avoided by waiting SOFTINT_PENDING 834 * CPUs in softint_disestablish() 835 * (b) gifintr() is already running 836 * => This pattern is avoided by waiting SOFTINT_ACTIVE 837 * CPUs in softint_disestablish() 838 */ 839 840 softint_disestablish(osi); 841 sc->gif_psrc = osrc; 842 sc->gif_pdst = odst; 843 osrc = NULL; 844 odst = NULL; 845 } 846 /* XXX we can detach from both, but be polite just in case */ 847 if (sc->gif_psrc) 848 (void)gif_encap_detach(sc); 849 850 /* 851 * Secondly, try to set new configurations. 852 * If the setup failed, rollback to old configurations. 853 */ 854 do { 855 osrc = sc->gif_psrc; 856 odst = sc->gif_pdst; 857 sc->gif_psrc = nsrc; 858 sc->gif_pdst = ndst; 859 860 error = gif_encap_attach(sc); 861 if (error) { 862 /* rollback to the last configuration. */ 863 nsrc = osrc; 864 ndst = odst; 865 osrc = sc->gif_psrc; 866 odst = sc->gif_pdst; 867 868 continue; 869 } 870 871 sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc); 872 if (sc->gif_si == NULL) { 873 (void)gif_encap_detach(sc); 874 875 /* rollback to the last configuration. */ 876 nsrc = osrc; 877 ndst = odst; 878 osrc = sc->gif_psrc; 879 odst = sc->gif_pdst; 880 881 error = ENOMEM; 882 continue; 883 } 884 } while (error != 0 && (nsrc != NULL && ndst != NULL)); 885 /* Thirdly, even rollback failed, clear configurations. */ 886 if (error) { 887 osrc = sc->gif_psrc; 888 odst = sc->gif_pdst; 889 sc->gif_psrc = NULL; 890 sc->gif_pdst = NULL; 891 } 892 893 if (osrc) 894 sockaddr_free(osrc); 895 if (odst) 896 sockaddr_free(odst); 897 898 if (sc->gif_psrc && sc->gif_pdst) 899 ifp->if_flags |= IFF_RUNNING; 900 else 901 ifp->if_flags &= ~IFF_RUNNING; 902 903 splx(s); 904 return error; 905 } 906 907 void 908 gif_delete_tunnel(struct ifnet *ifp) 909 { 910 struct gif_softc *sc = ifp->if_softc; 911 struct sockaddr *osrc, *odst; 912 void *osi; 913 int s; 914 915 s = splsoftnet(); 916 917 if (sc->gif_si) { 918 osrc = sc->gif_psrc; 919 odst = sc->gif_pdst; 920 osi = sc->gif_si; 921 922 sc->gif_psrc = NULL; 923 sc->gif_pdst = NULL; 924 sc->gif_si = NULL; 925 926 softint_disestablish(osi); 927 sc->gif_psrc = osrc; 928 sc->gif_pdst = odst; 929 } 930 if (sc->gif_psrc) { 931 sockaddr_free(sc->gif_psrc); 932 sc->gif_psrc = NULL; 933 } 934 if (sc->gif_pdst) { 935 sockaddr_free(sc->gif_pdst); 936 sc->gif_pdst = NULL; 937 } 938 /* it is safe to detach from both */ 939 #ifdef INET 940 (void)in_gif_detach(sc); 941 #endif 942 #ifdef INET6 943 (void)in6_gif_detach(sc); 944 #endif 945 946 if (sc->gif_psrc && sc->gif_pdst) 947 ifp->if_flags |= IFF_RUNNING; 948 else 949 ifp->if_flags &= ~IFF_RUNNING; 950 splx(s); 951 } 952