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