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