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