1 /* $NetBSD: if_gif.c,v 1.49 2005/02/01 12:13:51 he 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.49 2005/02/01 12:13:51 he 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 const 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 /* LINTED const cast */ 267 m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); 268 269 switch (ip.ip_v) { 270 #ifdef INET 271 case 4: 272 if (sc->gif_psrc->sa_family != AF_INET || 273 sc->gif_pdst->sa_family != AF_INET) 274 return 0; 275 return gif_encapcheck4(m, off, proto, arg); 276 #endif 277 #ifdef INET6 278 case 6: 279 if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 280 return 0; 281 if (sc->gif_psrc->sa_family != AF_INET6 || 282 sc->gif_pdst->sa_family != AF_INET6) 283 return 0; 284 return gif_encapcheck6(m, off, proto, arg); 285 #endif 286 default: 287 return 0; 288 } 289 } 290 #endif 291 292 int 293 gif_output(ifp, m, dst, rt) 294 struct ifnet *ifp; 295 struct mbuf *m; 296 struct sockaddr *dst; 297 struct rtentry *rt; /* added in net2 */ 298 { 299 struct gif_softc *sc = (struct gif_softc*)ifp; 300 int error = 0; 301 static int called = 0; /* XXX: MUTEX */ 302 ALTQ_DECL(struct altq_pktattr pktattr;) 303 int s; 304 305 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr); 306 307 /* 308 * gif may cause infinite recursion calls when misconfigured. 309 * We'll prevent this by introducing upper limit. 310 * XXX: this mechanism may introduce another problem about 311 * mutual exclusion of the variable CALLED, especially if we 312 * use kernel thread. 313 */ 314 if (++called > max_gif_nesting) { 315 log(LOG_NOTICE, 316 "gif_output: recursively called too many times(%d)\n", 317 called); 318 m_freem(m); 319 error = EIO; /* is there better errno? */ 320 goto end; 321 } 322 323 m->m_flags &= ~(M_BCAST|M_MCAST); 324 if (!(ifp->if_flags & IFF_UP) || 325 sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 326 m_freem(m); 327 error = ENETDOWN; 328 goto end; 329 } 330 331 /* inner AF-specific encapsulation */ 332 switch (dst->sa_family) { 333 #ifdef ISO 334 case AF_ISO: 335 m = gif_eon_encap(m); 336 if (!m) { 337 error = ENOBUFS; 338 goto end; 339 } 340 break; 341 #endif 342 default: 343 break; 344 } 345 346 /* XXX should we check if our outer source is legal? */ 347 348 /* use DLT_NULL encapsulation here to pass inner af type */ 349 M_PREPEND(m, sizeof(int), M_DONTWAIT); 350 if (!m) { 351 error = ENOBUFS; 352 goto end; 353 } 354 *mtod(m, int *) = dst->sa_family; 355 356 s = splnet(); 357 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error); 358 if (error) { 359 splx(s); 360 goto end; 361 } 362 splx(s); 363 364 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS 365 softintr_schedule(sc->gif_si); 366 #else 367 /* XXX bad spl level? */ 368 gifnetisr(); 369 #endif 370 error = 0; 371 372 end: 373 called = 0; /* reset recursion counter */ 374 if (error) 375 ifp->if_oerrors++; 376 return error; 377 } 378 379 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS 380 void 381 gifnetisr() 382 { 383 struct gif_softc *sc; 384 385 for (sc = LIST_FIRST(&gif_softc_list); sc != NULL; 386 sc = LIST_NEXT(sc, gif_list)) { 387 gifintr(sc); 388 } 389 } 390 #endif 391 392 void 393 gifintr(arg) 394 void *arg; 395 { 396 struct gif_softc *sc; 397 struct ifnet *ifp; 398 struct mbuf *m; 399 int family; 400 int len; 401 int s; 402 int error; 403 404 sc = (struct gif_softc *)arg; 405 ifp = &sc->gif_if; 406 407 /* output processing */ 408 while (1) { 409 s = splnet(); 410 IFQ_DEQUEUE(&sc->gif_if.if_snd, m); 411 splx(s); 412 if (m == NULL) 413 break; 414 415 #if NBRIDGE > 0 416 if(m->m_flags & M_PROTO1) { 417 M_PREPEND(m, sizeof(int), M_DONTWAIT); 418 if (!m) { 419 ifp->if_oerrors++; 420 continue; 421 } 422 *mtod(m, int *) = AF_LINK; 423 } 424 425 #endif 426 /* grab and chop off inner af type */ 427 if (sizeof(int) > m->m_len) { 428 m = m_pullup(m, sizeof(int)); 429 if (!m) { 430 ifp->if_oerrors++; 431 continue; 432 } 433 } 434 family = *mtod(m, int *); 435 #if NBPFILTER > 0 436 if (ifp->if_bpf) 437 bpf_mtap(ifp->if_bpf, m); 438 #endif 439 m_adj(m, sizeof(int)); 440 441 len = m->m_pkthdr.len; 442 443 /* dispatch to output logic based on outer AF */ 444 switch (sc->gif_psrc->sa_family) { 445 #ifdef INET 446 case AF_INET: 447 error = in_gif_output(ifp, family, m); 448 break; 449 #endif 450 #ifdef INET6 451 case AF_INET6: 452 error = in6_gif_output(ifp, family, m); 453 break; 454 #endif 455 default: 456 m_freem(m); 457 error = ENETDOWN; 458 break; 459 } 460 461 if (error) 462 ifp->if_oerrors++; 463 else { 464 ifp->if_opackets++; 465 ifp->if_obytes += len; 466 } 467 } 468 } 469 470 void 471 gif_input(m, af, ifp) 472 struct mbuf *m; 473 int af; 474 struct ifnet *ifp; 475 { 476 int s, isr; 477 struct ifqueue *ifq = NULL; 478 #if NBRIDGE > 0 479 struct ether_header *eh; 480 #endif 481 482 if (ifp == NULL) { 483 /* just in case */ 484 m_freem(m); 485 return; 486 } 487 488 m->m_pkthdr.rcvif = ifp; 489 490 #if NBPFILTER > 0 491 if (ifp->if_bpf) 492 bpf_mtap_af(ifp->if_bpf, af, m); 493 #endif /*NBPFILTER > 0*/ 494 495 /* 496 * Put the packet to the network layer input queue according to the 497 * specified address family. 498 * Note: older versions of gif_input directly called network layer 499 * input functions, e.g. ip6_input, here. We changed the policy to 500 * prevent too many recursive calls of such input functions, which 501 * might cause kernel panic. But the change may introduce another 502 * problem; if the input queue is full, packets are discarded. 503 * The kernel stack overflow really happened, and we believed 504 * queue-full rarely occurs, so we changed the policy. 505 */ 506 switch (af) { 507 #ifdef INET 508 case AF_INET: 509 ifq = &ipintrq; 510 isr = NETISR_IP; 511 break; 512 #endif 513 #ifdef INET6 514 case AF_INET6: 515 ifq = &ip6intrq; 516 isr = NETISR_IPV6; 517 break; 518 #endif 519 #ifdef ISO 520 case AF_ISO: 521 m = gif_eon_decap(ifp, m); 522 if (!m) 523 return; 524 ifq = &clnlintrq; 525 isr = NETISR_ISO; 526 break; 527 #endif 528 #if NBRIDGE > 0 529 case AF_LINK: 530 m_adj(m, sizeof(struct etherip_header)); 531 if (sizeof(struct ether_header) > m->m_len) { 532 m = m_pullup(m, sizeof(struct ether_header)); 533 if (!m) { 534 ifp->if_ierrors++; 535 return; 536 } 537 } 538 eh = mtod(m, struct ether_header *); 539 m->m_flags &= ~(M_BCAST|M_MCAST); 540 if (eh->ether_dhost[0] & 1) { 541 if (bcmp((caddr_t) etherbroadcastaddr, 542 (caddr_t)eh->ether_dhost, sizeof(etherbroadcastaddr)) == 0) 543 m->m_flags |= M_BCAST; 544 else 545 m->m_flags |= M_MCAST; 546 } 547 m->m_pkthdr.rcvif = ifp; 548 if(ifp->if_bridge) { 549 if (m->m_flags & (M_BCAST|M_MCAST)) 550 ifp->if_imcasts++; 551 552 s = splnet(); 553 m = bridge_input(ifp, m); 554 splx(s); 555 if (m == NULL) 556 return; 557 } 558 #endif 559 default: 560 m_freem(m); 561 return; 562 } 563 564 s = splnet(); 565 if (IF_QFULL(ifq)) { 566 IF_DROP(ifq); /* update statistics */ 567 m_freem(m); 568 splx(s); 569 return; 570 } 571 ifp->if_ipackets++; 572 ifp->if_ibytes += m->m_pkthdr.len; 573 IF_ENQUEUE(ifq, m); 574 /* we need schednetisr since the address family may change */ 575 schednetisr(isr); 576 splx(s); 577 } 578 579 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 580 int 581 gif_ioctl(ifp, cmd, data) 582 struct ifnet *ifp; 583 u_long cmd; 584 caddr_t data; 585 { 586 struct proc *p = curproc; /* XXX */ 587 struct gif_softc *sc = (struct gif_softc*)ifp; 588 struct ifreq *ifr = (struct ifreq*)data; 589 int error = 0, size; 590 struct sockaddr *dst, *src; 591 #ifdef SIOCSIFMTU 592 u_long mtu; 593 #endif 594 595 switch (cmd) { 596 case SIOCSIFADDR: 597 ifp->if_flags |= IFF_UP; 598 break; 599 600 case SIOCSIFDSTADDR: 601 break; 602 603 case SIOCADDMULTI: 604 case SIOCDELMULTI: 605 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 606 break; 607 switch (ifr->ifr_addr.sa_family) { 608 #ifdef INET 609 case AF_INET: /* IP supports Multicast */ 610 break; 611 #endif /* INET */ 612 #ifdef INET6 613 case AF_INET6: /* IP6 supports Multicast */ 614 break; 615 #endif /* INET6 */ 616 default: /* Other protocols doesn't support Multicast */ 617 error = EAFNOSUPPORT; 618 break; 619 } 620 break; 621 622 #ifdef SIOCSIFMTU /* xxx */ 623 case SIOCGIFMTU: 624 break; 625 626 case SIOCSIFMTU: 627 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 628 break; 629 mtu = ifr->ifr_mtu; 630 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 631 return (EINVAL); 632 ifp->if_mtu = mtu; 633 break; 634 #endif /* SIOCSIFMTU */ 635 636 #ifdef INET 637 case SIOCSIFPHYADDR: 638 #endif 639 #ifdef INET6 640 case SIOCSIFPHYADDR_IN6: 641 #endif /* INET6 */ 642 case SIOCSLIFPHYADDR: 643 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 644 break; 645 switch (cmd) { 646 #ifdef INET 647 case SIOCSIFPHYADDR: 648 src = (struct sockaddr *) 649 &(((struct in_aliasreq *)data)->ifra_addr); 650 dst = (struct sockaddr *) 651 &(((struct in_aliasreq *)data)->ifra_dstaddr); 652 break; 653 #endif 654 #ifdef INET6 655 case SIOCSIFPHYADDR_IN6: 656 src = (struct sockaddr *) 657 &(((struct in6_aliasreq *)data)->ifra_addr); 658 dst = (struct sockaddr *) 659 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 660 break; 661 #endif 662 case SIOCSLIFPHYADDR: 663 src = (struct sockaddr *) 664 &(((struct if_laddrreq *)data)->addr); 665 dst = (struct sockaddr *) 666 &(((struct if_laddrreq *)data)->dstaddr); 667 break; 668 default: 669 return EINVAL; 670 } 671 672 /* sa_family must be equal */ 673 if (src->sa_family != dst->sa_family) 674 return EINVAL; 675 676 /* validate sa_len */ 677 switch (src->sa_family) { 678 #ifdef INET 679 case AF_INET: 680 if (src->sa_len != sizeof(struct sockaddr_in)) 681 return EINVAL; 682 break; 683 #endif 684 #ifdef INET6 685 case AF_INET6: 686 if (src->sa_len != sizeof(struct sockaddr_in6)) 687 return EINVAL; 688 break; 689 #endif 690 default: 691 return EAFNOSUPPORT; 692 } 693 switch (dst->sa_family) { 694 #ifdef INET 695 case AF_INET: 696 if (dst->sa_len != sizeof(struct sockaddr_in)) 697 return EINVAL; 698 break; 699 #endif 700 #ifdef INET6 701 case AF_INET6: 702 if (dst->sa_len != sizeof(struct sockaddr_in6)) 703 return EINVAL; 704 break; 705 #endif 706 default: 707 return EAFNOSUPPORT; 708 } 709 710 /* check sa_family looks sane for the cmd */ 711 switch (cmd) { 712 case SIOCSIFPHYADDR: 713 if (src->sa_family == AF_INET) 714 break; 715 return EAFNOSUPPORT; 716 #ifdef INET6 717 case SIOCSIFPHYADDR_IN6: 718 if (src->sa_family == AF_INET6) 719 break; 720 return EAFNOSUPPORT; 721 #endif /* INET6 */ 722 case SIOCSLIFPHYADDR: 723 /* checks done in the above */ 724 break; 725 } 726 727 error = gif_set_tunnel(&sc->gif_if, src, dst); 728 break; 729 730 #ifdef SIOCDIFPHYADDR 731 case SIOCDIFPHYADDR: 732 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 733 break; 734 gif_delete_tunnel(&sc->gif_if); 735 break; 736 #endif 737 738 case SIOCGIFPSRCADDR: 739 #ifdef INET6 740 case SIOCGIFPSRCADDR_IN6: 741 #endif /* INET6 */ 742 if (sc->gif_psrc == NULL) { 743 error = EADDRNOTAVAIL; 744 goto bad; 745 } 746 src = sc->gif_psrc; 747 switch (cmd) { 748 #ifdef INET 749 case SIOCGIFPSRCADDR: 750 dst = &ifr->ifr_addr; 751 size = sizeof(ifr->ifr_addr); 752 break; 753 #endif /* INET */ 754 #ifdef INET6 755 case SIOCGIFPSRCADDR_IN6: 756 dst = (struct sockaddr *) 757 &(((struct in6_ifreq *)data)->ifr_addr); 758 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 759 break; 760 #endif /* INET6 */ 761 default: 762 error = EADDRNOTAVAIL; 763 goto bad; 764 } 765 if (src->sa_len > size) 766 return EINVAL; 767 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 768 break; 769 770 case SIOCGIFPDSTADDR: 771 #ifdef INET6 772 case SIOCGIFPDSTADDR_IN6: 773 #endif /* INET6 */ 774 if (sc->gif_pdst == NULL) { 775 error = EADDRNOTAVAIL; 776 goto bad; 777 } 778 src = sc->gif_pdst; 779 switch (cmd) { 780 #ifdef INET 781 case SIOCGIFPDSTADDR: 782 dst = &ifr->ifr_addr; 783 size = sizeof(ifr->ifr_addr); 784 break; 785 #endif /* INET */ 786 #ifdef INET6 787 case SIOCGIFPDSTADDR_IN6: 788 dst = (struct sockaddr *) 789 &(((struct in6_ifreq *)data)->ifr_addr); 790 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 791 break; 792 #endif /* INET6 */ 793 default: 794 error = EADDRNOTAVAIL; 795 goto bad; 796 } 797 if (src->sa_len > size) 798 return EINVAL; 799 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 800 break; 801 802 case SIOCGLIFPHYADDR: 803 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 804 error = EADDRNOTAVAIL; 805 goto bad; 806 } 807 808 /* copy src */ 809 src = sc->gif_psrc; 810 dst = (struct sockaddr *) 811 &(((struct if_laddrreq *)data)->addr); 812 size = sizeof(((struct if_laddrreq *)data)->addr); 813 if (src->sa_len > size) 814 return EINVAL; 815 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 816 817 /* copy dst */ 818 src = sc->gif_pdst; 819 dst = (struct sockaddr *) 820 &(((struct if_laddrreq *)data)->dstaddr); 821 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 822 if (src->sa_len > size) 823 return EINVAL; 824 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 825 break; 826 827 case SIOCSIFFLAGS: 828 /* if_ioctl() takes care of it */ 829 break; 830 831 default: 832 error = EINVAL; 833 break; 834 } 835 bad: 836 return error; 837 } 838 839 int 840 gif_set_tunnel(ifp, src, dst) 841 struct ifnet *ifp; 842 struct sockaddr *src; 843 struct sockaddr *dst; 844 { 845 struct gif_softc *sc = (struct gif_softc *)ifp; 846 struct gif_softc *sc2; 847 struct sockaddr *osrc, *odst, *sa; 848 int s; 849 int error; 850 851 s = splsoftnet(); 852 853 for (sc2 = LIST_FIRST(&gif_softc_list); sc2 != NULL; 854 sc2 = LIST_NEXT(sc2, gif_list)) { 855 if (sc2 == sc) 856 continue; 857 if (!sc2->gif_pdst || !sc2->gif_psrc) 858 continue; 859 if (sc2->gif_pdst->sa_family != dst->sa_family || 860 sc2->gif_pdst->sa_len != dst->sa_len || 861 sc2->gif_psrc->sa_family != src->sa_family || 862 sc2->gif_psrc->sa_len != src->sa_len) 863 continue; 864 /* can't configure same pair of address onto two gifs */ 865 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 866 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 867 error = EADDRNOTAVAIL; 868 goto bad; 869 } 870 871 /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 872 } 873 874 /* XXX we can detach from both, but be polite just in case */ 875 if (sc->gif_psrc) 876 switch (sc->gif_psrc->sa_family) { 877 #ifdef INET 878 case AF_INET: 879 (void)in_gif_detach(sc); 880 break; 881 #endif 882 #ifdef INET6 883 case AF_INET6: 884 (void)in6_gif_detach(sc); 885 break; 886 #endif 887 } 888 889 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS 890 sc->gif_si = softintr_establish(IPL_SOFTNET, gifintr, sc); 891 if (sc->gif_si == NULL) { 892 error = ENOMEM; 893 goto bad; 894 } 895 #endif 896 897 osrc = sc->gif_psrc; 898 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 899 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 900 sc->gif_psrc = sa; 901 902 odst = sc->gif_pdst; 903 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 904 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 905 sc->gif_pdst = sa; 906 907 switch (sc->gif_psrc->sa_family) { 908 #ifdef INET 909 case AF_INET: 910 error = in_gif_attach(sc); 911 break; 912 #endif 913 #ifdef INET6 914 case AF_INET6: 915 error = in6_gif_attach(sc); 916 break; 917 #endif 918 default: 919 error = EINVAL; 920 break; 921 } 922 if (error) { 923 /* rollback */ 924 free((caddr_t)sc->gif_psrc, M_IFADDR); 925 free((caddr_t)sc->gif_pdst, M_IFADDR); 926 sc->gif_psrc = osrc; 927 sc->gif_pdst = odst; 928 goto bad; 929 } 930 931 if (osrc) 932 free((caddr_t)osrc, M_IFADDR); 933 if (odst) 934 free((caddr_t)odst, M_IFADDR); 935 936 if (sc->gif_psrc && sc->gif_pdst) 937 ifp->if_flags |= IFF_RUNNING; 938 else 939 ifp->if_flags &= ~IFF_RUNNING; 940 splx(s); 941 942 return 0; 943 944 bad: 945 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS 946 if (sc->gif_si) { 947 softintr_disestablish(sc->gif_si); 948 sc->gif_si = NULL; 949 } 950 #endif 951 if (sc->gif_psrc && sc->gif_pdst) 952 ifp->if_flags |= IFF_RUNNING; 953 else 954 ifp->if_flags &= ~IFF_RUNNING; 955 splx(s); 956 957 return error; 958 } 959 960 void 961 gif_delete_tunnel(ifp) 962 struct ifnet *ifp; 963 { 964 struct gif_softc *sc = (struct gif_softc *)ifp; 965 int s; 966 967 s = splsoftnet(); 968 969 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS 970 if (sc->gif_si) { 971 softintr_disestablish(sc->gif_si); 972 sc->gif_si = NULL; 973 } 974 #endif 975 if (sc->gif_psrc) { 976 free((caddr_t)sc->gif_psrc, M_IFADDR); 977 sc->gif_psrc = NULL; 978 } 979 if (sc->gif_pdst) { 980 free((caddr_t)sc->gif_pdst, M_IFADDR); 981 sc->gif_pdst = NULL; 982 } 983 /* it is safe to detach from both */ 984 #ifdef INET 985 (void)in_gif_detach(sc); 986 #endif 987 #ifdef INET6 988 (void)in6_gif_detach(sc); 989 #endif 990 991 if (sc->gif_psrc && sc->gif_pdst) 992 ifp->if_flags |= IFF_RUNNING; 993 else 994 ifp->if_flags &= ~IFF_RUNNING; 995 splx(s); 996 } 997 998 #ifdef ISO 999 struct eonhdr { 1000 u_int8_t version; 1001 u_int8_t class; 1002 u_int16_t cksum; 1003 }; 1004 1005 /* 1006 * prepend EON header to ISO PDU 1007 */ 1008 static struct mbuf * 1009 gif_eon_encap(struct mbuf *m) 1010 { 1011 struct eonhdr *ehdr; 1012 1013 M_PREPEND(m, sizeof(*ehdr), M_DONTWAIT); 1014 if (m && m->m_len < sizeof(*ehdr)) 1015 m = m_pullup(m, sizeof(*ehdr)); 1016 if (m == NULL) 1017 return NULL; 1018 ehdr = mtod(m, struct eonhdr *); 1019 ehdr->version = 1; 1020 ehdr->class = 0; /* always unicast */ 1021 #if 0 1022 /* calculate the checksum of the eonhdr */ 1023 { 1024 struct mbuf mhead; 1025 memset(&mhead, 0, sizeof(mhead)); 1026 ehdr->cksum = 0; 1027 mhead.m_data = (caddr_t)ehdr; 1028 mhead.m_len = sizeof(*ehdr); 1029 mhead.m_next = 0; 1030 iso_gen_csum(&mhead, offsetof(struct eonhdr, cksum), 1031 mhead.m_len); 1032 } 1033 #else 1034 /* since the data is always constant we'll just plug the value in */ 1035 ehdr->cksum = htons(0xfc02); 1036 #endif 1037 return m; 1038 } 1039 1040 /* 1041 * remove EON header and check checksum 1042 */ 1043 static struct mbuf * 1044 gif_eon_decap(struct ifnet *ifp, struct mbuf *m) 1045 { 1046 struct eonhdr *ehdr; 1047 1048 if (m->m_len < sizeof(*ehdr) && 1049 (m = m_pullup(m, sizeof(*ehdr))) == NULL) { 1050 ifp->if_ierrors++; 1051 return NULL; 1052 } 1053 if (iso_check_csum(m, sizeof(struct eonhdr))) { 1054 m_freem(m); 1055 return NULL; 1056 } 1057 m_adj(m, sizeof(*ehdr)); 1058 return m; 1059 } 1060 #endif /*ISO*/ 1061