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