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