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