1 /* $OpenBSD: if_gif.c,v 1.51 2008/11/24 14:55:53 claudio 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/kernel.h> 36 #include <sys/mbuf.h> 37 #include <sys/socket.h> 38 #include <sys/sockio.h> 39 #include <sys/syslog.h> 40 41 #include <net/if.h> 42 #include <net/if_types.h> 43 #include <net/route.h> 44 #include <net/bpf.h> 45 46 #ifdef INET 47 #include <netinet/in.h> 48 #include <netinet/in_systm.h> 49 #include <netinet/in_var.h> 50 #include <netinet/in_gif.h> 51 #include <netinet/ip.h> 52 #endif /* INET */ 53 54 #ifdef INET6 55 #ifndef INET 56 #include <netinet/in.h> 57 #endif 58 #include <netinet/ip6.h> 59 #include <netinet6/in6_gif.h> 60 #endif /* INET6 */ 61 62 #include <net/if_gif.h> 63 64 #include "bpfilter.h" 65 #include "bridge.h" 66 67 void gifattach(int); 68 int gif_clone_create(struct if_clone *, int); 69 int gif_clone_destroy(struct ifnet *); 70 71 /* 72 * gif global variable definitions 73 */ 74 struct gif_softc_head gif_softc_list; 75 struct if_clone gif_cloner = 76 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); 77 78 /* ARGSUSED */ 79 void 80 gifattach(int count) 81 { 82 LIST_INIT(&gif_softc_list); 83 if_clone_attach(&gif_cloner); 84 } 85 86 int 87 gif_clone_create(struct if_clone *ifc, int unit) 88 { 89 struct gif_softc *sc; 90 int s; 91 92 sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO); 93 if (!sc) 94 return (ENOMEM); 95 96 snprintf(sc->gif_if.if_xname, sizeof sc->gif_if.if_xname, 97 "%s%d", ifc->ifc_name, unit); 98 sc->gif_if.if_mtu = GIF_MTU; 99 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 100 sc->gif_if.if_ioctl = gif_ioctl; 101 sc->gif_if.if_start = gif_start; 102 sc->gif_if.if_output = gif_output; 103 sc->gif_if.if_type = IFT_GIF; 104 IFQ_SET_MAXLEN(&sc->gif_if.if_snd, ifqmaxlen); 105 IFQ_SET_READY(&sc->gif_if.if_snd); 106 sc->gif_if.if_softc = sc; 107 if_attach(&sc->gif_if); 108 if_alloc_sadl(&sc->gif_if); 109 110 #if NBPFILTER > 0 111 bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, 112 sizeof(u_int)); 113 #endif 114 s = splnet(); 115 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 116 splx(s); 117 118 return (0); 119 } 120 121 int 122 gif_clone_destroy(struct ifnet *ifp) 123 { 124 struct gif_softc *sc = ifp->if_softc; 125 int s; 126 127 s = splnet(); 128 LIST_REMOVE(sc, gif_list); 129 splx(s); 130 131 if_detach(ifp); 132 133 if (sc->gif_psrc) 134 free((caddr_t)sc->gif_psrc, M_IFADDR); 135 sc->gif_psrc = NULL; 136 if (sc->gif_pdst) 137 free((caddr_t)sc->gif_pdst, M_IFADDR); 138 sc->gif_pdst = NULL; 139 free(sc, M_DEVBUF); 140 return (0); 141 } 142 143 void 144 gif_start(struct ifnet *ifp) 145 { 146 struct gif_softc *sc = (struct gif_softc*)ifp; 147 struct mbuf *m; 148 struct m_tag *mtag; 149 int family; 150 int s; 151 u_int8_t tp; 152 153 /* is interface up and running? */ 154 if ((ifp->if_flags & (IFF_OACTIVE | IFF_UP)) != IFF_UP || 155 sc->gif_psrc == NULL || sc->gif_pdst == NULL) 156 return; 157 158 /* are the tunnel endpoints valid? */ 159 #ifdef INET 160 if (sc->gif_psrc->sa_family != AF_INET) 161 #endif 162 #ifdef INET6 163 if (sc->gif_psrc->sa_family != AF_INET6) 164 #endif 165 return; 166 167 while (1) { 168 s = splnet(); 169 IFQ_DEQUEUE(&ifp->if_snd, m); 170 splx(s); 171 172 if (m == NULL) 173 break; 174 175 /* 176 * gif may cause infinite recursion calls when misconfigured. 177 * We'll prevent this by detecting loops. 178 */ 179 for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag; 180 mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) { 181 if (!bcmp((caddr_t)(mtag + 1), &ifp, 182 sizeof(struct ifnet *))) { 183 IF_DROP(&ifp->if_snd); 184 log(LOG_NOTICE, "gif_output: " 185 "recursively called too many times\n"); 186 m_freem(m); 187 break; 188 } 189 } 190 if (mtag) 191 continue; 192 193 mtag = m_tag_get(PACKET_TAG_GIF, sizeof(caddr_t), M_NOWAIT); 194 if (mtag == NULL) { 195 m_freem(m); 196 break; 197 } 198 bcopy(&ifp, mtag + 1, sizeof(caddr_t)); 199 m_tag_prepend(m, mtag); 200 201 /* 202 * Remove multicast and broadcast flags or encapsulated packet 203 * ends up as multicast or broadcast packet. 204 */ 205 m->m_flags &= ~(M_BCAST|M_MCAST); 206 207 /* extract address family */ 208 family = AF_UNSPEC; 209 tp = *mtod(m, u_int8_t *); 210 tp = (tp >> 4) & 0xff; /* Get the IP version number. */ 211 #ifdef INET 212 if (tp == IPVERSION) 213 family = AF_INET; 214 #endif 215 #ifdef INET6 216 if (tp == (IPV6_VERSION >> 4)) 217 family = AF_INET6; 218 #endif 219 220 #if NBRIDGE > 0 221 /* 222 * Check if the packet is comming via bridge and needs 223 * etherip encapsulation or not. 224 */ 225 if (ifp->if_bridge && (m->m_flags & M_PROTO1)) { 226 m->m_flags &= ~M_PROTO1; 227 family = AF_LINK; 228 } 229 #endif 230 231 #if NBPFILTER > 0 232 if (ifp->if_bpf) 233 bpf_mtap_af(ifp->if_bpf, family, m, BPF_DIRECTION_OUT); 234 #endif 235 ifp->if_opackets++; 236 ifp->if_obytes += m->m_pkthdr.len; 237 238 switch (sc->gif_psrc->sa_family) { 239 #ifdef INET 240 case AF_INET: 241 in_gif_output(ifp, family, m); 242 break; 243 #endif 244 #ifdef INET6 245 case AF_INET6: 246 in6_gif_output(ifp, family, m); 247 break; 248 #endif 249 default: 250 m_freem(m); 251 break; 252 } 253 } 254 } 255 256 int 257 gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 258 struct rtentry *rt) 259 { 260 struct gif_softc *sc = (struct gif_softc*)ifp; 261 int error = 0; 262 int s; 263 264 if (!(ifp->if_flags & IFF_UP) || 265 sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 266 m_freem(m); 267 error = ENETDOWN; 268 goto end; 269 } 270 271 switch (sc->gif_psrc->sa_family) { 272 #ifdef INET 273 case AF_INET: 274 break; 275 #endif 276 #ifdef INET6 277 case AF_INET6: 278 break; 279 #endif 280 default: 281 m_freem(m); 282 error = ENETDOWN; 283 goto end; 284 } 285 286 s = splnet(); 287 /* 288 * Queue message on interface, and start output if interface 289 * not yet active. 290 */ 291 IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error); 292 if (error) { 293 /* mbuf is already freed */ 294 splx(s); 295 return (error); 296 } 297 if_start(ifp); 298 splx(s); 299 return (error); 300 301 end: 302 if (error) 303 ifp->if_oerrors++; 304 return (error); 305 } 306 307 int 308 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 309 { 310 struct gif_softc *sc = (struct gif_softc*)ifp; 311 struct ifreq *ifr = (struct ifreq*)data; 312 int error = 0, size; 313 struct sockaddr *dst, *src; 314 struct sockaddr *sa; 315 int s; 316 struct gif_softc *sc2; 317 318 switch (cmd) { 319 case SIOCSIFADDR: 320 break; 321 322 case SIOCSIFDSTADDR: 323 break; 324 325 case SIOCADDMULTI: 326 case SIOCDELMULTI: 327 switch (ifr->ifr_addr.sa_family) { 328 #ifdef INET 329 case AF_INET: /* IP supports Multicast */ 330 break; 331 #endif /* INET */ 332 #ifdef INET6 333 case AF_INET6: /* IP6 supports Multicast */ 334 break; 335 #endif /* INET6 */ 336 default: /* Other protocols doesn't support Multicast */ 337 error = EAFNOSUPPORT; 338 break; 339 } 340 break; 341 342 case SIOCSIFPHYADDR: 343 #ifdef INET6 344 case SIOCSIFPHYADDR_IN6: 345 #endif /* INET6 */ 346 case SIOCSLIFPHYADDR: 347 switch (cmd) { 348 #ifdef INET 349 case SIOCSIFPHYADDR: 350 src = (struct sockaddr *) 351 &(((struct in_aliasreq *)data)->ifra_addr); 352 dst = (struct sockaddr *) 353 &(((struct in_aliasreq *)data)->ifra_dstaddr); 354 break; 355 #endif 356 #ifdef INET6 357 case SIOCSIFPHYADDR_IN6: 358 src = (struct sockaddr *) 359 &(((struct in6_aliasreq *)data)->ifra_addr); 360 dst = (struct sockaddr *) 361 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 362 break; 363 #endif 364 case SIOCSLIFPHYADDR: 365 src = (struct sockaddr *) 366 &(((struct if_laddrreq *)data)->addr); 367 dst = (struct sockaddr *) 368 &(((struct if_laddrreq *)data)->dstaddr); 369 break; 370 default: 371 return (EINVAL); 372 } 373 374 /* sa_family must be equal */ 375 if (src->sa_family != dst->sa_family) 376 return (EINVAL); 377 378 /* validate sa_len */ 379 switch (src->sa_family) { 380 #ifdef INET 381 case AF_INET: 382 if (src->sa_len != sizeof(struct sockaddr_in)) 383 return (EINVAL); 384 break; 385 #endif 386 #ifdef INET6 387 case AF_INET6: 388 if (src->sa_len != sizeof(struct sockaddr_in6)) 389 return (EINVAL); 390 break; 391 #endif 392 default: 393 return (EAFNOSUPPORT); 394 } 395 switch (dst->sa_family) { 396 #ifdef INET 397 case AF_INET: 398 if (dst->sa_len != sizeof(struct sockaddr_in)) 399 return (EINVAL); 400 break; 401 #endif 402 #ifdef INET6 403 case AF_INET6: 404 if (dst->sa_len != sizeof(struct sockaddr_in6)) 405 return (EINVAL); 406 break; 407 #endif 408 default: 409 return (EAFNOSUPPORT); 410 } 411 412 /* check sa_family looks sane for the cmd */ 413 switch (cmd) { 414 case SIOCSIFPHYADDR: 415 if (src->sa_family == AF_INET) 416 break; 417 return (EAFNOSUPPORT); 418 #ifdef INET6 419 case SIOCSIFPHYADDR_IN6: 420 if (src->sa_family == AF_INET6) 421 break; 422 return (EAFNOSUPPORT); 423 #endif /* INET6 */ 424 case SIOCSLIFPHYADDR: 425 /* checks done in the above */ 426 break; 427 } 428 429 LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 430 if (sc2 == sc) 431 continue; 432 if (!sc2->gif_pdst || !sc2->gif_psrc) 433 continue; 434 if (sc2->gif_pdst->sa_family != dst->sa_family || 435 sc2->gif_pdst->sa_len != dst->sa_len || 436 sc2->gif_psrc->sa_family != src->sa_family || 437 sc2->gif_psrc->sa_len != src->sa_len) 438 continue; 439 /* can't configure same pair of address onto two gifs */ 440 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 441 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 442 error = EADDRNOTAVAIL; 443 goto bad; 444 } 445 446 /* can't configure multiple multi-dest interfaces */ 447 #define multidest(x) \ 448 (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY) 449 #ifdef INET6 450 #define multidest6(x) \ 451 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr)) 452 #endif 453 if (dst->sa_family == AF_INET && 454 multidest(dst) && multidest(sc2->gif_pdst)) { 455 error = EADDRNOTAVAIL; 456 goto bad; 457 } 458 #ifdef INET6 459 if (dst->sa_family == AF_INET6 && 460 multidest6(dst) && multidest6(sc2->gif_pdst)) { 461 error = EADDRNOTAVAIL; 462 goto bad; 463 } 464 #endif 465 } 466 467 if (sc->gif_psrc) 468 free((caddr_t)sc->gif_psrc, M_IFADDR); 469 sa = malloc(src->sa_len, M_IFADDR, M_WAITOK); 470 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 471 sc->gif_psrc = sa; 472 473 if (sc->gif_pdst) 474 free((caddr_t)sc->gif_pdst, M_IFADDR); 475 sa = malloc(dst->sa_len, M_IFADDR, M_WAITOK); 476 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 477 sc->gif_pdst = sa; 478 479 s = splnet(); 480 ifp->if_flags |= IFF_RUNNING; 481 if_up(ifp); /* send up RTM_IFINFO */ 482 splx(s); 483 484 error = 0; 485 break; 486 487 #ifdef SIOCDIFPHYADDR 488 case SIOCDIFPHYADDR: 489 if (sc->gif_psrc) { 490 free((caddr_t)sc->gif_psrc, M_IFADDR); 491 sc->gif_psrc = NULL; 492 } 493 if (sc->gif_pdst) { 494 free((caddr_t)sc->gif_pdst, M_IFADDR); 495 sc->gif_pdst = NULL; 496 } 497 /* change the IFF_{UP, RUNNING} flag as well? */ 498 break; 499 #endif 500 501 case SIOCGIFPSRCADDR: 502 #ifdef INET6 503 case SIOCGIFPSRCADDR_IN6: 504 #endif /* INET6 */ 505 if (sc->gif_psrc == NULL) { 506 error = EADDRNOTAVAIL; 507 goto bad; 508 } 509 src = sc->gif_psrc; 510 switch (cmd) { 511 #ifdef INET 512 case SIOCGIFPSRCADDR: 513 dst = &ifr->ifr_addr; 514 size = sizeof(ifr->ifr_addr); 515 break; 516 #endif /* INET */ 517 #ifdef INET6 518 case SIOCGIFPSRCADDR_IN6: 519 dst = (struct sockaddr *) 520 &(((struct in6_ifreq *)data)->ifr_addr); 521 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 522 break; 523 #endif /* INET6 */ 524 default: 525 error = EADDRNOTAVAIL; 526 goto bad; 527 } 528 if (src->sa_len > size) 529 return (EINVAL); 530 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 531 break; 532 533 case SIOCGIFPDSTADDR: 534 #ifdef INET6 535 case SIOCGIFPDSTADDR_IN6: 536 #endif /* INET6 */ 537 if (sc->gif_pdst == NULL) { 538 error = EADDRNOTAVAIL; 539 goto bad; 540 } 541 src = sc->gif_pdst; 542 switch (cmd) { 543 #ifdef INET 544 case SIOCGIFPDSTADDR: 545 dst = &ifr->ifr_addr; 546 size = sizeof(ifr->ifr_addr); 547 break; 548 #endif /* INET */ 549 #ifdef INET6 550 case SIOCGIFPDSTADDR_IN6: 551 dst = (struct sockaddr *) 552 &(((struct in6_ifreq *)data)->ifr_addr); 553 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 554 break; 555 #endif /* INET6 */ 556 default: 557 error = EADDRNOTAVAIL; 558 goto bad; 559 } 560 if (src->sa_len > size) 561 return (EINVAL); 562 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 563 break; 564 565 case SIOCGLIFPHYADDR: 566 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 567 error = EADDRNOTAVAIL; 568 goto bad; 569 } 570 571 /* copy src */ 572 src = sc->gif_psrc; 573 dst = (struct sockaddr *) 574 &(((struct if_laddrreq *)data)->addr); 575 size = sizeof(((struct if_laddrreq *)data)->addr); 576 if (src->sa_len > size) 577 return (EINVAL); 578 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 579 580 /* copy dst */ 581 src = sc->gif_pdst; 582 dst = (struct sockaddr *) 583 &(((struct if_laddrreq *)data)->dstaddr); 584 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 585 if (src->sa_len > size) 586 return (EINVAL); 587 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 588 break; 589 590 case SIOCSIFFLAGS: 591 /* if_ioctl() takes care of it */ 592 break; 593 594 case SIOCSIFMTU: 595 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) 596 error = EINVAL; 597 else 598 ifp->if_mtu = ifr->ifr_mtu; 599 break; 600 601 default: 602 error = ENOTTY; 603 break; 604 } 605 bad: 606 return (error); 607 } 608