1 /* $OpenBSD: if_gif.c,v 1.86 2016/09/13 07:48:45 mpi Exp $ */ 2 /* $KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 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 <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/mbuf.h> 36 #include <sys/socket.h> 37 #include <sys/sockio.h> 38 #include <sys/syslog.h> 39 40 #include <net/if.h> 41 #include <net/if_var.h> 42 #include <net/if_types.h> 43 #include <net/route.h> 44 45 #include <netinet/in.h> 46 #include <netinet/in_var.h> 47 #include <netinet/ip.h> 48 #include <netinet/ip_ether.h> 49 #include <netinet/ip_var.h> 50 #include <netinet/ip_ipsp.h> 51 52 #ifdef INET6 53 #include <netinet6/in6_var.h> 54 #include <netinet/ip6.h> 55 #include <netinet6/ip6_var.h> 56 #endif /* INET6 */ 57 58 #include <net/if_gif.h> 59 60 #include "bpfilter.h" 61 #if NBPFILTER > 0 62 #include <net/bpf.h> 63 #endif 64 65 #ifdef MPLS 66 #include <netinet/ip_ether.h> 67 #endif 68 69 #include "pf.h" 70 #if NPF > 0 71 #include <net/pfvar.h> 72 #endif 73 74 #define GIF_MTU (1280) /* Default MTU */ 75 #define GIF_MTU_MIN (1280) /* Minimum MTU */ 76 #define GIF_MTU_MAX (8192) /* Maximum MTU */ 77 78 void gifattach(int); 79 int gif_clone_create(struct if_clone *, int); 80 int gif_clone_destroy(struct ifnet *); 81 int gif_checkloop(struct ifnet *, struct mbuf *); 82 void gif_start(struct ifnet *); 83 int gif_ioctl(struct ifnet *, u_long, caddr_t); 84 int gif_output(struct ifnet *, struct mbuf *, struct sockaddr *, 85 struct rtentry *); 86 87 int in_gif_output(struct ifnet *, int, struct mbuf **); 88 int in6_gif_output(struct ifnet *, int, struct mbuf **); 89 90 /* 91 * gif global variable definitions 92 */ 93 struct gif_softc_head gif_softc_list; 94 struct if_clone gif_cloner = 95 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); 96 97 void 98 gifattach(int count) 99 { 100 LIST_INIT(&gif_softc_list); 101 if_clone_attach(&gif_cloner); 102 } 103 104 int 105 gif_clone_create(struct if_clone *ifc, int unit) 106 { 107 struct gif_softc *sc; 108 int s; 109 110 sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO); 111 if (!sc) 112 return (ENOMEM); 113 114 snprintf(sc->gif_if.if_xname, sizeof sc->gif_if.if_xname, 115 "%s%d", ifc->ifc_name, unit); 116 sc->gif_if.if_mtu = GIF_MTU; 117 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 118 sc->gif_if.if_ioctl = gif_ioctl; 119 sc->gif_if.if_start = gif_start; 120 sc->gif_if.if_output = gif_output; 121 sc->gif_if.if_rtrequest = p2p_rtrequest; 122 sc->gif_if.if_type = IFT_GIF; 123 IFQ_SET_MAXLEN(&sc->gif_if.if_snd, IFQ_MAXLEN); 124 sc->gif_if.if_softc = sc; 125 if_attach(&sc->gif_if); 126 if_alloc_sadl(&sc->gif_if); 127 128 #if NBPFILTER > 0 129 bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_LOOP, sizeof(u_int32_t)); 130 #endif 131 s = splnet(); 132 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 133 splx(s); 134 135 return (0); 136 } 137 138 int 139 gif_clone_destroy(struct ifnet *ifp) 140 { 141 struct gif_softc *sc = ifp->if_softc; 142 int s; 143 144 s = splnet(); 145 LIST_REMOVE(sc, gif_list); 146 splx(s); 147 148 if_detach(ifp); 149 150 if (sc->gif_psrc) 151 free((caddr_t)sc->gif_psrc, M_IFADDR, 0); 152 sc->gif_psrc = NULL; 153 if (sc->gif_pdst) 154 free((caddr_t)sc->gif_pdst, M_IFADDR, 0); 155 sc->gif_pdst = NULL; 156 free(sc, M_DEVBUF, sizeof(*sc)); 157 return (0); 158 } 159 160 void 161 gif_start(struct ifnet *ifp) 162 { 163 struct gif_softc *sc = (struct gif_softc*)ifp; 164 struct mbuf *m; 165 166 for (;;) { 167 IFQ_DEQUEUE(&ifp->if_snd, m); 168 if (m == NULL) 169 break; 170 171 /* is interface up and usable? */ 172 if (!(ifp->if_flags & IFF_UP) || 173 sc->gif_psrc == NULL || sc->gif_pdst == NULL || 174 sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) { 175 m_freem(m); 176 continue; 177 } 178 179 #if NBPFILTER > 0 180 if (ifp->if_bpf) { 181 int offset; 182 sa_family_t family; 183 u_int8_t proto; 184 185 /* must decapsulate outer header for bpf */ 186 switch (sc->gif_psrc->sa_family) { 187 case AF_INET: 188 offset = sizeof(struct ip); 189 proto = mtod(m, struct ip *)->ip_p; 190 break; 191 #ifdef INET6 192 case AF_INET6: 193 offset = sizeof(struct ip6_hdr); 194 proto = mtod(m, struct ip6_hdr *)->ip6_nxt; 195 break; 196 #endif 197 default: 198 proto = 0; 199 break; 200 } 201 switch (proto) { 202 case IPPROTO_IPV4: 203 family = AF_INET; 204 break; 205 case IPPROTO_IPV6: 206 family = AF_INET6; 207 break; 208 case IPPROTO_ETHERIP: 209 family = AF_LINK; 210 offset += sizeof(struct etherip_header); 211 break; 212 case IPPROTO_MPLS: 213 family = AF_MPLS; 214 break; 215 default: 216 offset = 0; 217 family = sc->gif_psrc->sa_family; 218 break; 219 } 220 m->m_data += offset; 221 m->m_len -= offset; 222 m->m_pkthdr.len -= offset; 223 bpf_mtap_af(ifp->if_bpf, family, m, BPF_DIRECTION_OUT); 224 m->m_data -= offset; 225 m->m_len += offset; 226 m->m_pkthdr.len += offset; 227 } 228 #endif 229 ifp->if_opackets++; 230 231 /* XXX we should cache the outgoing route */ 232 233 switch (sc->gif_psrc->sa_family) { 234 case AF_INET: 235 ip_output(m, NULL, NULL, 0, NULL, NULL, 0); 236 break; 237 #ifdef INET6 238 case AF_INET6: 239 /* 240 * force fragmentation to minimum MTU, to avoid path 241 * MTU discovery. It is too painful to ask for resend 242 * of inner packet, to achieve path MTU discovery for 243 * encapsulated packets. 244 */ 245 ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL); 246 break; 247 #endif 248 default: 249 m_freem(m); 250 break; 251 } 252 } 253 } 254 255 int 256 gif_encap(struct ifnet *ifp, struct mbuf **mp, sa_family_t af) 257 { 258 struct gif_softc *sc = (struct gif_softc*)ifp; 259 int error = 0; 260 /* 261 * Remove multicast and broadcast flags or encapsulated packet 262 * ends up as multicast or broadcast packet. 263 */ 264 (*mp)->m_flags &= ~(M_BCAST|M_MCAST); 265 266 /* 267 * Encapsulate packet. Add IP or IP6 header depending on tunnel AF. 268 */ 269 switch (sc->gif_psrc->sa_family) { 270 case AF_INET: 271 error = in_gif_output(ifp, af, mp); 272 break; 273 #ifdef INET6 274 case AF_INET6: 275 error = in6_gif_output(ifp, af, mp); 276 break; 277 #endif 278 default: 279 m_freem(*mp); 280 error = EAFNOSUPPORT; 281 break; 282 } 283 284 if (error) 285 return (error); 286 287 error = gif_checkloop(ifp, *mp); 288 return (error); 289 } 290 291 int 292 gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 293 struct rtentry *rt) 294 { 295 struct gif_softc *sc = (struct gif_softc*)ifp; 296 int error = 0; 297 298 if (!(ifp->if_flags & IFF_UP) || 299 sc->gif_psrc == NULL || sc->gif_pdst == NULL || 300 sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) { 301 m_freem(m); 302 error = ENETDOWN; 303 goto end; 304 } 305 306 error = gif_encap(ifp, &m, dst->sa_family); 307 if (error) 308 goto end; 309 310 error = if_enqueue(ifp, m); 311 312 end: 313 if (error) 314 ifp->if_oerrors++; 315 return (error); 316 } 317 318 int 319 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 320 { 321 struct gif_softc *sc = (struct gif_softc*)ifp; 322 struct ifreq *ifr = (struct ifreq *)data; 323 int error = 0, size; 324 struct sockaddr *dst, *src; 325 struct sockaddr *sa; 326 int s; 327 struct gif_softc *sc2; 328 329 switch (cmd) { 330 case SIOCSIFADDR: 331 break; 332 333 case SIOCSIFDSTADDR: 334 break; 335 336 case SIOCADDMULTI: 337 case SIOCDELMULTI: 338 break; 339 340 case SIOCSIFPHYADDR: 341 #ifdef INET6 342 case SIOCSIFPHYADDR_IN6: 343 #endif /* INET6 */ 344 case SIOCSLIFPHYADDR: 345 switch (cmd) { 346 case SIOCSIFPHYADDR: 347 src = sintosa( 348 &(((struct in_aliasreq *)data)->ifra_addr)); 349 dst = sintosa( 350 &(((struct in_aliasreq *)data)->ifra_dstaddr)); 351 break; 352 #ifdef INET6 353 case SIOCSIFPHYADDR_IN6: 354 src = sin6tosa( 355 &(((struct in6_aliasreq *)data)->ifra_addr)); 356 dst = sin6tosa( 357 &(((struct in6_aliasreq *)data)->ifra_dstaddr)); 358 break; 359 #endif 360 case SIOCSLIFPHYADDR: 361 src = (struct sockaddr *) 362 &(((struct if_laddrreq *)data)->addr); 363 dst = (struct sockaddr *) 364 &(((struct if_laddrreq *)data)->dstaddr); 365 break; 366 default: 367 return (EINVAL); 368 } 369 370 /* sa_family must be equal */ 371 if (src->sa_family != dst->sa_family) 372 return (EINVAL); 373 374 /* validate sa_len */ 375 switch (src->sa_family) { 376 case AF_INET: 377 if (src->sa_len != sizeof(struct sockaddr_in)) 378 return (EINVAL); 379 break; 380 #ifdef INET6 381 case AF_INET6: 382 if (src->sa_len != sizeof(struct sockaddr_in6)) 383 return (EINVAL); 384 break; 385 #endif 386 default: 387 return (EAFNOSUPPORT); 388 } 389 switch (dst->sa_family) { 390 case AF_INET: 391 if (dst->sa_len != sizeof(struct sockaddr_in)) 392 return (EINVAL); 393 break; 394 #ifdef INET6 395 case AF_INET6: 396 if (dst->sa_len != sizeof(struct sockaddr_in6)) 397 return (EINVAL); 398 break; 399 #endif 400 default: 401 return (EAFNOSUPPORT); 402 } 403 404 /* check sa_family looks sane for the cmd */ 405 switch (cmd) { 406 case SIOCSIFPHYADDR: 407 if (src->sa_family == AF_INET) 408 break; 409 return (EAFNOSUPPORT); 410 #ifdef INET6 411 case SIOCSIFPHYADDR_IN6: 412 if (src->sa_family == AF_INET6) 413 break; 414 return (EAFNOSUPPORT); 415 #endif /* INET6 */ 416 case SIOCSLIFPHYADDR: 417 /* checks done in the above */ 418 break; 419 } 420 421 LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 422 if (sc2 == sc) 423 continue; 424 if (!sc2->gif_pdst || !sc2->gif_psrc) 425 continue; 426 if (sc2->gif_pdst->sa_family != dst->sa_family || 427 sc2->gif_pdst->sa_len != dst->sa_len || 428 sc2->gif_psrc->sa_family != src->sa_family || 429 sc2->gif_psrc->sa_len != src->sa_len) 430 continue; 431 /* can't configure same pair of address onto two gifs */ 432 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 433 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 434 error = EADDRNOTAVAIL; 435 goto bad; 436 } 437 438 /* can't configure multiple multi-dest interfaces */ 439 #define multidest(x) \ 440 (satosin(x)->sin_addr.s_addr == INADDR_ANY) 441 #ifdef INET6 442 #define multidest6(x) \ 443 (IN6_IS_ADDR_UNSPECIFIED(&satosin6(x)->sin6_addr)) 444 #endif 445 if (dst->sa_family == AF_INET && 446 multidest(dst) && multidest(sc2->gif_pdst)) { 447 error = EADDRNOTAVAIL; 448 goto bad; 449 } 450 #ifdef INET6 451 if (dst->sa_family == AF_INET6 && 452 multidest6(dst) && multidest6(sc2->gif_pdst)) { 453 error = EADDRNOTAVAIL; 454 goto bad; 455 } 456 #endif 457 } 458 459 if (sc->gif_psrc) 460 free((caddr_t)sc->gif_psrc, M_IFADDR, 0); 461 sa = malloc(src->sa_len, M_IFADDR, M_WAITOK); 462 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 463 sc->gif_psrc = sa; 464 465 if (sc->gif_pdst) 466 free((caddr_t)sc->gif_pdst, M_IFADDR, 0); 467 sa = malloc(dst->sa_len, M_IFADDR, M_WAITOK); 468 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 469 sc->gif_pdst = sa; 470 471 s = splnet(); 472 ifp->if_flags |= IFF_RUNNING; 473 if_up(ifp); /* send up RTM_IFINFO */ 474 splx(s); 475 476 error = 0; 477 break; 478 479 #ifdef SIOCDIFPHYADDR 480 case SIOCDIFPHYADDR: 481 if (sc->gif_psrc) { 482 free((caddr_t)sc->gif_psrc, M_IFADDR, 0); 483 sc->gif_psrc = NULL; 484 } 485 if (sc->gif_pdst) { 486 free((caddr_t)sc->gif_pdst, M_IFADDR, 0); 487 sc->gif_pdst = NULL; 488 } 489 /* change the IFF_{UP, RUNNING} flag as well? */ 490 break; 491 #endif 492 493 case SIOCGIFPSRCADDR: 494 #ifdef INET6 495 case SIOCGIFPSRCADDR_IN6: 496 #endif /* INET6 */ 497 if (sc->gif_psrc == NULL) { 498 error = EADDRNOTAVAIL; 499 goto bad; 500 } 501 src = sc->gif_psrc; 502 switch (cmd) { 503 case SIOCGIFPSRCADDR: 504 dst = &ifr->ifr_addr; 505 size = sizeof(ifr->ifr_addr); 506 break; 507 #ifdef INET6 508 case SIOCGIFPSRCADDR_IN6: 509 dst = sin6tosa( 510 &(((struct in6_ifreq *)data)->ifr_addr)); 511 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 512 break; 513 #endif /* INET6 */ 514 default: 515 error = EADDRNOTAVAIL; 516 goto bad; 517 } 518 if (src->sa_len > size) 519 return (EINVAL); 520 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 521 break; 522 523 case SIOCGIFPDSTADDR: 524 #ifdef INET6 525 case SIOCGIFPDSTADDR_IN6: 526 #endif /* INET6 */ 527 if (sc->gif_pdst == NULL) { 528 error = EADDRNOTAVAIL; 529 goto bad; 530 } 531 src = sc->gif_pdst; 532 switch (cmd) { 533 case SIOCGIFPDSTADDR: 534 dst = &ifr->ifr_addr; 535 size = sizeof(ifr->ifr_addr); 536 break; 537 #ifdef INET6 538 case SIOCGIFPDSTADDR_IN6: 539 dst = sin6tosa(&(((struct in6_ifreq *)data)->ifr_addr)); 540 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 541 break; 542 #endif /* INET6 */ 543 default: 544 error = EADDRNOTAVAIL; 545 goto bad; 546 } 547 if (src->sa_len > size) 548 return (EINVAL); 549 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 550 break; 551 552 case SIOCGLIFPHYADDR: 553 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 554 error = EADDRNOTAVAIL; 555 goto bad; 556 } 557 558 /* copy src */ 559 src = sc->gif_psrc; 560 dst = (struct sockaddr *) 561 &(((struct if_laddrreq *)data)->addr); 562 size = sizeof(((struct if_laddrreq *)data)->addr); 563 if (src->sa_len > size) 564 return (EINVAL); 565 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 566 567 /* copy dst */ 568 src = sc->gif_pdst; 569 dst = (struct sockaddr *) 570 &(((struct if_laddrreq *)data)->dstaddr); 571 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 572 if (src->sa_len > size) 573 return (EINVAL); 574 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 575 break; 576 577 case SIOCSIFFLAGS: 578 /* if_ioctl() takes care of it */ 579 break; 580 581 case SIOCSIFMTU: 582 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) 583 error = EINVAL; 584 else 585 ifp->if_mtu = ifr->ifr_mtu; 586 break; 587 588 case SIOCSLIFPHYRTABLE: 589 if (ifr->ifr_rdomainid < 0 || 590 ifr->ifr_rdomainid > RT_TABLEID_MAX || 591 !rtable_exists(ifr->ifr_rdomainid)) { 592 error = EINVAL; 593 break; 594 } 595 sc->gif_rtableid = ifr->ifr_rdomainid; 596 break; 597 case SIOCGLIFPHYRTABLE: 598 ifr->ifr_rdomainid = sc->gif_rtableid; 599 break; 600 default: 601 error = ENOTTY; 602 break; 603 } 604 bad: 605 return (error); 606 } 607 608 int 609 gif_checkloop(struct ifnet *ifp, struct mbuf *m) 610 { 611 struct m_tag *mtag; 612 613 /* 614 * gif may cause infinite recursion calls when misconfigured. 615 * We'll prevent this by detecting loops. 616 */ 617 for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag; 618 mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) { 619 if (*(struct ifnet **)(mtag + 1) == ifp) { 620 log(LOG_NOTICE, "gif_output: " 621 "recursively called too many times\n"); 622 m_freem(m); 623 return ENETUNREACH; 624 } 625 } 626 627 mtag = m_tag_get(PACKET_TAG_GIF, sizeof(struct ifnet *), M_NOWAIT); 628 if (mtag == NULL) { 629 m_freem(m); 630 return ENOMEM; 631 } 632 *(struct ifnet **)(mtag + 1) = ifp; 633 m_tag_prepend(m, mtag); 634 return 0; 635 } 636 637 int 638 in_gif_output(struct ifnet *ifp, int family, struct mbuf **m0) 639 { 640 struct gif_softc *sc = (struct gif_softc*)ifp; 641 struct sockaddr_in *sin_src = satosin(sc->gif_psrc); 642 struct sockaddr_in *sin_dst = satosin(sc->gif_pdst); 643 struct tdb tdb; 644 struct xformsw xfs; 645 int error; 646 struct mbuf *m = *m0; 647 648 if (sin_src == NULL || sin_dst == NULL || 649 sin_src->sin_family != AF_INET || 650 sin_dst->sin_family != AF_INET) { 651 m_freem(m); 652 return EAFNOSUPPORT; 653 } 654 655 #ifdef DIAGNOSTIC 656 if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) { 657 printf("%s: trying to send packet on wrong domain. " 658 "if %d vs. mbuf %d, AF %d\n", ifp->if_xname, 659 ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid), 660 family); 661 } 662 #endif 663 664 /* setup dummy tdb. it highly depends on ipip_output() code. */ 665 bzero(&tdb, sizeof(tdb)); 666 bzero(&xfs, sizeof(xfs)); 667 tdb.tdb_src.sin.sin_family = AF_INET; 668 tdb.tdb_src.sin.sin_len = sizeof(struct sockaddr_in); 669 tdb.tdb_src.sin.sin_addr = sin_src->sin_addr; 670 tdb.tdb_dst.sin.sin_family = AF_INET; 671 tdb.tdb_dst.sin.sin_len = sizeof(struct sockaddr_in); 672 tdb.tdb_dst.sin.sin_addr = sin_dst->sin_addr; 673 tdb.tdb_xform = &xfs; 674 xfs.xf_type = -1; /* not XF_IP4 */ 675 676 switch (family) { 677 case AF_INET: 678 break; 679 #ifdef INET6 680 case AF_INET6: 681 break; 682 #endif 683 #if MPLS 684 case AF_MPLS: 685 break; 686 #endif 687 default: 688 #ifdef DEBUG 689 printf("%s: warning: unknown family %d passed\n", __func__, 690 family); 691 #endif 692 m_freem(m); 693 return EAFNOSUPPORT; 694 } 695 696 /* encapsulate into IPv4 packet */ 697 *m0 = NULL; 698 #ifdef MPLS 699 if (family == AF_MPLS) 700 error = etherip_output(m, &tdb, m0, IPPROTO_MPLS); 701 else 702 #endif 703 error = ipip_output(m, &tdb, m0, 0, 0); 704 if (error) 705 return error; 706 else if (*m0 == NULL) 707 return EFAULT; 708 709 m = *m0; 710 711 m->m_pkthdr.ph_rtableid = sc->gif_rtableid; 712 #if NPF > 0 713 pf_pkt_addr_changed(m); 714 #endif 715 return 0; 716 } 717 718 void 719 in_gif_input(struct mbuf *m, ...) 720 { 721 int off; 722 struct gif_softc *sc; 723 struct ifnet *gifp = NULL; 724 struct ip *ip; 725 va_list ap; 726 727 va_start(ap, m); 728 off = va_arg(ap, int); 729 va_end(ap); 730 731 /* IP-in-IP header is caused by tunnel mode, so skip gif lookup */ 732 if (m->m_flags & M_TUNNEL) { 733 m->m_flags &= ~M_TUNNEL; 734 goto inject; 735 } 736 737 ip = mtod(m, struct ip *); 738 739 /* this code will be soon improved. */ 740 LIST_FOREACH(sc, &gif_softc_list, gif_list) { 741 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL || 742 sc->gif_psrc->sa_family != AF_INET || 743 sc->gif_pdst->sa_family != AF_INET || 744 rtable_l2(sc->gif_rtableid) != 745 rtable_l2(m->m_pkthdr.ph_rtableid)) { 746 continue; 747 } 748 749 if ((sc->gif_if.if_flags & IFF_UP) == 0) 750 continue; 751 752 if (in_hosteq(satosin(sc->gif_psrc)->sin_addr, ip->ip_dst) && 753 in_hosteq(satosin(sc->gif_pdst)->sin_addr, ip->ip_src)) { 754 gifp = &sc->gif_if; 755 break; 756 } 757 } 758 759 if (gifp) { 760 m->m_pkthdr.ph_ifidx = gifp->if_index; 761 m->m_pkthdr.ph_rtableid = gifp->if_rdomain; 762 gifp->if_ipackets++; 763 gifp->if_ibytes += m->m_pkthdr.len; 764 /* We have a configured GIF */ 765 ipip_input(m, off, gifp, ip->ip_p); 766 return; 767 } 768 769 inject: 770 ip4_input(m, off); /* No GIF interface was configured */ 771 return; 772 } 773 774 #ifdef INET6 775 int 776 in6_gif_output(struct ifnet *ifp, int family, struct mbuf **m0) 777 { 778 struct gif_softc *sc = (struct gif_softc*)ifp; 779 struct sockaddr_in6 *sin6_src = satosin6(sc->gif_psrc); 780 struct sockaddr_in6 *sin6_dst = satosin6(sc->gif_pdst); 781 struct tdb tdb; 782 struct xformsw xfs; 783 int error; 784 struct mbuf *m = *m0; 785 786 if (sin6_src == NULL || sin6_dst == NULL || 787 sin6_src->sin6_family != AF_INET6 || 788 sin6_dst->sin6_family != AF_INET6) { 789 m_freem(m); 790 return EAFNOSUPPORT; 791 } 792 793 /* setup dummy tdb. it highly depends on ipip_output() code. */ 794 bzero(&tdb, sizeof(tdb)); 795 bzero(&xfs, sizeof(xfs)); 796 tdb.tdb_src.sin6.sin6_family = AF_INET6; 797 tdb.tdb_src.sin6.sin6_len = sizeof(struct sockaddr_in6); 798 tdb.tdb_src.sin6.sin6_addr = sin6_src->sin6_addr; 799 tdb.tdb_dst.sin6.sin6_family = AF_INET6; 800 tdb.tdb_dst.sin6.sin6_len = sizeof(struct sockaddr_in6); 801 tdb.tdb_dst.sin6.sin6_addr = sin6_dst->sin6_addr; 802 tdb.tdb_xform = &xfs; 803 xfs.xf_type = -1; /* not XF_IP4 */ 804 805 switch (family) { 806 case AF_INET: 807 break; 808 #ifdef INET6 809 case AF_INET6: 810 break; 811 #endif 812 #ifdef MPLS 813 case AF_MPLS: 814 break; 815 #endif 816 default: 817 #ifdef DEBUG 818 printf("%s: warning: unknown family %d passed\n", __func__, 819 family); 820 #endif 821 m_freem(m); 822 return EAFNOSUPPORT; 823 } 824 825 /* encapsulate into IPv6 packet */ 826 *m0 = NULL; 827 #if MPLS 828 if (family == AF_MPLS) 829 error = etherip_output(m, &tdb, m0, IPPROTO_MPLS); 830 else 831 #endif 832 error = ipip_output(m, &tdb, m0, 0, 0); 833 if (error) 834 return error; 835 else if (*m0 == NULL) 836 return EFAULT; 837 838 m = *m0; 839 840 #if NPF > 0 841 pf_pkt_addr_changed(m); 842 #endif 843 return 0; 844 } 845 846 int in6_gif_input(struct mbuf **mp, int *offp, int proto) 847 { 848 struct mbuf *m = *mp; 849 struct gif_softc *sc; 850 struct ifnet *gifp = NULL; 851 struct ip6_hdr *ip6; 852 853 /* XXX What if we run transport-mode IPsec to protect gif tunnel ? */ 854 if (m->m_flags & (M_AUTH | M_CONF)) 855 goto inject; 856 857 ip6 = mtod(m, struct ip6_hdr *); 858 859 #define satoin6(sa) (satosin6(sa)->sin6_addr) 860 LIST_FOREACH(sc, &gif_softc_list, gif_list) { 861 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL || 862 sc->gif_psrc->sa_family != AF_INET6 || 863 sc->gif_pdst->sa_family != AF_INET6) { 864 continue; 865 } 866 867 if ((sc->gif_if.if_flags & IFF_UP) == 0) 868 continue; 869 870 if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && 871 IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) { 872 gifp = &sc->gif_if; 873 break; 874 } 875 } 876 877 if (gifp) { 878 m->m_pkthdr.ph_ifidx = gifp->if_index; 879 gifp->if_ipackets++; 880 gifp->if_ibytes += m->m_pkthdr.len; 881 ipip_input(m, *offp, gifp, proto); 882 return IPPROTO_DONE; 883 } 884 885 inject: 886 /* No GIF tunnel configured */ 887 ip4_input6(&m, offp, proto); 888 return IPPROTO_DONE; 889 } 890 #endif /* INET6 */ 891