1 /* $NetBSD: if_gif.c,v 1.143 2018/06/26 06:48:02 msaitoh 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.143 2018/06/26 06:48:02 msaitoh Exp $"); 35 36 #ifdef _KERNEL_OPT 37 #include "opt_inet.h" 38 #include "opt_net_mpsafe.h" 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/mbuf.h> 45 #include <sys/socket.h> 46 #include <sys/sockio.h> 47 #include <sys/errno.h> 48 #include <sys/ioctl.h> 49 #include <sys/time.h> 50 #include <sys/socketvar.h> 51 #include <sys/syslog.h> 52 #include <sys/proc.h> 53 #include <sys/cpu.h> 54 #include <sys/intr.h> 55 #include <sys/kmem.h> 56 #include <sys/sysctl.h> 57 #include <sys/xcall.h> 58 #include <sys/device.h> 59 #include <sys/module.h> 60 #include <sys/mutex.h> 61 #include <sys/pserialize.h> 62 #include <sys/psref.h> 63 64 #include <net/if.h> 65 #include <net/if_types.h> 66 #include <net/netisr.h> 67 #include <net/route.h> 68 #include <net/bpf.h> 69 70 #include <netinet/in.h> 71 #include <netinet/in_systm.h> 72 #include <netinet/ip.h> 73 #ifdef INET 74 #include <netinet/in_var.h> 75 #endif /* INET */ 76 #include <netinet/in_gif.h> 77 78 #ifdef INET6 79 #ifndef INET 80 #include <netinet/in.h> 81 #endif 82 #include <netinet6/in6_var.h> 83 #include <netinet/ip6.h> 84 #include <netinet6/ip6_var.h> 85 #include <netinet6/in6_gif.h> 86 #endif /* INET6 */ 87 88 #include <netinet/ip_encap.h> 89 #include <net/if_gif.h> 90 91 #include "ioconf.h" 92 93 #ifdef NET_MPSAFE 94 #define GIF_MPSAFE 1 95 #endif 96 97 /* 98 * gif global variable definitions 99 */ 100 LIST_HEAD(gif_sclist, gif_softc); 101 static struct { 102 struct gif_sclist list; 103 kmutex_t lock; 104 } gif_softcs __cacheline_aligned; 105 106 pserialize_t gif_psz __read_mostly; 107 struct psref_class *gv_psref_class __read_mostly; 108 109 static void gif_ro_init_pc(void *, void *, struct cpu_info *); 110 static void gif_ro_fini_pc(void *, void *, struct cpu_info *); 111 112 static int gifattach0(struct gif_softc *); 113 static int gif_output(struct ifnet *, struct mbuf *, 114 const struct sockaddr *, const struct rtentry *); 115 static void gif_start(struct ifnet *); 116 static int gif_transmit(struct ifnet *, struct mbuf *); 117 static int gif_transmit_direct(struct gif_variant *, struct mbuf *); 118 static int gif_ioctl(struct ifnet *, u_long, void *); 119 static int gif_set_tunnel(struct ifnet *, struct sockaddr *, 120 struct sockaddr *); 121 static void gif_delete_tunnel(struct ifnet *); 122 123 static int gif_clone_create(struct if_clone *, int); 124 static int gif_clone_destroy(struct ifnet *); 125 static int gif_check_nesting(struct ifnet *, struct mbuf *); 126 127 static int gif_encap_attach(struct gif_variant *); 128 static int gif_encap_detach(struct gif_variant *); 129 130 static void gif_update_variant(struct gif_softc *, struct gif_variant *); 131 132 static struct if_clone gif_cloner = 133 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); 134 135 #ifndef MAX_GIF_NEST 136 /* 137 * This macro controls the upper limitation on nesting of gif tunnels. 138 * Since, setting a large value to this macro with a careless configuration 139 * may introduce system crash, we don't allow any nestings by default. 140 * If you need to configure nested gif tunnels, you can define this macro 141 * in your kernel configuration file. However, if you do so, please be 142 * careful to configure the tunnels so that it won't make a loop. 143 */ 144 #define MAX_GIF_NEST 1 145 #endif 146 static int max_gif_nesting = MAX_GIF_NEST; 147 148 static struct sysctllog *gif_sysctl; 149 150 static void 151 gif_sysctl_setup(void) 152 { 153 gif_sysctl = NULL; 154 155 #ifdef INET 156 /* 157 * Previously create "net.inet.ip" entry to avoid sysctl_createv error. 158 */ 159 sysctl_createv(NULL, 0, NULL, NULL, 160 CTLFLAG_PERMANENT, 161 CTLTYPE_NODE, "inet", 162 SYSCTL_DESCR("PF_INET related settings"), 163 NULL, 0, NULL, 0, 164 CTL_NET, PF_INET, CTL_EOL); 165 sysctl_createv(NULL, 0, NULL, NULL, 166 CTLFLAG_PERMANENT, 167 CTLTYPE_NODE, "ip", 168 SYSCTL_DESCR("IPv4 related settings"), 169 NULL, 0, NULL, 0, 170 CTL_NET, PF_INET, IPPROTO_IP, CTL_EOL); 171 172 sysctl_createv(&gif_sysctl, 0, NULL, NULL, 173 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 174 CTLTYPE_INT, "gifttl", 175 SYSCTL_DESCR("Default TTL for a gif tunnel datagram"), 176 NULL, 0, &ip_gif_ttl, 0, 177 CTL_NET, PF_INET, IPPROTO_IP, 178 IPCTL_GIF_TTL, CTL_EOL); 179 #endif 180 #ifdef INET6 181 /* 182 * Previously create "net.inet6.ip6" entry to avoid sysctl_createv error. 183 */ 184 sysctl_createv(NULL, 0, NULL, NULL, 185 CTLFLAG_PERMANENT, 186 CTLTYPE_NODE, "inet6", 187 SYSCTL_DESCR("PF_INET6 related settings"), 188 NULL, 0, NULL, 0, 189 CTL_NET, PF_INET6, CTL_EOL); 190 sysctl_createv(NULL, 0, NULL, NULL, 191 CTLFLAG_PERMANENT, 192 CTLTYPE_NODE, "ip6", 193 SYSCTL_DESCR("IPv6 related settings"), 194 NULL, 0, NULL, 0, 195 CTL_NET, PF_INET6, IPPROTO_IPV6, CTL_EOL); 196 197 sysctl_createv(&gif_sysctl, 0, NULL, NULL, 198 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 199 CTLTYPE_INT, "gifhlim", 200 SYSCTL_DESCR("Default hop limit for a gif tunnel datagram"), 201 NULL, 0, &ip6_gif_hlim, 0, 202 CTL_NET, PF_INET6, IPPROTO_IPV6, 203 IPV6CTL_GIF_HLIM, CTL_EOL); 204 #endif 205 } 206 207 /* ARGSUSED */ 208 void 209 gifattach(int count) 210 { 211 /* 212 * Nothing to do here, initialization is handled by the 213 * module initialization code in gifinit() below). 214 */ 215 } 216 217 static void 218 gifinit(void) 219 { 220 221 mutex_init(&gif_softcs.lock, MUTEX_DEFAULT, IPL_NONE); 222 LIST_INIT(&gif_softcs.list); 223 if_clone_attach(&gif_cloner); 224 225 gif_psz = pserialize_create(); 226 gv_psref_class = psref_class_create("gifvar", IPL_SOFTNET); 227 228 gif_sysctl_setup(); 229 } 230 231 static int 232 gifdetach(void) 233 { 234 int error = 0; 235 236 mutex_enter(&gif_softcs.lock); 237 if (!LIST_EMPTY(&gif_softcs.list)) { 238 mutex_exit(&gif_softcs.lock); 239 error = EBUSY; 240 } 241 242 if (error == 0) { 243 psref_class_destroy(gv_psref_class); 244 pserialize_destroy(gif_psz); 245 246 if_clone_detach(&gif_cloner); 247 sysctl_teardown(&gif_sysctl); 248 } 249 250 return error; 251 } 252 253 static int 254 gif_clone_create(struct if_clone *ifc, int unit) 255 { 256 struct gif_softc *sc; 257 struct gif_variant *var; 258 int rv; 259 260 sc = kmem_zalloc(sizeof(struct gif_softc), KM_SLEEP); 261 262 if_initname(&sc->gif_if, ifc->ifc_name, unit); 263 264 rv = gifattach0(sc); 265 if (rv != 0) { 266 kmem_free(sc, sizeof(struct gif_softc)); 267 return rv; 268 } 269 270 var = kmem_zalloc(sizeof(*var), KM_SLEEP); 271 var->gv_softc = sc; 272 psref_target_init(&var->gv_psref, gv_psref_class); 273 274 sc->gif_var = var; 275 mutex_init(&sc->gif_lock, MUTEX_DEFAULT, IPL_NONE); 276 sc->gif_ro_percpu = percpu_alloc(sizeof(struct gif_ro)); 277 percpu_foreach(sc->gif_ro_percpu, gif_ro_init_pc, NULL); 278 279 mutex_enter(&gif_softcs.lock); 280 LIST_INSERT_HEAD(&gif_softcs.list, sc, gif_list); 281 mutex_exit(&gif_softcs.lock); 282 return 0; 283 } 284 285 static int 286 gifattach0(struct gif_softc *sc) 287 { 288 int rv; 289 290 sc->gif_if.if_addrlen = 0; 291 sc->gif_if.if_mtu = GIF_MTU; 292 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 293 sc->gif_if.if_extflags = IFEF_NO_LINK_STATE_CHANGE; 294 #ifdef GIF_MPSAFE 295 sc->gif_if.if_extflags |= IFEF_MPSAFE; 296 #endif 297 sc->gif_if.if_ioctl = gif_ioctl; 298 sc->gif_if.if_output = gif_output; 299 sc->gif_if.if_start = gif_start; 300 sc->gif_if.if_transmit = gif_transmit; 301 sc->gif_if.if_type = IFT_GIF; 302 sc->gif_if.if_dlt = DLT_NULL; 303 sc->gif_if.if_softc = sc; 304 IFQ_SET_READY(&sc->gif_if.if_snd); 305 rv = if_initialize(&sc->gif_if); 306 if (rv != 0) 307 return rv; 308 309 if_alloc_sadl(&sc->gif_if); 310 bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 311 if_register(&sc->gif_if); 312 return 0; 313 } 314 315 static void 316 gif_ro_init_pc(void *p, void *arg __unused, struct cpu_info *ci __unused) 317 { 318 struct gif_ro *gro = p; 319 320 gro->gr_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); 321 } 322 323 static void 324 gif_ro_fini_pc(void *p, void *arg __unused, struct cpu_info *ci __unused) 325 { 326 struct gif_ro *gro = p; 327 328 rtcache_free(&gro->gr_ro); 329 330 mutex_obj_free(gro->gr_lock); 331 } 332 333 void 334 gif_rtcache_free_pc(void *p, void *arg __unused, struct cpu_info *ci __unused) 335 { 336 struct gif_ro *gro = p; 337 338 rtcache_free(&gro->gr_ro); 339 } 340 341 static int 342 gif_clone_destroy(struct ifnet *ifp) 343 { 344 struct gif_softc *sc = (void *) ifp; 345 struct gif_variant *var; 346 347 LIST_REMOVE(sc, gif_list); 348 349 gif_delete_tunnel(&sc->gif_if); 350 bpf_detach(ifp); 351 if_detach(ifp); 352 353 percpu_foreach(sc->gif_ro_percpu, gif_ro_fini_pc, NULL); 354 percpu_free(sc->gif_ro_percpu, sizeof(struct gif_ro)); 355 356 mutex_destroy(&sc->gif_lock); 357 358 var = sc->gif_var; 359 kmem_free(var, sizeof(*var)); 360 kmem_free(sc, sizeof(struct gif_softc)); 361 362 return 0; 363 } 364 365 #ifdef GIF_ENCAPCHECK 366 int 367 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg) 368 { 369 struct ip ip; 370 struct gif_softc *sc; 371 struct gif_variant *var; 372 struct psref psref; 373 int ret = 0; 374 375 sc = arg; 376 if (sc == NULL) 377 return 0; 378 379 if ((sc->gif_if.if_flags & IFF_UP) == 0) 380 return 0; 381 382 var = gif_getref_variant(sc, &psref); 383 /* no physical address */ 384 if (var->gv_psrc == NULL || var->gv_pdst == NULL) 385 goto out; 386 387 switch (proto) { 388 #ifdef INET 389 case IPPROTO_IPV4: 390 break; 391 #endif 392 #ifdef INET6 393 case IPPROTO_IPV6: 394 break; 395 #endif 396 default: 397 goto out; 398 } 399 400 /* Bail on short packets */ 401 KASSERT(m->m_flags & M_PKTHDR); 402 if (m->m_pkthdr.len < sizeof(ip)) 403 goto out; 404 405 m_copydata(m, 0, sizeof(ip), &ip); 406 407 switch (ip.ip_v) { 408 #ifdef INET 409 case 4: 410 if (var->gv_psrc->sa_family != AF_INET || 411 var->gv_pdst->sa_family != AF_INET) 412 goto out; 413 ret = gif_encapcheck4(m, off, proto, var); 414 break; 415 #endif 416 #ifdef INET6 417 case 6: 418 if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 419 goto out; 420 if (var->gv_psrc->sa_family != AF_INET6 || 421 var->gv_pdst->sa_family != AF_INET6) 422 goto out; 423 ret = gif_encapcheck6(m, off, proto, var); 424 break; 425 #endif 426 default: 427 goto out; 428 } 429 430 out: 431 gif_putref_variant(var, &psref); 432 return ret; 433 } 434 #endif 435 436 /* 437 * gif may cause infinite recursion calls when misconfigured. 438 * We'll prevent this by introducing upper limit. 439 */ 440 static int 441 gif_check_nesting(struct ifnet *ifp, struct mbuf *m) 442 { 443 444 return if_tunnel_check_nesting(ifp, m, max_gif_nesting); 445 } 446 447 static int 448 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 449 const struct rtentry *rt) 450 { 451 struct gif_softc *sc = ifp->if_softc; 452 struct gif_variant *var = NULL; 453 struct psref psref; 454 int error = 0; 455 456 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 457 458 if ((error = gif_check_nesting(ifp, m)) != 0) { 459 m_freem(m); 460 goto end; 461 } 462 463 if ((ifp->if_flags & IFF_UP) == 0) { 464 m_freem(m); 465 error = ENETDOWN; 466 goto end; 467 } 468 469 var = gif_getref_variant(sc, &psref); 470 if (var->gv_psrc == NULL || var->gv_pdst == NULL) { 471 m_freem(m); 472 error = ENETDOWN; 473 goto end; 474 } 475 /* XXX should we check if our outer source is legal? */ 476 477 m->m_flags &= ~(M_BCAST|M_MCAST); 478 479 /* use DLT_NULL encapsulation here to pass inner af type */ 480 M_PREPEND(m, sizeof(int), M_DONTWAIT); 481 if (!m) { 482 error = ENOBUFS; 483 goto end; 484 } 485 *mtod(m, int *) = dst->sa_family; 486 487 /* Clear checksum-offload flags. */ 488 m->m_pkthdr.csum_flags = 0; 489 m->m_pkthdr.csum_data = 0; 490 491 error = gif_transmit_direct(var, m); 492 end: 493 if (var != NULL) 494 gif_putref_variant(var, &psref); 495 if (error) 496 ifp->if_oerrors++; 497 return error; 498 } 499 500 static void 501 gif_start(struct ifnet *ifp) 502 { 503 struct gif_softc *sc; 504 struct gif_variant *var; 505 struct mbuf *m; 506 struct psref psref; 507 int family; 508 int len; 509 int error; 510 511 sc = ifp->if_softc; 512 var = gif_getref_variant(sc, &psref); 513 514 KASSERT(var->gv_output != NULL); 515 516 /* output processing */ 517 while (1) { 518 IFQ_DEQUEUE(&sc->gif_if.if_snd, m); 519 if (m == NULL) 520 break; 521 522 /* grab and chop off inner af type */ 523 if (sizeof(int) > m->m_len) { 524 m = m_pullup(m, sizeof(int)); 525 if (!m) { 526 ifp->if_oerrors++; 527 continue; 528 } 529 } 530 family = *mtod(m, int *); 531 bpf_mtap(ifp, m, BPF_D_OUT); 532 m_adj(m, sizeof(int)); 533 534 len = m->m_pkthdr.len; 535 536 error = var->gv_output(var, family, m); 537 if (error) 538 ifp->if_oerrors++; 539 else { 540 ifp->if_opackets++; 541 ifp->if_obytes += len; 542 } 543 } 544 545 gif_putref_variant(var, &psref); 546 } 547 548 static int 549 gif_transmit(struct ifnet *ifp, struct mbuf *m) 550 { 551 struct gif_softc *sc; 552 struct gif_variant *var; 553 struct psref psref; 554 int error; 555 556 sc = ifp->if_softc; 557 558 /* output processing */ 559 if (m == NULL) 560 return EINVAL; 561 562 var = gif_getref_variant(sc, &psref); 563 error = gif_transmit_direct(var, m); 564 gif_putref_variant(var, &psref); 565 566 return error; 567 } 568 569 static int 570 gif_transmit_direct(struct gif_variant *var, struct mbuf *m) 571 { 572 struct ifnet *ifp = &var->gv_softc->gif_if; 573 int error; 574 int family; 575 int len; 576 577 KASSERT(gif_heldref_variant(var)); 578 KASSERT(var->gv_output != NULL); 579 580 /* grab and chop off inner af type */ 581 if (sizeof(int) > m->m_len) { 582 m = m_pullup(m, sizeof(int)); 583 if (!m) { 584 ifp->if_oerrors++; 585 return ENOBUFS; 586 } 587 } 588 family = *mtod(m, int *); 589 bpf_mtap(ifp, m, BPF_D_OUT); 590 m_adj(m, sizeof(int)); 591 592 len = m->m_pkthdr.len; 593 594 error = var->gv_output(var, family, m); 595 if (error) 596 ifp->if_oerrors++; 597 else { 598 ifp->if_opackets++; 599 ifp->if_obytes += len; 600 } 601 602 return error; 603 } 604 605 void 606 gif_input(struct mbuf *m, int af, struct ifnet *ifp) 607 { 608 pktqueue_t *pktq; 609 size_t pktlen; 610 611 if (ifp == NULL) { 612 /* just in case */ 613 m_freem(m); 614 return; 615 } 616 617 m_set_rcvif(m, ifp); 618 pktlen = m->m_pkthdr.len; 619 620 bpf_mtap_af(ifp, af, m, BPF_D_IN); 621 622 /* 623 * Put the packet to the network layer input queue according to the 624 * specified address family. Note: we avoid direct call to the 625 * input function of the network layer in order to avoid recursion. 626 * This may be revisited in the future. 627 */ 628 switch (af) { 629 #ifdef INET 630 case AF_INET: 631 pktq = ip_pktq; 632 break; 633 #endif 634 #ifdef INET6 635 case AF_INET6: 636 pktq = ip6_pktq; 637 break; 638 #endif 639 default: 640 m_freem(m); 641 return; 642 } 643 644 #ifdef GIF_MPSAFE 645 const u_int h = curcpu()->ci_index; 646 #else 647 const uint32_t h = pktq_rps_hash(m); 648 #endif 649 if (__predict_true(pktq_enqueue(pktq, m, h))) { 650 ifp->if_ibytes += pktlen; 651 ifp->if_ipackets++; 652 } else { 653 m_freem(m); 654 } 655 } 656 657 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 658 static int 659 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data) 660 { 661 struct gif_softc *sc = ifp->if_softc; 662 struct ifreq *ifr = (struct ifreq*)data; 663 struct ifaddr *ifa = (struct ifaddr*)data; 664 int error = 0, size, bound; 665 struct sockaddr *dst, *src; 666 struct gif_variant *var; 667 struct psref psref; 668 669 switch (cmd) { 670 case SIOCINITIFADDR: 671 ifp->if_flags |= IFF_UP; 672 ifa->ifa_rtrequest = p2p_rtrequest; 673 break; 674 675 case SIOCADDMULTI: 676 case SIOCDELMULTI: 677 switch (ifr->ifr_addr.sa_family) { 678 #ifdef INET 679 case AF_INET: /* IP supports Multicast */ 680 break; 681 #endif /* INET */ 682 #ifdef INET6 683 case AF_INET6: /* IP6 supports Multicast */ 684 break; 685 #endif /* INET6 */ 686 default: /* Other protocols doesn't support Multicast */ 687 error = EAFNOSUPPORT; 688 break; 689 } 690 break; 691 692 case SIOCSIFMTU: 693 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) 694 return EINVAL; 695 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 696 error = 0; 697 break; 698 699 #ifdef INET 700 case SIOCSIFPHYADDR: 701 #endif 702 #ifdef INET6 703 case SIOCSIFPHYADDR_IN6: 704 #endif /* INET6 */ 705 case SIOCSLIFPHYADDR: 706 switch (cmd) { 707 #ifdef INET 708 case SIOCSIFPHYADDR: 709 src = (struct sockaddr *) 710 &(((struct in_aliasreq *)data)->ifra_addr); 711 dst = (struct sockaddr *) 712 &(((struct in_aliasreq *)data)->ifra_dstaddr); 713 break; 714 #endif 715 #ifdef INET6 716 case SIOCSIFPHYADDR_IN6: 717 src = (struct sockaddr *) 718 &(((struct in6_aliasreq *)data)->ifra_addr); 719 dst = (struct sockaddr *) 720 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 721 break; 722 #endif 723 case SIOCSLIFPHYADDR: 724 src = (struct sockaddr *) 725 &(((struct if_laddrreq *)data)->addr); 726 dst = (struct sockaddr *) 727 &(((struct if_laddrreq *)data)->dstaddr); 728 break; 729 default: 730 return EINVAL; 731 } 732 733 /* sa_family must be equal */ 734 if (src->sa_family != dst->sa_family) 735 return EINVAL; 736 737 /* validate sa_len */ 738 switch (src->sa_family) { 739 #ifdef INET 740 case AF_INET: 741 if (src->sa_len != sizeof(struct sockaddr_in)) 742 return EINVAL; 743 break; 744 #endif 745 #ifdef INET6 746 case AF_INET6: 747 if (src->sa_len != sizeof(struct sockaddr_in6)) 748 return EINVAL; 749 break; 750 #endif 751 default: 752 return EAFNOSUPPORT; 753 } 754 switch (dst->sa_family) { 755 #ifdef INET 756 case AF_INET: 757 if (dst->sa_len != sizeof(struct sockaddr_in)) 758 return EINVAL; 759 break; 760 #endif 761 #ifdef INET6 762 case AF_INET6: 763 if (dst->sa_len != sizeof(struct sockaddr_in6)) 764 return EINVAL; 765 break; 766 #endif 767 default: 768 return EAFNOSUPPORT; 769 } 770 771 /* check sa_family looks sane for the cmd */ 772 switch (cmd) { 773 case SIOCSIFPHYADDR: 774 if (src->sa_family == AF_INET) 775 break; 776 return EAFNOSUPPORT; 777 #ifdef INET6 778 case SIOCSIFPHYADDR_IN6: 779 if (src->sa_family == AF_INET6) 780 break; 781 return EAFNOSUPPORT; 782 #endif /* INET6 */ 783 case SIOCSLIFPHYADDR: 784 /* checks done in the above */ 785 break; 786 } 787 /* 788 * calls gif_getref_variant() for other softcs to check 789 * address pair duplicattion 790 */ 791 bound = curlwp_bind(); 792 error = gif_set_tunnel(&sc->gif_if, src, dst); 793 curlwp_bindx(bound); 794 break; 795 796 #ifdef SIOCDIFPHYADDR 797 case SIOCDIFPHYADDR: 798 bound = curlwp_bind(); 799 gif_delete_tunnel(&sc->gif_if); 800 curlwp_bindx(bound); 801 break; 802 #endif 803 804 case SIOCGIFPSRCADDR: 805 #ifdef INET6 806 case SIOCGIFPSRCADDR_IN6: 807 #endif /* INET6 */ 808 bound = curlwp_bind(); 809 var = gif_getref_variant(sc, &psref); 810 if (var->gv_psrc == NULL) { 811 gif_putref_variant(var, &psref); 812 curlwp_bindx(bound); 813 error = EADDRNOTAVAIL; 814 goto bad; 815 } 816 src = var->gv_psrc; 817 switch (cmd) { 818 #ifdef INET 819 case SIOCGIFPSRCADDR: 820 dst = &ifr->ifr_addr; 821 size = sizeof(ifr->ifr_addr); 822 break; 823 #endif /* INET */ 824 #ifdef INET6 825 case SIOCGIFPSRCADDR_IN6: 826 dst = (struct sockaddr *) 827 &(((struct in6_ifreq *)data)->ifr_addr); 828 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 829 break; 830 #endif /* INET6 */ 831 default: 832 gif_putref_variant(var, &psref); 833 curlwp_bindx(bound); 834 error = EADDRNOTAVAIL; 835 goto bad; 836 } 837 if (src->sa_len > size) { 838 gif_putref_variant(var, &psref); 839 curlwp_bindx(bound); 840 return EINVAL; 841 } 842 memcpy(dst, src, src->sa_len); 843 gif_putref_variant(var, &psref); 844 curlwp_bindx(bound); 845 break; 846 847 case SIOCGIFPDSTADDR: 848 #ifdef INET6 849 case SIOCGIFPDSTADDR_IN6: 850 #endif /* INET6 */ 851 bound = curlwp_bind(); 852 var = gif_getref_variant(sc, &psref); 853 if (var->gv_pdst == NULL) { 854 gif_putref_variant(var, &psref); 855 curlwp_bindx(bound); 856 error = EADDRNOTAVAIL; 857 goto bad; 858 } 859 src = var->gv_pdst; 860 switch (cmd) { 861 #ifdef INET 862 case SIOCGIFPDSTADDR: 863 dst = &ifr->ifr_addr; 864 size = sizeof(ifr->ifr_addr); 865 break; 866 #endif /* INET */ 867 #ifdef INET6 868 case SIOCGIFPDSTADDR_IN6: 869 dst = (struct sockaddr *) 870 &(((struct in6_ifreq *)data)->ifr_addr); 871 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 872 break; 873 #endif /* INET6 */ 874 default: 875 gif_putref_variant(var, &psref); 876 curlwp_bindx(bound); 877 error = EADDRNOTAVAIL; 878 goto bad; 879 } 880 if (src->sa_len > size) { 881 gif_putref_variant(var, &psref); 882 curlwp_bindx(bound); 883 return EINVAL; 884 } 885 memcpy(dst, src, src->sa_len); 886 gif_putref_variant(var, &psref); 887 curlwp_bindx(bound); 888 break; 889 890 case SIOCGLIFPHYADDR: 891 bound = curlwp_bind(); 892 var = gif_getref_variant(sc, &psref); 893 if (var->gv_psrc == NULL || var->gv_pdst == NULL) { 894 gif_putref_variant(var, &psref); 895 curlwp_bindx(bound); 896 error = EADDRNOTAVAIL; 897 goto bad; 898 } 899 900 /* copy src */ 901 src = var->gv_psrc; 902 dst = (struct sockaddr *) 903 &(((struct if_laddrreq *)data)->addr); 904 size = sizeof(((struct if_laddrreq *)data)->addr); 905 if (src->sa_len > size) { 906 gif_putref_variant(var, &psref); 907 curlwp_bindx(bound); 908 return EINVAL; 909 } 910 memcpy(dst, src, src->sa_len); 911 912 /* copy dst */ 913 src = var->gv_pdst; 914 dst = (struct sockaddr *) 915 &(((struct if_laddrreq *)data)->dstaddr); 916 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 917 if (src->sa_len > size) { 918 gif_putref_variant(var, &psref); 919 curlwp_bindx(bound); 920 return EINVAL; 921 } 922 memcpy(dst, src, src->sa_len); 923 gif_putref_variant(var, &psref); 924 curlwp_bindx(bound); 925 break; 926 927 default: 928 return ifioctl_common(ifp, cmd, data); 929 } 930 bad: 931 return error; 932 } 933 934 static int 935 gif_encap_attach(struct gif_variant *var) 936 { 937 int error; 938 939 if (var == NULL || var->gv_psrc == NULL) 940 return EINVAL; 941 942 switch (var->gv_psrc->sa_family) { 943 #ifdef INET 944 case AF_INET: 945 error = in_gif_attach(var); 946 break; 947 #endif 948 #ifdef INET6 949 case AF_INET6: 950 error = in6_gif_attach(var); 951 break; 952 #endif 953 default: 954 error = EINVAL; 955 break; 956 } 957 958 return error; 959 } 960 961 static int 962 gif_encap_detach(struct gif_variant *var) 963 { 964 int error; 965 966 if (var == NULL || var->gv_psrc == NULL) 967 return EINVAL; 968 969 switch (var->gv_psrc->sa_family) { 970 #ifdef INET 971 case AF_INET: 972 error = in_gif_detach(var); 973 break; 974 #endif 975 #ifdef INET6 976 case AF_INET6: 977 error = in6_gif_detach(var); 978 break; 979 #endif 980 default: 981 error = EINVAL; 982 break; 983 } 984 985 return error; 986 } 987 988 static int 989 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) 990 { 991 struct gif_softc *sc = ifp->if_softc; 992 struct gif_softc *sc2; 993 struct gif_variant *ovar, *nvar; 994 struct sockaddr *osrc, *odst; 995 struct sockaddr *nsrc, *ndst; 996 int error; 997 #ifndef GIF_MPSAFE 998 int s; 999 1000 s = splsoftnet(); 1001 #endif 1002 error = encap_lock_enter(); 1003 if (error) { 1004 #ifndef GIF_MPSAFE 1005 splx(s); 1006 #endif 1007 return error; 1008 } 1009 1010 nsrc = sockaddr_dup(src, M_WAITOK); 1011 ndst = sockaddr_dup(dst, M_WAITOK); 1012 nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1013 1014 mutex_enter(&sc->gif_lock); 1015 1016 ovar = sc->gif_var; 1017 1018 if ((ovar->gv_pdst && sockaddr_cmp(ovar->gv_pdst, dst) == 0) && 1019 (ovar->gv_psrc && sockaddr_cmp(ovar->gv_psrc, src) == 0)) { 1020 /* address and port pair not changed. */ 1021 error = 0; 1022 goto out; 1023 } 1024 1025 mutex_enter(&gif_softcs.lock); 1026 LIST_FOREACH(sc2, &gif_softcs.list, gif_list) { 1027 struct gif_variant *var2; 1028 struct psref psref; 1029 1030 if (sc2 == sc) 1031 continue; 1032 var2 = gif_getref_variant(sc, &psref); 1033 if (!var2->gv_pdst || !var2->gv_psrc) { 1034 gif_putref_variant(var2, &psref); 1035 continue; 1036 } 1037 /* can't configure same pair of address onto two gifs */ 1038 if (sockaddr_cmp(var2->gv_pdst, dst) == 0 && 1039 sockaddr_cmp(var2->gv_psrc, src) == 0) { 1040 /* continue to use the old configureation. */ 1041 gif_putref_variant(var2, &psref); 1042 mutex_exit(&gif_softcs.lock); 1043 error = EADDRNOTAVAIL; 1044 goto out; 1045 } 1046 gif_putref_variant(var2, &psref); 1047 /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 1048 } 1049 mutex_exit(&gif_softcs.lock); 1050 1051 osrc = ovar->gv_psrc; 1052 odst = ovar->gv_pdst; 1053 1054 *nvar = *ovar; 1055 nvar->gv_psrc = nsrc; 1056 nvar->gv_pdst = ndst; 1057 nvar->gv_encap_cookie4 = NULL; 1058 nvar->gv_encap_cookie6 = NULL; 1059 error = gif_encap_attach(nvar); 1060 if (error) 1061 goto out; 1062 psref_target_init(&nvar->gv_psref, gv_psref_class); 1063 membar_producer(); 1064 gif_update_variant(sc, nvar); 1065 1066 mutex_exit(&sc->gif_lock); 1067 1068 (void)gif_encap_detach(ovar); 1069 encap_lock_exit(); 1070 1071 if (osrc) 1072 sockaddr_free(osrc); 1073 if (odst) 1074 sockaddr_free(odst); 1075 kmem_free(ovar, sizeof(*ovar)); 1076 1077 #ifndef GIF_MPSAFE 1078 splx(s); 1079 #endif 1080 return 0; 1081 1082 out: 1083 sockaddr_free(nsrc); 1084 sockaddr_free(ndst); 1085 kmem_free(nvar, sizeof(*nvar)); 1086 1087 mutex_exit(&sc->gif_lock); 1088 encap_lock_exit(); 1089 #ifndef GIF_MPSAFE 1090 splx(s); 1091 #endif 1092 return error; 1093 } 1094 1095 static void 1096 gif_delete_tunnel(struct ifnet *ifp) 1097 { 1098 struct gif_softc *sc = ifp->if_softc; 1099 struct gif_variant *ovar, *nvar; 1100 struct sockaddr *osrc, *odst; 1101 int error; 1102 #ifndef GIF_MPSAFE 1103 int s; 1104 1105 s = splsoftnet(); 1106 #endif 1107 error = encap_lock_enter(); 1108 if (error) { 1109 #ifndef GIF_MPSAFE 1110 splx(s); 1111 #endif 1112 return; 1113 } 1114 1115 nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1116 1117 mutex_enter(&sc->gif_lock); 1118 1119 ovar = sc->gif_var; 1120 osrc = ovar->gv_psrc; 1121 odst = ovar->gv_pdst; 1122 if (osrc == NULL || odst == NULL) { 1123 /* address pair not changed. */ 1124 mutex_exit(&sc->gif_lock); 1125 encap_lock_exit(); 1126 kmem_free(nvar, sizeof(*nvar)); 1127 #ifndef GIF_MPSAFE 1128 splx(s); 1129 #endif 1130 return; 1131 } 1132 1133 *nvar = *ovar; 1134 nvar->gv_psrc = NULL; 1135 nvar->gv_pdst = NULL; 1136 nvar->gv_encap_cookie4 = NULL; 1137 nvar->gv_encap_cookie6 = NULL; 1138 nvar->gv_output = NULL; 1139 psref_target_init(&nvar->gv_psref, gv_psref_class); 1140 membar_producer(); 1141 gif_update_variant(sc, nvar); 1142 1143 mutex_exit(&sc->gif_lock); 1144 1145 gif_encap_detach(ovar); 1146 encap_lock_exit(); 1147 1148 sockaddr_free(osrc); 1149 sockaddr_free(odst); 1150 kmem_free(ovar, sizeof(*ovar)); 1151 1152 #ifndef GIF_MPSAFE 1153 splx(s); 1154 #endif 1155 } 1156 1157 /* 1158 * gif_variant update API. 1159 * 1160 * Assumption: 1161 * reader side dereferences sc->gif_var in reader critical section only, 1162 * that is, all of reader sides do not reader the sc->gif_var after 1163 * pserialize_perform(). 1164 */ 1165 static void 1166 gif_update_variant(struct gif_softc *sc, struct gif_variant *nvar) 1167 { 1168 struct ifnet *ifp = &sc->gif_if; 1169 struct gif_variant *ovar = sc->gif_var; 1170 1171 KASSERT(mutex_owned(&sc->gif_lock)); 1172 1173 sc->gif_var = nvar; 1174 pserialize_perform(gif_psz); 1175 psref_target_destroy(&ovar->gv_psref, gv_psref_class); 1176 1177 if (nvar->gv_psrc != NULL && nvar->gv_pdst != NULL) 1178 ifp->if_flags |= IFF_RUNNING; 1179 else 1180 ifp->if_flags &= ~IFF_RUNNING; 1181 } 1182 1183 /* 1184 * Module infrastructure 1185 */ 1186 #include "if_module.h" 1187 1188 IF_MODULE(MODULE_CLASS_DRIVER, gif, "ip_ecn") 1189