1 /* $NetBSD: if_gif.c,v 1.75 2008/06/15 16:37:21 christos 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.75 2008/06/15 16:37:21 christos Exp $"); 35 36 #include "opt_inet.h" 37 #include "opt_iso.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/mbuf.h> 43 #include <sys/socket.h> 44 #include <sys/sockio.h> 45 #include <sys/errno.h> 46 #include <sys/ioctl.h> 47 #include <sys/time.h> 48 #include <sys/syslog.h> 49 #include <sys/proc.h> 50 #include <sys/protosw.h> 51 #include <sys/kauth.h> 52 #include <sys/cpu.h> 53 #include <sys/intr.h> 54 55 #include <net/if.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 #endif /* INET */ 67 #include <netinet/in_gif.h> 68 69 #ifdef INET6 70 #ifndef INET 71 #include <netinet/in.h> 72 #endif 73 #include <netinet6/in6_var.h> 74 #include <netinet/ip6.h> 75 #include <netinet6/ip6_var.h> 76 #include <netinet6/in6_gif.h> 77 #include <netinet6/ip6protosw.h> 78 #endif /* INET6 */ 79 80 #ifdef ISO 81 #include <netiso/iso.h> 82 #include <netiso/iso_var.h> 83 #endif 84 85 #include <netinet/ip_encap.h> 86 #include <net/if_gif.h> 87 88 #include "bpfilter.h" 89 90 #include <net/net_osdep.h> 91 92 void gifattach(int); 93 static void gifintr(void *); 94 #ifdef ISO 95 static struct mbuf *gif_eon_encap(struct mbuf *); 96 static struct mbuf *gif_eon_decap(struct ifnet *, struct mbuf *); 97 #endif 98 99 /* 100 * gif global variable definitions 101 */ 102 LIST_HEAD(, gif_softc) gif_softc_list; /* XXX should be static */ 103 104 static int gif_clone_create(struct if_clone *, int); 105 static int gif_clone_destroy(struct ifnet *); 106 107 static struct if_clone gif_cloner = 108 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); 109 110 #ifndef MAX_GIF_NEST 111 /* 112 * This macro controls the upper limitation on nesting of gif tunnels. 113 * Since, setting a large value to this macro with a careless configuration 114 * may introduce system crash, we don't allow any nestings by default. 115 * If you need to configure nested gif tunnels, you can define this macro 116 * in your kernel configuration file. However, if you do so, please be 117 * careful to configure the tunnels so that it won't make a loop. 118 */ 119 #define MAX_GIF_NEST 1 120 #endif 121 static int max_gif_nesting = MAX_GIF_NEST; 122 123 /* ARGSUSED */ 124 void 125 gifattach(int count) 126 { 127 128 LIST_INIT(&gif_softc_list); 129 if_clone_attach(&gif_cloner); 130 } 131 132 static int 133 gif_clone_create(struct if_clone *ifc, int unit) 134 { 135 struct gif_softc *sc; 136 137 sc = malloc(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK|M_ZERO); 138 139 if_initname(&sc->gif_if, ifc->ifc_name, unit); 140 141 gifattach0(sc); 142 143 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 144 return (0); 145 } 146 147 void 148 gifattach0(struct gif_softc *sc) 149 { 150 151 sc->encap_cookie4 = sc->encap_cookie6 = NULL; 152 153 sc->gif_if.if_addrlen = 0; 154 sc->gif_if.if_mtu = GIF_MTU; 155 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 156 sc->gif_if.if_ioctl = gif_ioctl; 157 sc->gif_if.if_output = gif_output; 158 sc->gif_if.if_type = IFT_GIF; 159 sc->gif_if.if_dlt = DLT_NULL; 160 IFQ_SET_READY(&sc->gif_if.if_snd); 161 if_attach(&sc->gif_if); 162 if_alloc_sadl(&sc->gif_if); 163 #if NBPFILTER > 0 164 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 165 #endif 166 } 167 168 static int 169 gif_clone_destroy(struct ifnet *ifp) 170 { 171 struct gif_softc *sc = (void *) ifp; 172 173 gif_delete_tunnel(&sc->gif_if); 174 LIST_REMOVE(sc, gif_list); 175 #ifdef INET6 176 encap_detach(sc->encap_cookie6); 177 #endif 178 #ifdef INET 179 encap_detach(sc->encap_cookie4); 180 #endif 181 182 #if NBPFILTER > 0 183 bpfdetach(ifp); 184 #endif 185 if_detach(ifp); 186 rtcache_free(&sc->gif_ro); 187 188 free(sc, M_DEVBUF); 189 190 return (0); 191 } 192 193 #ifdef GIF_ENCAPCHECK 194 int 195 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg) 196 { 197 struct ip ip; 198 struct gif_softc *sc; 199 200 sc = (struct gif_softc *)arg; 201 if (sc == NULL) 202 return 0; 203 204 if ((sc->gif_if.if_flags & IFF_UP) == 0) 205 return 0; 206 207 /* no physical address */ 208 if (!sc->gif_psrc || !sc->gif_pdst) 209 return 0; 210 211 switch (proto) { 212 #ifdef INET 213 case IPPROTO_IPV4: 214 break; 215 #endif 216 #ifdef INET6 217 case IPPROTO_IPV6: 218 break; 219 #endif 220 #ifdef ISO 221 case IPPROTO_EON: 222 break; 223 #endif 224 default: 225 return 0; 226 } 227 228 /* Bail on short packets */ 229 KASSERT(m->m_flags & M_PKTHDR); 230 if (m->m_pkthdr.len < sizeof(ip)) 231 return 0; 232 233 m_copydata(m, 0, sizeof(ip), (void *)&ip); 234 235 switch (ip.ip_v) { 236 #ifdef INET 237 case 4: 238 if (sc->gif_psrc->sa_family != AF_INET || 239 sc->gif_pdst->sa_family != AF_INET) 240 return 0; 241 return gif_encapcheck4(m, off, proto, arg); 242 #endif 243 #ifdef INET6 244 case 6: 245 if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 246 return 0; 247 if (sc->gif_psrc->sa_family != AF_INET6 || 248 sc->gif_pdst->sa_family != AF_INET6) 249 return 0; 250 return gif_encapcheck6(m, off, proto, arg); 251 #endif 252 default: 253 return 0; 254 } 255 } 256 #endif 257 258 int 259 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 260 struct rtentry *rt) 261 { 262 struct gif_softc *sc = (struct gif_softc*)ifp; 263 int error = 0; 264 static int called = 0; /* XXX: MUTEX */ 265 ALTQ_DECL(struct altq_pktattr pktattr;) 266 int s; 267 268 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr); 269 270 /* 271 * gif may cause infinite recursion calls when misconfigured. 272 * We'll prevent this by introducing upper limit. 273 * XXX: this mechanism may introduce another problem about 274 * mutual exclusion of the variable CALLED, especially if we 275 * use kernel thread. 276 */ 277 if (++called > max_gif_nesting) { 278 log(LOG_NOTICE, 279 "gif_output: recursively called too many times(%d)\n", 280 called); 281 m_freem(m); 282 error = EIO; /* is there better errno? */ 283 goto end; 284 } 285 286 m->m_flags &= ~(M_BCAST|M_MCAST); 287 if (!(ifp->if_flags & IFF_UP) || 288 sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 289 m_freem(m); 290 error = ENETDOWN; 291 goto end; 292 } 293 294 /* inner AF-specific encapsulation */ 295 switch (dst->sa_family) { 296 #ifdef ISO 297 case AF_ISO: 298 m = gif_eon_encap(m); 299 if (!m) { 300 error = ENOBUFS; 301 goto end; 302 } 303 break; 304 #endif 305 default: 306 break; 307 } 308 309 /* XXX should we check if our outer source is legal? */ 310 311 /* use DLT_NULL encapsulation here to pass inner af type */ 312 M_PREPEND(m, sizeof(int), M_DONTWAIT); 313 if (!m) { 314 error = ENOBUFS; 315 goto end; 316 } 317 *mtod(m, int *) = dst->sa_family; 318 319 s = splnet(); 320 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error); 321 if (error) { 322 splx(s); 323 goto end; 324 } 325 splx(s); 326 327 softint_schedule(sc->gif_si); 328 error = 0; 329 330 end: 331 called = 0; /* reset recursion counter */ 332 if (error) 333 ifp->if_oerrors++; 334 return error; 335 } 336 337 static void 338 gifintr(void *arg) 339 { 340 struct gif_softc *sc; 341 struct ifnet *ifp; 342 struct mbuf *m; 343 int family; 344 int len; 345 int s; 346 int error; 347 348 sc = (struct gif_softc *)arg; 349 ifp = &sc->gif_if; 350 351 /* output processing */ 352 while (1) { 353 s = splnet(); 354 IFQ_DEQUEUE(&sc->gif_if.if_snd, m); 355 splx(s); 356 if (m == NULL) 357 break; 358 359 /* grab and chop off inner af type */ 360 if (sizeof(int) > m->m_len) { 361 m = m_pullup(m, sizeof(int)); 362 if (!m) { 363 ifp->if_oerrors++; 364 continue; 365 } 366 } 367 family = *mtod(m, int *); 368 #if NBPFILTER > 0 369 if (ifp->if_bpf) 370 bpf_mtap(ifp->if_bpf, m); 371 #endif 372 m_adj(m, sizeof(int)); 373 374 len = m->m_pkthdr.len; 375 376 /* dispatch to output logic based on outer AF */ 377 switch (sc->gif_psrc->sa_family) { 378 #ifdef INET 379 case AF_INET: 380 error = in_gif_output(ifp, family, m); 381 break; 382 #endif 383 #ifdef INET6 384 case AF_INET6: 385 error = in6_gif_output(ifp, family, m); 386 break; 387 #endif 388 default: 389 m_freem(m); 390 error = ENETDOWN; 391 break; 392 } 393 394 if (error) 395 ifp->if_oerrors++; 396 else { 397 ifp->if_opackets++; 398 ifp->if_obytes += len; 399 } 400 } 401 } 402 403 void 404 gif_input(struct mbuf *m, int af, struct ifnet *ifp) 405 { 406 int s, isr; 407 struct ifqueue *ifq = NULL; 408 409 if (ifp == NULL) { 410 /* just in case */ 411 m_freem(m); 412 return; 413 } 414 415 m->m_pkthdr.rcvif = ifp; 416 417 #if NBPFILTER > 0 418 if (ifp->if_bpf) 419 bpf_mtap_af(ifp->if_bpf, af, m); 420 #endif /*NBPFILTER > 0*/ 421 422 /* 423 * Put the packet to the network layer input queue according to the 424 * specified address family. 425 * Note: older versions of gif_input directly called network layer 426 * input functions, e.g. ip6_input, here. We changed the policy to 427 * prevent too many recursive calls of such input functions, which 428 * might cause kernel panic. But the change may introduce another 429 * problem; if the input queue is full, packets are discarded. 430 * The kernel stack overflow really happened, and we believed 431 * queue-full rarely occurs, so we changed the policy. 432 */ 433 switch (af) { 434 #ifdef INET 435 case AF_INET: 436 ifq = &ipintrq; 437 isr = NETISR_IP; 438 break; 439 #endif 440 #ifdef INET6 441 case AF_INET6: 442 ifq = &ip6intrq; 443 isr = NETISR_IPV6; 444 break; 445 #endif 446 #ifdef ISO 447 case AF_ISO: 448 m = gif_eon_decap(ifp, m); 449 if (!m) 450 return; 451 ifq = &clnlintrq; 452 isr = NETISR_ISO; 453 break; 454 #endif 455 default: 456 m_freem(m); 457 return; 458 } 459 460 s = splnet(); 461 if (IF_QFULL(ifq)) { 462 IF_DROP(ifq); /* update statistics */ 463 m_freem(m); 464 splx(s); 465 return; 466 } 467 ifp->if_ipackets++; 468 ifp->if_ibytes += m->m_pkthdr.len; 469 IF_ENQUEUE(ifq, m); 470 /* we need schednetisr since the address family may change */ 471 schednetisr(isr); 472 splx(s); 473 } 474 475 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 476 int 477 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data) 478 { 479 struct lwp *l = curlwp; /* XXX */ 480 struct gif_softc *sc = (struct gif_softc*)ifp; 481 struct ifreq *ifr = (struct ifreq*)data; 482 int error = 0, size; 483 struct sockaddr *dst, *src; 484 485 switch (cmd) { 486 case SIOCSIFMTU: 487 case SIOCSLIFPHYADDR: 488 #ifdef SIOCDIFPHYADDR 489 case SIOCDIFPHYADDR: 490 #endif 491 if ((error = kauth_authorize_network(l->l_cred, 492 KAUTH_NETWORK_INTERFACE, 493 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 494 NULL)) != 0) 495 return (error); 496 /* FALLTHROUGH */ 497 default: 498 break; 499 } 500 501 switch (cmd) { 502 case SIOCSIFADDR: 503 ifp->if_flags |= IFF_UP; 504 break; 505 506 case SIOCSIFDSTADDR: 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 SIOCGIFMTU: 527 break; 528 529 case SIOCSIFMTU: 530 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) 531 return EINVAL; 532 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 533 error = 0; 534 break; 535 536 #ifdef INET 537 case SIOCSIFPHYADDR: 538 #endif 539 #ifdef INET6 540 case SIOCSIFPHYADDR_IN6: 541 #endif /* INET6 */ 542 case SIOCSLIFPHYADDR: 543 switch (cmd) { 544 #ifdef INET 545 case SIOCSIFPHYADDR: 546 src = (struct sockaddr *) 547 &(((struct in_aliasreq *)data)->ifra_addr); 548 dst = (struct sockaddr *) 549 &(((struct in_aliasreq *)data)->ifra_dstaddr); 550 break; 551 #endif 552 #ifdef INET6 553 case SIOCSIFPHYADDR_IN6: 554 src = (struct sockaddr *) 555 &(((struct in6_aliasreq *)data)->ifra_addr); 556 dst = (struct sockaddr *) 557 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 558 break; 559 #endif 560 case SIOCSLIFPHYADDR: 561 src = (struct sockaddr *) 562 &(((struct if_laddrreq *)data)->addr); 563 dst = (struct sockaddr *) 564 &(((struct if_laddrreq *)data)->dstaddr); 565 break; 566 default: 567 return EINVAL; 568 } 569 570 /* sa_family must be equal */ 571 if (src->sa_family != dst->sa_family) 572 return EINVAL; 573 574 /* validate sa_len */ 575 switch (src->sa_family) { 576 #ifdef INET 577 case AF_INET: 578 if (src->sa_len != sizeof(struct sockaddr_in)) 579 return EINVAL; 580 break; 581 #endif 582 #ifdef INET6 583 case AF_INET6: 584 if (src->sa_len != sizeof(struct sockaddr_in6)) 585 return EINVAL; 586 break; 587 #endif 588 default: 589 return EAFNOSUPPORT; 590 } 591 switch (dst->sa_family) { 592 #ifdef INET 593 case AF_INET: 594 if (dst->sa_len != sizeof(struct sockaddr_in)) 595 return EINVAL; 596 break; 597 #endif 598 #ifdef INET6 599 case AF_INET6: 600 if (dst->sa_len != sizeof(struct sockaddr_in6)) 601 return EINVAL; 602 break; 603 #endif 604 default: 605 return EAFNOSUPPORT; 606 } 607 608 /* check sa_family looks sane for the cmd */ 609 switch (cmd) { 610 case SIOCSIFPHYADDR: 611 if (src->sa_family == AF_INET) 612 break; 613 return EAFNOSUPPORT; 614 #ifdef INET6 615 case SIOCSIFPHYADDR_IN6: 616 if (src->sa_family == AF_INET6) 617 break; 618 return EAFNOSUPPORT; 619 #endif /* INET6 */ 620 case SIOCSLIFPHYADDR: 621 /* checks done in the above */ 622 break; 623 } 624 625 error = gif_set_tunnel(&sc->gif_if, src, dst); 626 break; 627 628 #ifdef SIOCDIFPHYADDR 629 case SIOCDIFPHYADDR: 630 gif_delete_tunnel(&sc->gif_if); 631 break; 632 #endif 633 634 case SIOCGIFPSRCADDR: 635 #ifdef INET6 636 case SIOCGIFPSRCADDR_IN6: 637 #endif /* INET6 */ 638 if (sc->gif_psrc == NULL) { 639 error = EADDRNOTAVAIL; 640 goto bad; 641 } 642 src = sc->gif_psrc; 643 switch (cmd) { 644 #ifdef INET 645 case SIOCGIFPSRCADDR: 646 dst = &ifr->ifr_addr; 647 size = sizeof(ifr->ifr_addr); 648 break; 649 #endif /* INET */ 650 #ifdef INET6 651 case SIOCGIFPSRCADDR_IN6: 652 dst = (struct sockaddr *) 653 &(((struct in6_ifreq *)data)->ifr_addr); 654 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 655 break; 656 #endif /* INET6 */ 657 default: 658 error = EADDRNOTAVAIL; 659 goto bad; 660 } 661 if (src->sa_len > size) 662 return EINVAL; 663 memcpy(dst, src, src->sa_len); 664 break; 665 666 case SIOCGIFPDSTADDR: 667 #ifdef INET6 668 case SIOCGIFPDSTADDR_IN6: 669 #endif /* INET6 */ 670 if (sc->gif_pdst == NULL) { 671 error = EADDRNOTAVAIL; 672 goto bad; 673 } 674 src = sc->gif_pdst; 675 switch (cmd) { 676 #ifdef INET 677 case SIOCGIFPDSTADDR: 678 dst = &ifr->ifr_addr; 679 size = sizeof(ifr->ifr_addr); 680 break; 681 #endif /* INET */ 682 #ifdef INET6 683 case SIOCGIFPDSTADDR_IN6: 684 dst = (struct sockaddr *) 685 &(((struct in6_ifreq *)data)->ifr_addr); 686 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 687 break; 688 #endif /* INET6 */ 689 default: 690 error = EADDRNOTAVAIL; 691 goto bad; 692 } 693 if (src->sa_len > size) 694 return EINVAL; 695 memcpy(dst, src, src->sa_len); 696 break; 697 698 case SIOCGLIFPHYADDR: 699 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 700 error = EADDRNOTAVAIL; 701 goto bad; 702 } 703 704 /* copy src */ 705 src = sc->gif_psrc; 706 dst = (struct sockaddr *) 707 &(((struct if_laddrreq *)data)->addr); 708 size = sizeof(((struct if_laddrreq *)data)->addr); 709 if (src->sa_len > size) 710 return EINVAL; 711 memcpy(dst, src, src->sa_len); 712 713 /* copy dst */ 714 src = sc->gif_pdst; 715 dst = (struct sockaddr *) 716 &(((struct if_laddrreq *)data)->dstaddr); 717 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 718 if (src->sa_len > size) 719 return EINVAL; 720 memcpy(dst, src, src->sa_len); 721 break; 722 723 case SIOCSIFFLAGS: 724 /* if_ioctl() takes care of it */ 725 break; 726 727 default: 728 error = EINVAL; 729 break; 730 } 731 bad: 732 return error; 733 } 734 735 int 736 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) 737 { 738 struct gif_softc *sc = (struct gif_softc *)ifp; 739 struct gif_softc *sc2; 740 struct sockaddr *osrc, *odst; 741 int s; 742 int error; 743 744 s = splsoftnet(); 745 746 LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 747 if (sc2 == sc) 748 continue; 749 if (!sc2->gif_pdst || !sc2->gif_psrc) 750 continue; 751 /* can't configure same pair of address onto two gifs */ 752 if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 && 753 sockaddr_cmp(sc2->gif_psrc, src) == 0) { 754 error = EADDRNOTAVAIL; 755 goto bad; 756 } 757 758 /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 759 } 760 761 if (sc->gif_si) { 762 softint_disestablish(sc->gif_si); 763 sc->gif_si = NULL; 764 } 765 766 /* XXX we can detach from both, but be polite just in case */ 767 if (sc->gif_psrc) 768 switch (sc->gif_psrc->sa_family) { 769 #ifdef INET 770 case AF_INET: 771 (void)in_gif_detach(sc); 772 break; 773 #endif 774 #ifdef INET6 775 case AF_INET6: 776 (void)in6_gif_detach(sc); 777 break; 778 #endif 779 } 780 781 sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc); 782 if (sc->gif_si == NULL) { 783 error = ENOMEM; 784 goto bad; 785 } 786 787 osrc = sc->gif_psrc; 788 sc->gif_psrc = sockaddr_dup(src, M_WAITOK); 789 790 odst = sc->gif_pdst; 791 sc->gif_pdst = sockaddr_dup(dst, M_WAITOK); 792 793 switch (sc->gif_psrc->sa_family) { 794 #ifdef INET 795 case AF_INET: 796 error = in_gif_attach(sc); 797 break; 798 #endif 799 #ifdef INET6 800 case AF_INET6: 801 error = in6_gif_attach(sc); 802 break; 803 #endif 804 default: 805 error = EINVAL; 806 break; 807 } 808 if (error) { 809 /* rollback */ 810 sockaddr_free(sc->gif_psrc); 811 sockaddr_free(sc->gif_pdst); 812 sc->gif_psrc = osrc; 813 sc->gif_pdst = odst; 814 goto bad; 815 } 816 817 if (osrc) 818 sockaddr_free(osrc); 819 if (odst) 820 sockaddr_free(odst); 821 822 if (sc->gif_psrc && sc->gif_pdst) 823 ifp->if_flags |= IFF_RUNNING; 824 else 825 ifp->if_flags &= ~IFF_RUNNING; 826 splx(s); 827 828 return 0; 829 830 bad: 831 if (sc->gif_si) { 832 softint_disestablish(sc->gif_si); 833 sc->gif_si = NULL; 834 } 835 if (sc->gif_psrc && sc->gif_pdst) 836 ifp->if_flags |= IFF_RUNNING; 837 else 838 ifp->if_flags &= ~IFF_RUNNING; 839 splx(s); 840 841 return error; 842 } 843 844 void 845 gif_delete_tunnel(struct ifnet *ifp) 846 { 847 struct gif_softc *sc = (struct gif_softc *)ifp; 848 int s; 849 850 s = splsoftnet(); 851 852 if (sc->gif_si) { 853 softint_disestablish(sc->gif_si); 854 sc->gif_si = NULL; 855 } 856 if (sc->gif_psrc) { 857 sockaddr_free(sc->gif_psrc); 858 sc->gif_psrc = NULL; 859 } 860 if (sc->gif_pdst) { 861 sockaddr_free(sc->gif_pdst); 862 sc->gif_pdst = NULL; 863 } 864 /* it is safe to detach from both */ 865 #ifdef INET 866 (void)in_gif_detach(sc); 867 #endif 868 #ifdef INET6 869 (void)in6_gif_detach(sc); 870 #endif 871 872 if (sc->gif_psrc && sc->gif_pdst) 873 ifp->if_flags |= IFF_RUNNING; 874 else 875 ifp->if_flags &= ~IFF_RUNNING; 876 splx(s); 877 } 878 879 #ifdef ISO 880 struct eonhdr { 881 uint8_t version; 882 uint8_t class; 883 uint16_t cksum; 884 }; 885 886 /* 887 * prepend EON header to ISO PDU 888 */ 889 static struct mbuf * 890 gif_eon_encap(struct mbuf *m) 891 { 892 struct eonhdr *ehdr; 893 894 M_PREPEND(m, sizeof(*ehdr), M_DONTWAIT); 895 if (m && m->m_len < sizeof(*ehdr)) 896 m = m_pullup(m, sizeof(*ehdr)); 897 if (m == NULL) 898 return NULL; 899 ehdr = mtod(m, struct eonhdr *); 900 ehdr->version = 1; 901 ehdr->class = 0; /* always unicast */ 902 #if 0 903 /* calculate the checksum of the eonhdr */ 904 { 905 struct mbuf mhead; 906 memset(&mhead, 0, sizeof(mhead)); 907 ehdr->cksum = 0; 908 mhead.m_data = (void *)ehdr; 909 mhead.m_len = sizeof(*ehdr); 910 mhead.m_next = 0; 911 iso_gen_csum(&mhead, offsetof(struct eonhdr, cksum), 912 mhead.m_len); 913 } 914 #else 915 /* since the data is always constant we'll just plug the value in */ 916 ehdr->cksum = htons(0xfc02); 917 #endif 918 return m; 919 } 920 921 /* 922 * remove EON header and check checksum 923 */ 924 static struct mbuf * 925 gif_eon_decap(struct ifnet *ifp, struct mbuf *m) 926 { 927 struct eonhdr *ehdr; 928 929 if (m->m_len < sizeof(*ehdr) && 930 (m = m_pullup(m, sizeof(*ehdr))) == NULL) { 931 ifp->if_ierrors++; 932 return NULL; 933 } 934 if (iso_check_csum(m, sizeof(struct eonhdr))) { 935 m_freem(m); 936 return NULL; 937 } 938 m_adj(m, sizeof(*ehdr)); 939 return m; 940 } 941 #endif /*ISO*/ 942