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