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