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