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