if_gif.c revision 130933
1/* $FreeBSD: head/sys/net/if_gif.c 130933 2004-06-22 20:13:25Z brooks $ */ 2/* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun 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 "opt_inet.h" 34#include "opt_inet6.h" 35#include "opt_mac.h" 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/kernel.h> 40#include <sys/mac.h> 41#include <sys/malloc.h> 42#include <sys/mbuf.h> 43#include <sys/module.h> 44#include <sys/socket.h> 45#include <sys/sockio.h> 46#include <sys/errno.h> 47#include <sys/time.h> 48#include <sys/sysctl.h> 49#include <sys/syslog.h> 50#include <sys/protosw.h> 51#include <sys/conf.h> 52#include <machine/cpu.h> 53 54#include <net/if.h> 55#include <net/if_clone.h> 56#include <net/if_types.h> 57#include <net/netisr.h> 58#include <net/route.h> 59#include <net/bpf.h> 60 61#include <netinet/in.h> 62#include <netinet/in_systm.h> 63#include <netinet/ip.h> 64#ifdef INET 65#include <netinet/in_var.h> 66#include <netinet/in_gif.h> 67#include <netinet/ip_var.h> 68#endif /* INET */ 69 70#ifdef INET6 71#ifndef INET 72#include <netinet/in.h> 73#endif 74#include <netinet6/in6_var.h> 75#include <netinet/ip6.h> 76#include <netinet6/ip6_var.h> 77#include <netinet6/in6_gif.h> 78#include <netinet6/ip6protosw.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#define GIFNAME "gif" 87 88/* 89 * gif_mtx protects the global gif_softc_list. 90 * XXX: Per-softc locking is still required. 91 */ 92static struct mtx gif_mtx; 93static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 94static LIST_HEAD(, gif_softc) gif_softc_list; 95 96void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 97void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 98void (*ng_gif_attach_p)(struct ifnet *ifp); 99void (*ng_gif_detach_p)(struct ifnet *ifp); 100 101static int gif_clone_create(struct if_clone *, int); 102static void gif_clone_destroy(struct ifnet *); 103 104IFC_SIMPLE_DECLARE(gif, 0); 105 106static int gifmodevent(module_t, int, void *); 107 108SYSCTL_DECL(_net_link); 109SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 110 "Generic Tunnel Interface"); 111#ifndef MAX_GIF_NEST 112/* 113 * This macro controls the default upper limitation on nesting of gif tunnels. 114 * Since, setting a large value to this macro with a careless configuration 115 * may introduce system crash, we don't allow any nestings by default. 116 * If you need to configure nested gif tunnels, you can define this macro 117 * in your kernel configuration file. However, if you do so, please be 118 * careful to configure the tunnels so that it won't make a loop. 119 */ 120#define MAX_GIF_NEST 1 121#endif 122static int max_gif_nesting = MAX_GIF_NEST; 123SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 124 &max_gif_nesting, 0, "Max nested tunnels"); 125 126/* 127 * By default, we disallow creation of multiple tunnels between the same 128 * pair of addresses. Some applications require this functionality so 129 * we allow control over this check here. 130 */ 131#ifdef XBONEHACK 132static int parallel_tunnels = 1; 133#else 134static int parallel_tunnels = 0; 135#endif 136SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 137 ¶llel_tunnels, 0, "Allow parallel tunnels?"); 138 139static int 140gif_clone_create(ifc, unit) 141 struct if_clone *ifc; 142 int unit; 143{ 144 struct gif_softc *sc; 145 146 sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK); 147 bzero(sc, sizeof(struct gif_softc)); 148 149 sc->gif_if.if_softc = sc; 150 if_initname(&sc->gif_if, ifc->ifc_name, unit); 151 152 gifattach0(sc); 153 154 mtx_lock(&gif_mtx); 155 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 156 mtx_unlock(&gif_mtx); 157 return (0); 158} 159 160void 161gifattach0(sc) 162 struct gif_softc *sc; 163{ 164 165 sc->encap_cookie4 = sc->encap_cookie6 = NULL; 166 167 sc->gif_if.if_addrlen = 0; 168 sc->gif_if.if_mtu = GIF_MTU; 169 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 170#if 0 171 /* turn off ingress filter */ 172 sc->gif_if.if_flags |= IFF_LINK2; 173#endif 174 sc->gif_if.if_ioctl = gif_ioctl; 175 sc->gif_if.if_output = gif_output; 176 sc->gif_if.if_type = IFT_GIF; 177 sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 178 if_attach(&sc->gif_if); 179 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 180 if (ng_gif_attach_p != NULL) 181 (*ng_gif_attach_p)(&sc->gif_if); 182} 183 184static void 185gif_destroy(struct gif_softc *sc) 186{ 187 struct ifnet *ifp = &sc->gif_if; 188 int err; 189 190 gif_delete_tunnel(ifp); 191#ifdef INET6 192 if (sc->encap_cookie6 != NULL) { 193 err = encap_detach(sc->encap_cookie6); 194 KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 195 } 196#endif 197#ifdef INET 198 if (sc->encap_cookie4 != NULL) { 199 err = encap_detach(sc->encap_cookie4); 200 KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 201 } 202#endif 203 204 if (ng_gif_detach_p != NULL) 205 (*ng_gif_detach_p)(ifp); 206 bpfdetach(ifp); 207 if_detach(ifp); 208 209 free(sc, M_GIF); 210} 211 212static void 213gif_clone_destroy(ifp) 214 struct ifnet *ifp; 215{ 216 struct gif_softc *sc = ifp->if_softc; 217 218 mtx_lock(&gif_mtx); 219 LIST_REMOVE(sc, gif_list); 220 mtx_unlock(&gif_mtx); 221 gif_destroy(sc); 222} 223 224static int 225gifmodevent(mod, type, data) 226 module_t mod; 227 int type; 228 void *data; 229{ 230 struct gif_softc *sc; 231 232 switch (type) { 233 case MOD_LOAD: 234 mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF); 235 LIST_INIT(&gif_softc_list); 236 if_clone_attach(&gif_cloner); 237 238#ifdef INET6 239 ip6_gif_hlim = GIF_HLIM; 240#endif 241 242 break; 243 case MOD_UNLOAD: 244 if_clone_detach(&gif_cloner); 245 246 mtx_lock(&gif_mtx); 247 while ((sc = LIST_FIRST(&gif_softc_list)) != NULL) { 248 LIST_REMOVE(sc, gif_list); 249 mtx_unlock(&gif_mtx); 250 gif_destroy(sc); 251 mtx_lock(&gif_mtx); 252 } 253 mtx_unlock(&gif_mtx); 254 mtx_destroy(&gif_mtx); 255#ifdef INET6 256 ip6_gif_hlim = 0; 257#endif 258 break; 259 } 260 return 0; 261} 262 263static moduledata_t gif_mod = { 264 "if_gif", 265 gifmodevent, 266 0 267}; 268 269DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 270MODULE_VERSION(if_gif, 1); 271 272int 273gif_encapcheck(m, off, proto, arg) 274 const struct mbuf *m; 275 int off; 276 int proto; 277 void *arg; 278{ 279 struct ip ip; 280 struct gif_softc *sc; 281 282 sc = (struct gif_softc *)arg; 283 if (sc == NULL) 284 return 0; 285 286 if ((sc->gif_if.if_flags & IFF_UP) == 0) 287 return 0; 288 289 /* no physical address */ 290 if (!sc->gif_psrc || !sc->gif_pdst) 291 return 0; 292 293 switch (proto) { 294#ifdef INET 295 case IPPROTO_IPV4: 296 break; 297#endif 298#ifdef INET6 299 case IPPROTO_IPV6: 300 break; 301#endif 302 default: 303 return 0; 304 } 305 306 /* Bail on short packets */ 307 if (m->m_pkthdr.len < sizeof(ip)) 308 return 0; 309 310 m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 311 312 switch (ip.ip_v) { 313#ifdef INET 314 case 4: 315 if (sc->gif_psrc->sa_family != AF_INET || 316 sc->gif_pdst->sa_family != AF_INET) 317 return 0; 318 return gif_encapcheck4(m, off, proto, arg); 319#endif 320#ifdef INET6 321 case 6: 322 if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 323 return 0; 324 if (sc->gif_psrc->sa_family != AF_INET6 || 325 sc->gif_pdst->sa_family != AF_INET6) 326 return 0; 327 return gif_encapcheck6(m, off, proto, arg); 328#endif 329 default: 330 return 0; 331 } 332} 333 334int 335gif_output(ifp, m, dst, rt) 336 struct ifnet *ifp; 337 struct mbuf *m; 338 struct sockaddr *dst; 339 struct rtentry *rt; /* added in net2 */ 340{ 341 struct gif_softc *sc = (struct gif_softc*)ifp; 342 struct m_tag *mtag; 343 int error = 0; 344 int gif_called; 345 346#ifdef MAC 347 error = mac_check_ifnet_transmit(ifp, m); 348 if (error) { 349 m_freem(m); 350 goto end; 351 } 352#endif 353 354 /* 355 * gif may cause infinite recursion calls when misconfigured. 356 * We'll prevent this by detecting loops. 357 * 358 * High nesting level may cause stack exhaustion. 359 * We'll prevent this by introducing upper limit. 360 */ 361 gif_called = 1; 362 mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, NULL); 363 while (mtag != NULL) { 364 if (*(struct ifnet **)(mtag + 1) == ifp) { 365 log(LOG_NOTICE, 366 "gif_output: loop detected on %s\n", 367 (*(struct ifnet **)(mtag + 1))->if_xname); 368 m_freem(m); 369 error = EIO; /* is there better errno? */ 370 goto end; 371 } 372 mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag); 373 gif_called++; 374 } 375 if (gif_called > max_gif_nesting) { 376 log(LOG_NOTICE, 377 "gif_output: recursively called too many times(%d)\n", 378 gif_called); 379 m_freem(m); 380 error = EIO; /* is there better errno? */ 381 goto end; 382 } 383 mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *), 384 M_NOWAIT); 385 if (mtag == NULL) { 386 m_freem(m); 387 error = ENOMEM; 388 goto end; 389 } 390 *(struct ifnet **)(mtag + 1) = ifp; 391 m_tag_prepend(m, mtag); 392 393 m->m_flags &= ~(M_BCAST|M_MCAST); 394 if (!(ifp->if_flags & IFF_UP) || 395 sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 396 m_freem(m); 397 error = ENETDOWN; 398 goto end; 399 } 400 401 if (ifp->if_bpf) { 402 u_int32_t af = dst->sa_family; 403 bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 404 } 405 ifp->if_opackets++; 406 ifp->if_obytes += m->m_pkthdr.len; 407 408 /* inner AF-specific encapsulation */ 409 410 /* XXX should we check if our outer source is legal? */ 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 error = in_gif_output(ifp, dst->sa_family, m); 417 break; 418#endif 419#ifdef INET6 420 case AF_INET6: 421 error = in6_gif_output(ifp, dst->sa_family, m); 422 break; 423#endif 424 default: 425 m_freem(m); 426 error = ENETDOWN; 427 goto end; 428 } 429 430 end: 431 if (error) 432 ifp->if_oerrors++; 433 return error; 434} 435 436void 437gif_input(m, af, ifp) 438 struct mbuf *m; 439 int af; 440 struct ifnet *ifp; 441{ 442 int isr; 443 444 if (ifp == NULL) { 445 /* just in case */ 446 m_freem(m); 447 return; 448 } 449 450 m->m_pkthdr.rcvif = ifp; 451 452#ifdef MAC 453 mac_create_mbuf_from_ifnet(ifp, m); 454#endif 455 456 if (ifp->if_bpf) { 457 u_int32_t af1 = af; 458 bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 459 } 460 461 if (ng_gif_input_p != NULL) { 462 (*ng_gif_input_p)(ifp, &m, af); 463 if (m == NULL) 464 return; 465 } 466 467 /* 468 * Put the packet to the network layer input queue according to the 469 * specified address family. 470 * Note: older versions of gif_input directly called network layer 471 * input functions, e.g. ip6_input, here. We changed the policy to 472 * prevent too many recursive calls of such input functions, which 473 * might cause kernel panic. But the change may introduce another 474 * problem; if the input queue is full, packets are discarded. 475 * The kernel stack overflow really happened, and we believed 476 * queue-full rarely occurs, so we changed the policy. 477 */ 478 switch (af) { 479#ifdef INET 480 case AF_INET: 481 isr = NETISR_IP; 482 break; 483#endif 484#ifdef INET6 485 case AF_INET6: 486 isr = NETISR_IPV6; 487 break; 488#endif 489 default: 490 if (ng_gif_input_orphan_p != NULL) 491 (*ng_gif_input_orphan_p)(ifp, m, af); 492 else 493 m_freem(m); 494 return; 495 } 496 497 ifp->if_ipackets++; 498 ifp->if_ibytes += m->m_pkthdr.len; 499 netisr_dispatch(isr, m); 500} 501 502/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 503int 504gif_ioctl(ifp, cmd, data) 505 struct ifnet *ifp; 506 u_long cmd; 507 caddr_t data; 508{ 509 struct gif_softc *sc = (struct gif_softc*)ifp; 510 struct ifreq *ifr = (struct ifreq*)data; 511 int error = 0, size; 512 struct sockaddr *dst, *src; 513#ifdef SIOCSIFMTU /* xxx */ 514 u_long mtu; 515#endif 516 517 switch (cmd) { 518 case SIOCSIFADDR: 519 ifp->if_flags |= IFF_UP; 520 break; 521 522 case SIOCSIFDSTADDR: 523 break; 524 525 case SIOCADDMULTI: 526 case SIOCDELMULTI: 527 break; 528 529#ifdef SIOCSIFMTU /* xxx */ 530 case SIOCGIFMTU: 531 break; 532 533 case SIOCSIFMTU: 534 mtu = ifr->ifr_mtu; 535 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 536 return (EINVAL); 537 ifp->if_mtu = mtu; 538 break; 539#endif /* SIOCSIFMTU */ 540 541#ifdef INET 542 case SIOCSIFPHYADDR: 543#endif 544#ifdef INET6 545 case SIOCSIFPHYADDR_IN6: 546#endif /* INET6 */ 547 case SIOCSLIFPHYADDR: 548 switch (cmd) { 549#ifdef INET 550 case SIOCSIFPHYADDR: 551 src = (struct sockaddr *) 552 &(((struct in_aliasreq *)data)->ifra_addr); 553 dst = (struct sockaddr *) 554 &(((struct in_aliasreq *)data)->ifra_dstaddr); 555 break; 556#endif 557#ifdef INET6 558 case SIOCSIFPHYADDR_IN6: 559 src = (struct sockaddr *) 560 &(((struct in6_aliasreq *)data)->ifra_addr); 561 dst = (struct sockaddr *) 562 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 563 break; 564#endif 565 case SIOCSLIFPHYADDR: 566 src = (struct sockaddr *) 567 &(((struct if_laddrreq *)data)->addr); 568 dst = (struct sockaddr *) 569 &(((struct if_laddrreq *)data)->dstaddr); 570 break; 571 default: 572 return EINVAL; 573 } 574 575 /* sa_family must be equal */ 576 if (src->sa_family != dst->sa_family) 577 return EINVAL; 578 579 /* validate sa_len */ 580 switch (src->sa_family) { 581#ifdef INET 582 case AF_INET: 583 if (src->sa_len != sizeof(struct sockaddr_in)) 584 return EINVAL; 585 break; 586#endif 587#ifdef INET6 588 case AF_INET6: 589 if (src->sa_len != sizeof(struct sockaddr_in6)) 590 return EINVAL; 591 break; 592#endif 593 default: 594 return EAFNOSUPPORT; 595 } 596 switch (dst->sa_family) { 597#ifdef INET 598 case AF_INET: 599 if (dst->sa_len != sizeof(struct sockaddr_in)) 600 return EINVAL; 601 break; 602#endif 603#ifdef INET6 604 case AF_INET6: 605 if (dst->sa_len != sizeof(struct sockaddr_in6)) 606 return EINVAL; 607 break; 608#endif 609 default: 610 return EAFNOSUPPORT; 611 } 612 613 /* check sa_family looks sane for the cmd */ 614 switch (cmd) { 615 case SIOCSIFPHYADDR: 616 if (src->sa_family == AF_INET) 617 break; 618 return EAFNOSUPPORT; 619#ifdef INET6 620 case SIOCSIFPHYADDR_IN6: 621 if (src->sa_family == AF_INET6) 622 break; 623 return EAFNOSUPPORT; 624#endif /* INET6 */ 625 case SIOCSLIFPHYADDR: 626 /* checks done in the above */ 627 break; 628 } 629 630 error = gif_set_tunnel(&sc->gif_if, src, dst); 631 break; 632 633#ifdef SIOCDIFPHYADDR 634 case SIOCDIFPHYADDR: 635 gif_delete_tunnel(&sc->gif_if); 636 break; 637#endif 638 639 case SIOCGIFPSRCADDR: 640#ifdef INET6 641 case SIOCGIFPSRCADDR_IN6: 642#endif /* INET6 */ 643 if (sc->gif_psrc == NULL) { 644 error = EADDRNOTAVAIL; 645 goto bad; 646 } 647 src = sc->gif_psrc; 648 switch (cmd) { 649#ifdef INET 650 case SIOCGIFPSRCADDR: 651 dst = &ifr->ifr_addr; 652 size = sizeof(ifr->ifr_addr); 653 break; 654#endif /* INET */ 655#ifdef INET6 656 case SIOCGIFPSRCADDR_IN6: 657 dst = (struct sockaddr *) 658 &(((struct in6_ifreq *)data)->ifr_addr); 659 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 660 break; 661#endif /* INET6 */ 662 default: 663 error = EADDRNOTAVAIL; 664 goto bad; 665 } 666 if (src->sa_len > size) 667 return EINVAL; 668 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 669 break; 670 671 case SIOCGIFPDSTADDR: 672#ifdef INET6 673 case SIOCGIFPDSTADDR_IN6: 674#endif /* INET6 */ 675 if (sc->gif_pdst == NULL) { 676 error = EADDRNOTAVAIL; 677 goto bad; 678 } 679 src = sc->gif_pdst; 680 switch (cmd) { 681#ifdef INET 682 case SIOCGIFPDSTADDR: 683 dst = &ifr->ifr_addr; 684 size = sizeof(ifr->ifr_addr); 685 break; 686#endif /* INET */ 687#ifdef INET6 688 case SIOCGIFPDSTADDR_IN6: 689 dst = (struct sockaddr *) 690 &(((struct in6_ifreq *)data)->ifr_addr); 691 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 692 break; 693#endif /* INET6 */ 694 default: 695 error = EADDRNOTAVAIL; 696 goto bad; 697 } 698 if (src->sa_len > size) 699 return EINVAL; 700 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 701 break; 702 703 case SIOCGLIFPHYADDR: 704 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 705 error = EADDRNOTAVAIL; 706 goto bad; 707 } 708 709 /* copy src */ 710 src = sc->gif_psrc; 711 dst = (struct sockaddr *) 712 &(((struct if_laddrreq *)data)->addr); 713 size = sizeof(((struct if_laddrreq *)data)->addr); 714 if (src->sa_len > size) 715 return EINVAL; 716 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 717 718 /* copy dst */ 719 src = sc->gif_pdst; 720 dst = (struct sockaddr *) 721 &(((struct if_laddrreq *)data)->dstaddr); 722 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 723 if (src->sa_len > size) 724 return EINVAL; 725 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 726 break; 727 728 case SIOCSIFFLAGS: 729 /* if_ioctl() takes care of it */ 730 break; 731 732 default: 733 error = EINVAL; 734 break; 735 } 736 bad: 737 return error; 738} 739 740/* 741 * XXXRW: There's a general event-ordering issue here: the code to check 742 * if a given tunnel is already present happens before we perform a 743 * potentially blocking setup of the tunnel. This code needs to be 744 * re-ordered so that the check and replacement can be atomic using 745 * a mutex. 746 */ 747int 748gif_set_tunnel(ifp, src, dst) 749 struct ifnet *ifp; 750 struct sockaddr *src; 751 struct sockaddr *dst; 752{ 753 struct gif_softc *sc = (struct gif_softc *)ifp; 754 struct gif_softc *sc2; 755 struct sockaddr *osrc, *odst, *sa; 756 int s; 757 int error = 0; 758 759 s = splnet(); 760 761 mtx_lock(&gif_mtx); 762 LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 763 if (sc2 == sc) 764 continue; 765 if (!sc2->gif_pdst || !sc2->gif_psrc) 766 continue; 767 if (sc2->gif_pdst->sa_family != dst->sa_family || 768 sc2->gif_pdst->sa_len != dst->sa_len || 769 sc2->gif_psrc->sa_family != src->sa_family || 770 sc2->gif_psrc->sa_len != src->sa_len) 771 continue; 772 773 /* 774 * Disallow parallel tunnels unless instructed 775 * otherwise. 776 */ 777 if (!parallel_tunnels && 778 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 779 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 780 error = EADDRNOTAVAIL; 781 mtx_unlock(&gif_mtx); 782 goto bad; 783 } 784 785 /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 786 } 787 mtx_unlock(&gif_mtx); 788 789 /* XXX we can detach from both, but be polite just in case */ 790 if (sc->gif_psrc) 791 switch (sc->gif_psrc->sa_family) { 792#ifdef INET 793 case AF_INET: 794 (void)in_gif_detach(sc); 795 break; 796#endif 797#ifdef INET6 798 case AF_INET6: 799 (void)in6_gif_detach(sc); 800 break; 801#endif 802 } 803 804 osrc = sc->gif_psrc; 805 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 806 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 807 sc->gif_psrc = sa; 808 809 odst = sc->gif_pdst; 810 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 811 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 812 sc->gif_pdst = sa; 813 814 switch (sc->gif_psrc->sa_family) { 815#ifdef INET 816 case AF_INET: 817 error = in_gif_attach(sc); 818 break; 819#endif 820#ifdef INET6 821 case AF_INET6: 822 error = in6_gif_attach(sc); 823 break; 824#endif 825 } 826 if (error) { 827 /* rollback */ 828 free((caddr_t)sc->gif_psrc, M_IFADDR); 829 free((caddr_t)sc->gif_pdst, M_IFADDR); 830 sc->gif_psrc = osrc; 831 sc->gif_pdst = odst; 832 goto bad; 833 } 834 835 if (osrc) 836 free((caddr_t)osrc, M_IFADDR); 837 if (odst) 838 free((caddr_t)odst, M_IFADDR); 839 840 if (sc->gif_psrc && sc->gif_pdst) 841 ifp->if_flags |= IFF_RUNNING; 842 else 843 ifp->if_flags &= ~IFF_RUNNING; 844 splx(s); 845 846 return 0; 847 848 bad: 849 if (sc->gif_psrc && sc->gif_pdst) 850 ifp->if_flags |= IFF_RUNNING; 851 else 852 ifp->if_flags &= ~IFF_RUNNING; 853 splx(s); 854 855 return error; 856} 857 858void 859gif_delete_tunnel(ifp) 860 struct ifnet *ifp; 861{ 862 struct gif_softc *sc = (struct gif_softc *)ifp; 863 int s; 864 865 s = splnet(); 866 867 if (sc->gif_psrc) { 868 free((caddr_t)sc->gif_psrc, M_IFADDR); 869 sc->gif_psrc = NULL; 870 } 871 if (sc->gif_pdst) { 872 free((caddr_t)sc->gif_pdst, M_IFADDR); 873 sc->gif_pdst = NULL; 874 } 875 /* it is safe to detach from both */ 876#ifdef INET 877 (void)in_gif_detach(sc); 878#endif 879#ifdef INET6 880 (void)in6_gif_detach(sc); 881#endif 882 883 if (sc->gif_psrc && sc->gif_pdst) 884 ifp->if_flags |= IFF_RUNNING; 885 else 886 ifp->if_flags &= ~IFF_RUNNING; 887 splx(s); 888} 889