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