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 u_int32_t af = dst->sa_family; 353 bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 354 } 355 ifp->if_opackets++; 356 ifp->if_obytes += m->m_pkthdr.len; 357 358 /* inner AF-specific encapsulation */ 359 360 /* XXX should we check if our outer source is legal? */ 361 362 /* dispatch to output logic based on outer AF */ 363 switch (sc->gif_psrc->sa_family) { 364 #ifdef INET 365 case AF_INET: 366 error = in_gif_output(ifp, dst->sa_family, m); 367 break; 368 #endif 369 #ifdef INET6 370 case AF_INET6: 371 error = in6_gif_output(ifp, dst->sa_family, m); 372 break; 373 #endif 374 default: 375 m_freem(m); 376 error = ENETDOWN; 377 goto end; 378 } 379 380 end: 381 called = 0; /* reset recursion counter */ 382 if (error) 383 ifp->if_oerrors++; 384 return error; 385 } 386 387 void 388 gif_input(m, af, ifp) 389 struct mbuf *m; 390 int af; 391 struct ifnet *ifp; 392 { 393 int isr; 394 395 if (ifp == NULL) { 396 /* just in case */ 397 m_freem(m); 398 return; 399 } 400 401 m->m_pkthdr.rcvif = ifp; 402 403 #ifdef MAC 404 mac_create_mbuf_from_ifnet(ifp, m); 405 #endif 406 407 if (ifp->if_bpf) { 408 u_int32_t af1 = af; 409 bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 410 } 411 412 if (ng_gif_input_p != NULL) { 413 (*ng_gif_input_p)(ifp, &m, af); 414 if (m == NULL) 415 return; 416 } 417 418 /* 419 * Put the packet to the network layer input queue according to the 420 * specified address family. 421 * Note: older versions of gif_input directly called network layer 422 * input functions, e.g. ip6_input, here. We changed the policy to 423 * prevent too many recursive calls of such input functions, which 424 * might cause kernel panic. But the change may introduce another 425 * problem; if the input queue is full, packets are discarded. 426 * The kernel stack overflow really happened, and we believed 427 * queue-full rarely occurs, so we changed the policy. 428 */ 429 switch (af) { 430 #ifdef INET 431 case AF_INET: 432 isr = NETISR_IP; 433 break; 434 #endif 435 #ifdef INET6 436 case AF_INET6: 437 isr = NETISR_IPV6; 438 break; 439 #endif 440 default: 441 if (ng_gif_input_orphan_p != NULL) 442 (*ng_gif_input_orphan_p)(ifp, m, af); 443 else 444 m_freem(m); 445 return; 446 } 447 448 ifp->if_ipackets++; 449 ifp->if_ibytes += m->m_pkthdr.len; 450 netisr_dispatch(isr, m); 451 } 452 453 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 454 int 455 gif_ioctl(ifp, cmd, data) 456 struct ifnet *ifp; 457 u_long cmd; 458 caddr_t data; 459 { 460 struct gif_softc *sc = (struct gif_softc*)ifp; 461 struct ifreq *ifr = (struct ifreq*)data; 462 int error = 0, size; 463 struct sockaddr *dst, *src; 464 #ifdef SIOCSIFMTU /* xxx */ 465 u_long mtu; 466 #endif 467 468 switch (cmd) { 469 case SIOCSIFADDR: 470 ifp->if_flags |= IFF_UP; 471 break; 472 473 case SIOCSIFDSTADDR: 474 break; 475 476 case SIOCADDMULTI: 477 case SIOCDELMULTI: 478 break; 479 480 #ifdef SIOCSIFMTU /* xxx */ 481 case SIOCGIFMTU: 482 break; 483 484 case SIOCSIFMTU: 485 mtu = ifr->ifr_mtu; 486 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 487 return (EINVAL); 488 ifp->if_mtu = mtu; 489 break; 490 #endif /* SIOCSIFMTU */ 491 492 #ifdef INET 493 case SIOCSIFPHYADDR: 494 #endif 495 #ifdef INET6 496 case SIOCSIFPHYADDR_IN6: 497 #endif /* INET6 */ 498 case SIOCSLIFPHYADDR: 499 switch (cmd) { 500 #ifdef INET 501 case SIOCSIFPHYADDR: 502 src = (struct sockaddr *) 503 &(((struct in_aliasreq *)data)->ifra_addr); 504 dst = (struct sockaddr *) 505 &(((struct in_aliasreq *)data)->ifra_dstaddr); 506 break; 507 #endif 508 #ifdef INET6 509 case SIOCSIFPHYADDR_IN6: 510 src = (struct sockaddr *) 511 &(((struct in6_aliasreq *)data)->ifra_addr); 512 dst = (struct sockaddr *) 513 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 514 break; 515 #endif 516 case SIOCSLIFPHYADDR: 517 src = (struct sockaddr *) 518 &(((struct if_laddrreq *)data)->addr); 519 dst = (struct sockaddr *) 520 &(((struct if_laddrreq *)data)->dstaddr); 521 break; 522 default: 523 return EINVAL; 524 } 525 526 /* sa_family must be equal */ 527 if (src->sa_family != dst->sa_family) 528 return EINVAL; 529 530 /* validate sa_len */ 531 switch (src->sa_family) { 532 #ifdef INET 533 case AF_INET: 534 if (src->sa_len != sizeof(struct sockaddr_in)) 535 return EINVAL; 536 break; 537 #endif 538 #ifdef INET6 539 case AF_INET6: 540 if (src->sa_len != sizeof(struct sockaddr_in6)) 541 return EINVAL; 542 break; 543 #endif 544 default: 545 return EAFNOSUPPORT; 546 } 547 switch (dst->sa_family) { 548 #ifdef INET 549 case AF_INET: 550 if (dst->sa_len != sizeof(struct sockaddr_in)) 551 return EINVAL; 552 break; 553 #endif 554 #ifdef INET6 555 case AF_INET6: 556 if (dst->sa_len != sizeof(struct sockaddr_in6)) 557 return EINVAL; 558 break; 559 #endif 560 default: 561 return EAFNOSUPPORT; 562 } 563 564 /* check sa_family looks sane for the cmd */ 565 switch (cmd) { 566 case SIOCSIFPHYADDR: 567 if (src->sa_family == AF_INET) 568 break; 569 return EAFNOSUPPORT; 570 #ifdef INET6 571 case SIOCSIFPHYADDR_IN6: 572 if (src->sa_family == AF_INET6) 573 break; 574 return EAFNOSUPPORT; 575 #endif /* INET6 */ 576 case SIOCSLIFPHYADDR: 577 /* checks done in the above */ 578 break; 579 } 580 581 error = gif_set_tunnel(&sc->gif_if, src, dst); 582 break; 583 584 #ifdef SIOCDIFPHYADDR 585 case SIOCDIFPHYADDR: 586 gif_delete_tunnel(&sc->gif_if); 587 break; 588 #endif 589 590 case SIOCGIFPSRCADDR: 591 #ifdef INET6 592 case SIOCGIFPSRCADDR_IN6: 593 #endif /* INET6 */ 594 if (sc->gif_psrc == NULL) { 595 error = EADDRNOTAVAIL; 596 goto bad; 597 } 598 src = sc->gif_psrc; 599 switch (cmd) { 600 #ifdef INET 601 case SIOCGIFPSRCADDR: 602 dst = &ifr->ifr_addr; 603 size = sizeof(ifr->ifr_addr); 604 break; 605 #endif /* INET */ 606 #ifdef INET6 607 case SIOCGIFPSRCADDR_IN6: 608 dst = (struct sockaddr *) 609 &(((struct in6_ifreq *)data)->ifr_addr); 610 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 611 break; 612 #endif /* INET6 */ 613 default: 614 error = EADDRNOTAVAIL; 615 goto bad; 616 } 617 if (src->sa_len > size) 618 return EINVAL; 619 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 620 break; 621 622 case SIOCGIFPDSTADDR: 623 #ifdef INET6 624 case SIOCGIFPDSTADDR_IN6: 625 #endif /* INET6 */ 626 if (sc->gif_pdst == NULL) { 627 error = EADDRNOTAVAIL; 628 goto bad; 629 } 630 src = sc->gif_pdst; 631 switch (cmd) { 632 #ifdef INET 633 case SIOCGIFPDSTADDR: 634 dst = &ifr->ifr_addr; 635 size = sizeof(ifr->ifr_addr); 636 break; 637 #endif /* INET */ 638 #ifdef INET6 639 case SIOCGIFPDSTADDR_IN6: 640 dst = (struct sockaddr *) 641 &(((struct in6_ifreq *)data)->ifr_addr); 642 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 643 break; 644 #endif /* INET6 */ 645 default: 646 error = EADDRNOTAVAIL; 647 goto bad; 648 } 649 if (src->sa_len > size) 650 return EINVAL; 651 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 652 break; 653 654 case SIOCGLIFPHYADDR: 655 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 656 error = EADDRNOTAVAIL; 657 goto bad; 658 } 659 660 /* copy src */ 661 src = sc->gif_psrc; 662 dst = (struct sockaddr *) 663 &(((struct if_laddrreq *)data)->addr); 664 size = sizeof(((struct if_laddrreq *)data)->addr); 665 if (src->sa_len > size) 666 return EINVAL; 667 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 668 669 /* copy dst */ 670 src = sc->gif_pdst; 671 dst = (struct sockaddr *) 672 &(((struct if_laddrreq *)data)->dstaddr); 673 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 674 if (src->sa_len > size) 675 return EINVAL; 676 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 677 break; 678 679 case SIOCSIFFLAGS: 680 /* if_ioctl() takes care of it */ 681 break; 682 683 default: 684 error = EINVAL; 685 break; 686 } 687 bad: 688 return error; 689 } 690 691 int 692 gif_set_tunnel(ifp, src, dst) 693 struct ifnet *ifp; 694 struct sockaddr *src; 695 struct sockaddr *dst; 696 { 697 struct gif_softc *sc = (struct gif_softc *)ifp; 698 struct gif_softc *sc2; 699 struct sockaddr *osrc, *odst, *sa; 700 int s; 701 int error = 0; 702 703 s = splnet(); 704 705 LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 706 if (sc2 == sc) 707 continue; 708 if (!sc2->gif_pdst || !sc2->gif_psrc) 709 continue; 710 if (sc2->gif_pdst->sa_family != dst->sa_family || 711 sc2->gif_pdst->sa_len != dst->sa_len || 712 sc2->gif_psrc->sa_family != src->sa_family || 713 sc2->gif_psrc->sa_len != src->sa_len) 714 continue; 715 716 /* 717 * Disallow parallel tunnels unless instructed 718 * otherwise. 719 */ 720 if (!parallel_tunnels && 721 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 722 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 723 error = EADDRNOTAVAIL; 724 goto bad; 725 } 726 727 /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 728 } 729 730 /* XXX we can detach from both, but be polite just in case */ 731 if (sc->gif_psrc) 732 switch (sc->gif_psrc->sa_family) { 733 #ifdef INET 734 case AF_INET: 735 (void)in_gif_detach(sc); 736 break; 737 #endif 738 #ifdef INET6 739 case AF_INET6: 740 (void)in6_gif_detach(sc); 741 break; 742 #endif 743 } 744 745 osrc = sc->gif_psrc; 746 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 747 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 748 sc->gif_psrc = sa; 749 750 odst = sc->gif_pdst; 751 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 752 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 753 sc->gif_pdst = sa; 754 755 switch (sc->gif_psrc->sa_family) { 756 #ifdef INET 757 case AF_INET: 758 error = in_gif_attach(sc); 759 break; 760 #endif 761 #ifdef INET6 762 case AF_INET6: 763 error = in6_gif_attach(sc); 764 break; 765 #endif 766 } 767 if (error) { 768 /* rollback */ 769 free((caddr_t)sc->gif_psrc, M_IFADDR); 770 free((caddr_t)sc->gif_pdst, M_IFADDR); 771 sc->gif_psrc = osrc; 772 sc->gif_pdst = odst; 773 goto bad; 774 } 775 776 if (osrc) 777 free((caddr_t)osrc, M_IFADDR); 778 if (odst) 779 free((caddr_t)odst, M_IFADDR); 780 781 if (sc->gif_psrc && sc->gif_pdst) 782 ifp->if_flags |= IFF_RUNNING; 783 else 784 ifp->if_flags &= ~IFF_RUNNING; 785 splx(s); 786 787 return 0; 788 789 bad: 790 if (sc->gif_psrc && sc->gif_pdst) 791 ifp->if_flags |= IFF_RUNNING; 792 else 793 ifp->if_flags &= ~IFF_RUNNING; 794 splx(s); 795 796 return error; 797 } 798 799 void 800 gif_delete_tunnel(ifp) 801 struct ifnet *ifp; 802 { 803 struct gif_softc *sc = (struct gif_softc *)ifp; 804 int s; 805 806 s = splnet(); 807 808 if (sc->gif_psrc) { 809 free((caddr_t)sc->gif_psrc, M_IFADDR); 810 sc->gif_psrc = NULL; 811 } 812 if (sc->gif_pdst) { 813 free((caddr_t)sc->gif_pdst, M_IFADDR); 814 sc->gif_pdst = NULL; 815 } 816 /* it is safe to detach from both */ 817 #ifdef INET 818 (void)in_gif_detach(sc); 819 #endif 820 #ifdef INET6 821 (void)in6_gif_detach(sc); 822 #endif 823 824 if (sc->gif_psrc && sc->gif_pdst) 825 ifp->if_flags |= IFF_RUNNING; 826 else 827 ifp->if_flags &= ~IFF_RUNNING; 828 splx(s); 829 } 830