1/* 2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.6 2001/07/24 19:10:18 brooks Exp $ */ 29/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */ 30 31/* 32 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. Neither the name of the project nor the names of its contributors 44 * may be used to endorse or promote products derived from this software 45 * without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 */ 59/* 60 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce 61 * support for mandatory and extensible security protections. This notice 62 * is included in support of clause 2.2 (b) of the Apple Public License, 63 * Version 2.0. 64 */ 65 66#include <sys/param.h> 67#include <sys/systm.h> 68#include <sys/kernel.h> 69#include <sys/malloc.h> 70#include <sys/mbuf.h> 71#include <sys/socket.h> 72#include <sys/sockio.h> 73#include <sys/errno.h> 74#include <sys/time.h> 75#include <sys/syslog.h> 76#include <sys/protosw.h> 77#include <kern/cpu_number.h> 78 79#include <net/if.h> 80#include <net/if_types.h> 81#include <net/route.h> 82#include <net/bpf.h> 83#include <net/kpi_protocol.h> 84#include <net/kpi_interface.h> 85#include <net/init.h> 86 87#include <netinet/in.h> 88#include <netinet/in_systm.h> 89#include <netinet/ip.h> 90#if INET 91#include <netinet/in_var.h> 92#include <netinet/in_gif.h> 93#include <netinet/ip_var.h> 94#endif /* INET */ 95 96#if INET6 97#include <netinet6/in6_var.h> 98#include <netinet/ip6.h> 99#include <netinet6/ip6_var.h> 100#include <netinet6/in6_gif.h> 101#include <netinet6/ip6protosw.h> 102#endif /* INET6 */ 103 104#include <netinet/ip_encap.h> 105#include <net/dlil.h> 106#include <net/if_gif.h> 107 108#include <net/net_osdep.h> 109 110#if CONFIG_MACF_NET 111#include <security/mac_framework.h> 112#endif 113 114#define GIFNAME "gif" 115#define GIFDEV "if_gif" 116#define GIF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */ 117 118/* gif lock variables */ 119static lck_grp_t *gif_mtx_grp; 120static lck_grp_attr_t *gif_mtx_grp_attr; 121static lck_attr_t *gif_mtx_attr; 122decl_lck_mtx_data(static, gif_mtx_data); 123static lck_mtx_t *gif_mtx = &gif_mtx_data; 124 125TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs); 126 127static int gif_encapcheck(const struct mbuf *, int, int, void *); 128static errno_t gif_output(ifnet_t ifp, mbuf_t m); 129static errno_t gif_input(ifnet_t ifp, protocol_family_t protocol_family, 130 mbuf_t m, char *frame_header); 131static errno_t gif_ioctl(ifnet_t ifp, u_long cmd, void *data); 132 133static int ngif = 0; /* number of interfaces */ 134 135#if INET 136static struct protosw in_gif_protosw = 137{ 138 .pr_type = SOCK_RAW, 139 .pr_protocol = 0, /* IPPROTO_IPV[46] */ 140 .pr_flags = PR_ATOMIC|PR_ADDR, 141 .pr_input = in_gif_input, 142 .pr_usrreqs = &rip_usrreqs, 143 .pr_unlock = rip_unlock, 144}; 145#endif 146#if INET6 147static struct ip6protosw in6_gif_protosw = 148{ 149 .pr_type = SOCK_RAW, 150 .pr_protocol = 0, /* IPPROTO_IPV[46] */ 151 .pr_flags = PR_ATOMIC|PR_ADDR, 152 .pr_input = in6_gif_input, 153 .pr_usrreqs = &rip6_usrreqs, 154 .pr_unlock = rip_unlock, 155}; 156#endif 157 158static if_clone_t gif_cloner = NULL; 159static int gif_clone_create(struct if_clone *, uint32_t, void *); 160static int gif_clone_destroy(struct ifnet *); 161static void gif_delete_tunnel(struct gif_softc *); 162static void gif_detach(struct ifnet *); 163 164/* 165 * Theory of operation: initially, one gif interface is created. 166 * Any time a gif interface is configured, if there are no other 167 * unconfigured gif interfaces, a new gif interface is created. 168 * BSD uses the clone mechanism to dynamically create more 169 * gif interfaces. 170 * 171 * We have some extra glue to support DLIL. 172 */ 173 174/* GIF interface module support */ 175static int 176gif_demux( 177 ifnet_t ifp, 178 __unused mbuf_t m, 179 __unused char *frame_header, 180 protocol_family_t *protocol_family) 181{ 182 struct gif_softc *sc = ifnet_softc(ifp); 183 184 GIF_LOCK(sc); 185 /* Only one protocol may be attached to a gif interface. */ 186 *protocol_family = sc->gif_proto; 187 GIF_UNLOCK(sc); 188 189 return (0); 190} 191 192static errno_t 193gif_add_proto( 194 ifnet_t ifp, 195 protocol_family_t protocol_family, 196 __unused const struct ifnet_demux_desc *demux_array, 197 __unused u_int32_t demux_count) 198{ 199 /* Only one protocol may be attached at a time */ 200 struct gif_softc *sc = ifnet_softc(ifp); 201 202 GIF_LOCK(sc); 203 if (sc->gif_proto != 0) 204 printf("gif_add_proto: request add_proto for gif%d\n", 205 ifnet_unit(ifp)); 206 207 sc->gif_proto = protocol_family; 208 GIF_UNLOCK(sc); 209 210 return (0); 211} 212 213static errno_t 214gif_del_proto( 215 ifnet_t ifp, 216 protocol_family_t protocol_family) 217{ 218 struct gif_softc *sc = ifnet_softc(ifp); 219 220 GIF_LOCK(sc); 221 if (sc->gif_proto == protocol_family) 222 sc->gif_proto = 0; 223 GIF_UNLOCK(sc); 224 225 return (0); 226} 227 228/* Glue code to attach inet to a gif interface through DLIL */ 229static errno_t 230gif_attach_proto_family( 231 ifnet_t ifp, 232 protocol_family_t protocol_family) 233{ 234 struct ifnet_attach_proto_param reg; 235 errno_t stat; 236 237 bzero(®, sizeof (reg)); 238 reg.input = gif_input; 239 240 stat = ifnet_attach_protocol(ifp, protocol_family, ®); 241 if (stat && stat != EEXIST) { 242 printf("gif_attach_proto_family can't attach interface \ 243 fam=%d\n", protocol_family); 244 } 245 246 return (stat); 247} 248 249/* Function to setup the first gif interface */ 250void 251gif_init(void) 252{ 253 errno_t result; 254 struct ifnet_clone_params ifnet_clone_params; 255 struct if_clone *ifc = NULL; 256 257 /* Initialize the list of interfaces */ 258 TAILQ_INIT(&gifs); 259 260 /* Initialize the gif global lock */ 261 gif_mtx_grp_attr = lck_grp_attr_alloc_init(); 262 gif_mtx_grp = lck_grp_alloc_init("gif", gif_mtx_grp_attr); 263 gif_mtx_attr = lck_attr_alloc_init(); 264 lck_mtx_init(gif_mtx, gif_mtx_grp, gif_mtx_attr); 265 266 /* Register protocol registration functions */ 267 result = proto_register_plumber(PF_INET, APPLE_IF_FAM_GIF, 268 gif_attach_proto_family, NULL); 269 if (result != 0) 270 printf("proto_register_plumber failed for AF_INET error=%d\n", 271 result); 272 273 result = proto_register_plumber(PF_INET6, APPLE_IF_FAM_GIF, 274 gif_attach_proto_family, NULL); 275 if (result != 0) 276 printf("proto_register_plumber failed for AF_INET6 error=%d\n", 277 result); 278 279 ifnet_clone_params.ifc_name = "gif"; 280 ifnet_clone_params.ifc_create = gif_clone_create; 281 ifnet_clone_params.ifc_destroy = gif_clone_destroy; 282 283 result = ifnet_clone_attach(&ifnet_clone_params, &gif_cloner); 284 if (result != 0) 285 printf("gifattach: ifnet_clone_attach failed %d\n", result); 286 287 /* Create first device */ 288 ifc = if_clone_lookup("gif", NULL); 289 gif_clone_create(ifc, 0, NULL); 290} 291 292static errno_t 293gif_set_bpf_tap( 294 ifnet_t ifp, 295 bpf_tap_mode mode, 296 bpf_packet_func callback) 297{ 298 struct gif_softc *sc = ifnet_softc(ifp); 299 300 GIF_LOCK(sc); 301 sc->tap_mode = mode; 302 sc->tap_callback = callback; 303 GIF_UNLOCK(sc); 304 305 return (0); 306} 307 308static void 309gif_detach(struct ifnet *ifp) 310{ 311 struct gif_softc *sc = ifp->if_softc; 312 lck_mtx_destroy(&sc->gif_lock, gif_mtx_grp); 313 _FREE(ifp->if_softc, M_DEVBUF); 314 ifp->if_softc = NULL; 315 (void) ifnet_release(ifp); 316} 317 318static int 319gif_clone_create(struct if_clone *ifc, uint32_t unit, __unused void *params) 320{ 321 struct gif_softc *sc = NULL; 322 struct ifnet_init_params gif_init_params; 323 errno_t error = 0; 324 325 lck_mtx_lock(gif_mtx); 326 327 /* Can't create more than GIF_MAXUNIT */ 328 if (ngif >= GIF_MAXUNIT) { 329 error = ENXIO; 330 goto done; 331 } 332 333 sc = _MALLOC(sizeof (struct gif_softc), M_DEVBUF, M_WAITOK); 334 if (sc == NULL) { 335 log(LOG_ERR, "gif_clone_create: failed to allocate gif%d\n", 336 unit); 337 error = ENOBUFS; 338 goto done; 339 } 340 bzero(sc, sizeof (struct gif_softc)); 341 342 /* use the interface name as the unique id for ifp recycle */ 343 snprintf(sc->gif_ifname, sizeof (sc->gif_ifname), "%s%d", 344 ifc->ifc_name, unit); 345 346 lck_mtx_init(&sc->gif_lock, gif_mtx_grp, gif_mtx_attr); 347 348 bzero(&gif_init_params, sizeof (gif_init_params)); 349 gif_init_params.uniqueid = sc->gif_ifname; 350 gif_init_params.uniqueid_len = strlen(sc->gif_ifname); 351 gif_init_params.name = GIFNAME; 352 gif_init_params.unit = unit; 353 gif_init_params.type = IFT_GIF; 354 gif_init_params.family = IFNET_FAMILY_GIF; 355 gif_init_params.output = gif_output; 356 gif_init_params.demux = gif_demux; 357 gif_init_params.add_proto = gif_add_proto; 358 gif_init_params.del_proto = gif_del_proto; 359 gif_init_params.softc = sc; 360 gif_init_params.ioctl = gif_ioctl; 361 gif_init_params.set_bpf_tap = gif_set_bpf_tap; 362 gif_init_params.detach = gif_detach; 363 364 error = ifnet_allocate(&gif_init_params, &sc->gif_if); 365 if (error != 0) { 366 printf("gif_clone_create, ifnet_allocate failed - %d\n", error); 367 _FREE(sc, M_DEVBUF); 368 error = ENOBUFS; 369 goto done; 370 } 371 372 sc->encap_cookie4 = sc->encap_cookie6 = NULL; 373#if INET 374 sc->encap_cookie4 = encap_attach_func(AF_INET, -1, 375 gif_encapcheck, &in_gif_protosw, sc); 376 if (sc->encap_cookie4 == NULL) { 377 printf("%s: unable to attach encap4\n", if_name(sc->gif_if)); 378 ifnet_release(sc->gif_if); 379 FREE(sc, M_DEVBUF); 380 error = ENOBUFS; 381 goto done; 382 } 383#endif 384#if INET6 385 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, 386 gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc); 387 if (sc->encap_cookie6 == NULL) { 388 if (sc->encap_cookie4) { 389 encap_detach(sc->encap_cookie4); 390 sc->encap_cookie4 = NULL; 391 } 392 printf("%s: unable to attach encap6\n", if_name(sc->gif_if)); 393 ifnet_release(sc->gif_if); 394 FREE(sc, M_DEVBUF); 395 error = ENOBUFS; 396 goto done; 397 } 398#endif 399 sc->gif_called = 0; 400 ifnet_set_mtu(sc->gif_if, GIF_MTU); 401 ifnet_set_flags(sc->gif_if, IFF_POINTOPOINT | IFF_MULTICAST, 0xffff); 402#if 0 403 /* turn off ingress filter */ 404 sc->gif_if.if_flags |= IFF_LINK2; 405#endif 406 error = ifnet_attach(sc->gif_if, NULL); 407 if (error != 0) { 408 printf("gif_clone_create - ifnet_attach failed - %d\n", error); 409 ifnet_release(sc->gif_if); 410 if (sc->encap_cookie4) { 411 encap_detach(sc->encap_cookie4); 412 sc->encap_cookie4 = NULL; 413 } 414 if (sc->encap_cookie6) { 415 encap_detach(sc->encap_cookie6); 416 sc->encap_cookie6 = NULL; 417 } 418 FREE(sc, M_DEVBUF); 419 goto done; 420 } 421#if CONFIG_MACF_NET 422 mac_ifnet_label_init(&sc->gif_if); 423#endif 424 bpfattach(sc->gif_if, DLT_NULL, sizeof (u_int)); 425 TAILQ_INSERT_TAIL(&gifs, sc, gif_link); 426 ngif++; 427done: 428 lck_mtx_unlock(gif_mtx); 429 430 return (error); 431} 432 433static int 434gif_clone_destroy(struct ifnet *ifp) 435{ 436#if defined(INET) || defined(INET6) 437 int error = 0; 438#endif 439 struct gif_softc *sc = ifp->if_softc; 440 441 lck_mtx_lock(gif_mtx); 442 TAILQ_REMOVE(&gifs, sc, gif_link); 443 ngif--; 444 445 GIF_LOCK(sc); 446 gif_delete_tunnel(sc); 447#ifdef INET6 448 if (sc->encap_cookie6 != NULL) { 449 error = encap_detach(sc->encap_cookie6); 450 KASSERT(error == 0, ("gif_clone_destroy: Unexpected \ 451 error detaching encap_cookie6")); 452 } 453#endif 454#ifdef INET 455 if (sc->encap_cookie4 != NULL) { 456 error = encap_detach(sc->encap_cookie4); 457 KASSERT(error == 0, ("gif_clone_destroy: Unexpected \ 458 error detaching encap_cookie4")); 459 } 460#endif 461 error = ifnet_set_flags(ifp, 0, IFF_UP); 462 if (error != 0) { 463 printf("gif_clone_destroy: ifnet_set_flags failed %d\n", error); 464 } 465 466 error = ifnet_detach(ifp); 467 if (error != 0) 468 panic("gif_clone_destroy: ifnet_detach(%p) failed %d\n", ifp, 469 error); 470 471 GIF_UNLOCK(sc); 472 lck_mtx_unlock(gif_mtx); 473 474 return (0); 475} 476 477static int 478gif_encapcheck( 479 const struct mbuf *m, 480 int off, 481 int proto, 482 void *arg) 483{ 484 int error = 0; 485 struct ip ip; 486 struct gif_softc *sc; 487 488 sc = (struct gif_softc *)arg; 489 if (sc == NULL) 490 return (error); 491 492 GIF_LOCK(sc); 493 if ((ifnet_flags(sc->gif_if) & IFF_UP) == 0) 494 goto done; 495 496 /* no physical address */ 497 if (!sc->gif_psrc || !sc->gif_pdst) 498 goto done; 499 500 switch (proto) { 501#if INET 502 case IPPROTO_IPV4: 503 break; 504#endif 505#if INET6 506 case IPPROTO_IPV6: 507 break; 508#endif 509 default: 510 goto done; 511 } 512 513 mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof (ip), &ip); 514 515 switch (ip.ip_v) { 516#if INET 517 case 4: 518 if (sc->gif_psrc->sa_family != AF_INET || 519 sc->gif_pdst->sa_family != AF_INET) 520 goto done; 521 error = gif_encapcheck4(m, off, proto, arg); 522#endif 523#if INET6 524 case 6: 525 if (sc->gif_psrc->sa_family != AF_INET6 || 526 sc->gif_pdst->sa_family != AF_INET6) 527 goto done; 528 error = gif_encapcheck6(m, off, proto, arg); 529#endif 530 default: 531 goto done; 532 } 533done: 534 GIF_UNLOCK(sc); 535 return (error); 536} 537 538static errno_t 539gif_output( 540 ifnet_t ifp, 541 mbuf_t m) 542{ 543 struct gif_softc *sc = ifnet_softc(ifp); 544 struct sockaddr *gif_psrc; 545 struct sockaddr *gif_pdst; 546 int error = 0; 547 548 GIF_LOCK(sc); 549 gif_psrc = sc->gif_psrc; 550 gif_pdst = sc->gif_pdst; 551 GIF_UNLOCK(sc); 552 553 /* 554 * max_gif_nesting check used to live here. It doesn't anymore 555 * because there is no guaruntee that we won't be called 556 * concurrently from more than one thread. 557 */ 558 m->m_flags &= ~(M_BCAST|M_MCAST); 559 if (!(ifnet_flags(ifp) & IFF_UP) || 560 gif_psrc == NULL || gif_pdst == NULL) { 561 ifnet_touch_lastchange(ifp); 562 m_freem(m); /* free it here not in dlil_output */ 563 error = ENETDOWN; 564 goto end; 565 } 566 567 bpf_tap_out(ifp, 0, m, &sc->gif_proto, sizeof (sc->gif_proto)); 568 569 GIF_LOCK(sc); 570 571 /* inner AF-specific encapsulation */ 572 573 /* XXX should we check if our outer source is legal? */ 574 575 /* dispatch to output logic based on outer AF */ 576 switch (sc->gif_psrc->sa_family) { 577#if INET 578 case AF_INET: 579 error = in_gif_output(ifp, sc->gif_proto, m, NULL); 580 break; 581#endif 582#if INET6 583 case AF_INET6: 584 error = in6_gif_output(ifp, sc->gif_proto, m, NULL); 585 break; 586#endif 587 default: 588 error = ENETDOWN; 589 break; 590 } 591 592 GIF_UNLOCK(sc); 593end: 594 if (error) { 595 /* the mbuf was freed either by in_gif_output or in here */ 596 ifnet_stat_increment_out(ifp, 0, 0, 1); 597 } else { 598 ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0); 599 } 600 if (error == 0) 601 error = EJUSTRETURN; /* if no error, packet got sent already */ 602 return (error); 603} 604 605/* 606 * gif_input is the input handler for IP and IPv6 attached to gif 607 */ 608static errno_t 609gif_input( 610 ifnet_t ifp, 611 protocol_family_t protocol_family, 612 mbuf_t m, 613 __unused char *frame_header) 614{ 615 struct gif_softc *sc = ifnet_softc(ifp); 616 617 bpf_tap_in(ifp, 0, m, &sc->gif_proto, sizeof (sc->gif_proto)); 618 619 /* 620 * Put the packet to the network layer input queue according to the 621 * specified address family. 622 * Note: older versions of gif_input directly called network layer 623 * input functions, e.g. ip6_input, here. We changed the policy to 624 * prevent too many recursive calls of such input functions, which 625 * might cause kernel panic. But the change may introduce another 626 * problem; if the input queue is full, packets are discarded. 627 * We believed it rarely occurs and changed the policy. If we find 628 * it occurs more times than we thought, we may change the policy 629 * again. 630 */ 631 if (proto_input(protocol_family, m) != 0) { 632 ifnet_stat_increment_in(ifp, 0, 0, 1); 633 m_freem(m); 634 } else 635 ifnet_stat_increment_in(ifp, 1, m->m_pkthdr.len, 0); 636 637 return (0); 638} 639 640/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 641static errno_t 642gif_ioctl( 643 ifnet_t ifp, 644 u_long cmd, 645 void *data) 646{ 647 struct gif_softc *sc = ifnet_softc(ifp); 648 struct ifreq *ifr = (struct ifreq *)data; 649 int error = 0, size; 650 struct sockaddr *dst = NULL, *src = NULL; 651 struct sockaddr *sa; 652 struct ifnet *ifp2; 653 struct gif_softc *sc2; 654 655 switch (cmd) { 656 case SIOCSIFADDR: 657 break; 658 659 case SIOCSIFDSTADDR: 660 break; 661 662 case SIOCADDMULTI: 663 case SIOCDELMULTI: 664 break; 665 666#ifdef SIOCSIFMTU /* xxx */ 667 case SIOCGIFMTU: 668 break; 669 670 case SIOCSIFMTU: 671 { 672 u_int32_t mtu; 673 mtu = ifr->ifr_mtu; 674 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { 675 return (EINVAL); 676 } 677 ifnet_set_mtu(ifp, mtu); 678 } 679 break; 680#endif /* SIOCSIFMTU */ 681 682 case SIOCSIFPHYADDR: 683#if INET6 684 case SIOCSIFPHYADDR_IN6_32: 685 case SIOCSIFPHYADDR_IN6_64: 686#endif /* INET6 */ 687 case SIOCSLIFPHYADDR: 688 switch (cmd) { 689#if INET 690 case SIOCSIFPHYADDR: 691 src = (struct sockaddr *) 692 &(((struct in_aliasreq *)data)->ifra_addr); 693 dst = (struct sockaddr *) 694 &(((struct in_aliasreq *)data)->ifra_dstaddr); 695 break; 696#endif 697#if INET6 698 case SIOCSIFPHYADDR_IN6_32: { 699 struct in6_aliasreq_32 *ifra_32 = 700 (struct in6_aliasreq_32 *)data; 701 702 src = (struct sockaddr *)&ifra_32->ifra_addr; 703 dst = (struct sockaddr *)&ifra_32->ifra_dstaddr; 704 break; 705 } 706 707 case SIOCSIFPHYADDR_IN6_64: { 708 struct in6_aliasreq_64 *ifra_64 = 709 (struct in6_aliasreq_64 *)data; 710 711 src = (struct sockaddr *)&ifra_64->ifra_addr; 712 dst = (struct sockaddr *)&ifra_64->ifra_dstaddr; 713 break; 714 } 715#endif 716 case SIOCSLIFPHYADDR: 717 src = (struct sockaddr *) 718 &(((struct if_laddrreq *)data)->addr); 719 dst = (struct sockaddr *) 720 &(((struct if_laddrreq *)data)->dstaddr); 721 } 722 723 /* sa_family must be equal */ 724 if (src->sa_family != dst->sa_family) 725 return (EINVAL); 726 727 /* validate sa_len */ 728 switch (src->sa_family) { 729#if INET 730 case AF_INET: 731 if (src->sa_len != sizeof (struct sockaddr_in)) 732 return (EINVAL); 733 break; 734#endif 735#if INET6 736 case AF_INET6: 737 if (src->sa_len != sizeof (struct sockaddr_in6)) 738 return (EINVAL); 739 break; 740#endif 741 default: 742 return (EAFNOSUPPORT); 743 } 744 switch (dst->sa_family) { 745#if INET 746 case AF_INET: 747 if (dst->sa_len != sizeof (struct sockaddr_in)) 748 return (EINVAL); 749 break; 750#endif 751#if INET6 752 case AF_INET6: 753 if (dst->sa_len != sizeof (struct sockaddr_in6)) 754 return (EINVAL); 755 break; 756#endif 757 default: 758 return (EAFNOSUPPORT); 759 } 760 761 /* check sa_family looks sane for the cmd */ 762 switch (cmd) { 763 case SIOCSIFPHYADDR: 764 if (src->sa_family == AF_INET) 765 break; 766 return (EAFNOSUPPORT); 767#if INET6 768 case SIOCSIFPHYADDR_IN6_32: 769 case SIOCSIFPHYADDR_IN6_64: 770 if (src->sa_family == AF_INET6) 771 break; 772 return (EAFNOSUPPORT); 773#endif /* INET6 */ 774 case SIOCSLIFPHYADDR: 775 /* checks done in the above */ 776 break; 777 } 778 779#define GIF_ORDERED_LOCK(sc, sc2) \ 780 if (sc < sc2) { \ 781 GIF_LOCK(sc); \ 782 GIF_LOCK(sc2); \ 783 } else { \ 784 GIF_LOCK(sc2); \ 785 GIF_LOCK(sc); \ 786 } 787 788#define GIF_ORDERED_UNLOCK(sc, sc2) \ 789 if (sc > sc2) { \ 790 GIF_UNLOCK(sc); \ 791 GIF_UNLOCK(sc2); \ 792 } else { \ 793 GIF_UNLOCK(sc2); \ 794 GIF_UNLOCK(sc); \ 795 } 796 797 ifnet_head_lock_shared(); 798 TAILQ_FOREACH(ifp2, &ifnet_head, if_link) { 799 if (strcmp(ifnet_name(ifp2), GIFNAME) != 0) 800 continue; 801 sc2 = ifnet_softc(ifp2); 802 if (sc2 == sc) 803 continue; 804 /* lock sc and sc2 in increasing order of ifnet index */ 805 GIF_ORDERED_LOCK(sc, sc2); 806 if (!sc2->gif_pdst || !sc2->gif_psrc) { 807 GIF_ORDERED_UNLOCK(sc, sc2); 808 continue; 809 } 810 if (sc2->gif_pdst->sa_family != dst->sa_family || 811 sc2->gif_pdst->sa_len != dst->sa_len || 812 sc2->gif_psrc->sa_family != src->sa_family || 813 sc2->gif_psrc->sa_len != src->sa_len) { 814 GIF_ORDERED_UNLOCK(sc, sc2); 815 continue; 816 } 817#ifndef XBONEHACK 818 /* can't configure same pair of address onto two gifs */ 819 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 820 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 821 GIF_ORDERED_UNLOCK(sc, sc2); 822 error = EADDRNOTAVAIL; 823 ifnet_head_done(); 824 goto bad; 825 } 826#endif 827 828 /* can't configure multiple multi-dest interfaces */ 829#define multidest(x) \ 830 (((struct sockaddr_in *)(void *)(x))->sin_addr.s_addr == INADDR_ANY) 831#if INET6 832#define multidest6(x) \ 833 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) \ 834 (void *)(x))->sin6_addr)) 835#endif 836 if (dst->sa_family == AF_INET && 837 multidest(dst) && multidest(sc2->gif_pdst)) { 838 GIF_ORDERED_UNLOCK(sc, sc2); 839 error = EADDRNOTAVAIL; 840 ifnet_head_done(); 841 goto bad; 842 } 843#if INET6 844 if (dst->sa_family == AF_INET6 && 845 multidest6(dst) && multidest6(sc2->gif_pdst)) { 846 GIF_ORDERED_UNLOCK(sc, sc2); 847 error = EADDRNOTAVAIL; 848 ifnet_head_done(); 849 goto bad; 850 } 851#endif 852 GIF_ORDERED_UNLOCK(sc, sc2); 853 } 854 ifnet_head_done(); 855 856 GIF_LOCK(sc); 857 if (sc->gif_psrc) 858 FREE((caddr_t)sc->gif_psrc, M_IFADDR); 859 sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, 860 M_WAITOK); 861 if (sa == NULL) { 862 GIF_UNLOCK(sc); 863 return (ENOBUFS); 864 } 865 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 866 sc->gif_psrc = sa; 867 868 if (sc->gif_pdst) 869 FREE((caddr_t)sc->gif_pdst, M_IFADDR); 870 sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, 871 M_WAITOK); 872 if (sa == NULL) { 873 GIF_UNLOCK(sc); 874 return (ENOBUFS); 875 } 876 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 877 sc->gif_pdst = sa; 878 GIF_UNLOCK(sc); 879 880 ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING | 881 IFF_UP); 882 883 error = 0; 884 break; 885 886#ifdef SIOCDIFPHYADDR 887 case SIOCDIFPHYADDR: 888 GIF_LOCK(sc); 889 if (sc->gif_psrc) { 890 FREE((caddr_t)sc->gif_psrc, M_IFADDR); 891 sc->gif_psrc = NULL; 892 } 893 if (sc->gif_pdst) { 894 FREE((caddr_t)sc->gif_pdst, M_IFADDR); 895 sc->gif_pdst = NULL; 896 } 897 GIF_UNLOCK(sc); 898 /* change the IFF_{UP, RUNNING} flag as well? */ 899 break; 900#endif 901 902 case SIOCGIFPSRCADDR: 903#if INET6 904 case SIOCGIFPSRCADDR_IN6: 905#endif /* INET6 */ 906 GIF_LOCK(sc); 907 if (sc->gif_psrc == NULL) { 908 GIF_UNLOCK(sc); 909 error = EADDRNOTAVAIL; 910 goto bad; 911 } 912 src = sc->gif_psrc; 913 switch (cmd) { 914#if INET 915 case SIOCGIFPSRCADDR: 916 dst = &ifr->ifr_addr; 917 size = sizeof (ifr->ifr_addr); 918 break; 919#endif /* INET */ 920#if INET6 921 case SIOCGIFPSRCADDR_IN6: 922 dst = (struct sockaddr *) 923 &(((struct in6_ifreq *)data)->ifr_addr); 924 size = sizeof (((struct in6_ifreq *)data)->ifr_addr); 925 break; 926#endif /* INET6 */ 927 default: 928 GIF_UNLOCK(sc); 929 error = EADDRNOTAVAIL; 930 goto bad; 931 } 932 if (src->sa_len > size) { 933 GIF_UNLOCK(sc); 934 return (EINVAL); 935 } 936 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 937 GIF_UNLOCK(sc); 938 break; 939 940 case SIOCGIFPDSTADDR: 941#if INET6 942 case SIOCGIFPDSTADDR_IN6: 943#endif /* INET6 */ 944 GIF_LOCK(sc); 945 if (sc->gif_pdst == NULL) { 946 GIF_UNLOCK(sc); 947 error = EADDRNOTAVAIL; 948 goto bad; 949 } 950 src = sc->gif_pdst; 951 switch (cmd) { 952#if INET 953 case SIOCGIFPDSTADDR: 954 dst = &ifr->ifr_addr; 955 size = sizeof (ifr->ifr_addr); 956 break; 957#endif /* INET */ 958#if INET6 959 case SIOCGIFPDSTADDR_IN6: 960 dst = (struct sockaddr *) 961 &(((struct in6_ifreq *)data)->ifr_addr); 962 size = sizeof (((struct in6_ifreq *)data)->ifr_addr); 963 break; 964#endif /* INET6 */ 965 default: 966 error = EADDRNOTAVAIL; 967 GIF_UNLOCK(sc); 968 goto bad; 969 } 970 if (src->sa_len > size) { 971 GIF_UNLOCK(sc); 972 return (EINVAL); 973 } 974 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 975 GIF_UNLOCK(sc); 976 break; 977 978 case SIOCGLIFPHYADDR: 979 GIF_LOCK(sc); 980 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 981 GIF_UNLOCK(sc); 982 error = EADDRNOTAVAIL; 983 goto bad; 984 } 985 986 /* copy src */ 987 src = sc->gif_psrc; 988 dst = (struct sockaddr *) 989 &(((struct if_laddrreq *)data)->addr); 990 size = sizeof (((struct if_laddrreq *)data)->addr); 991 if (src->sa_len > size) { 992 GIF_UNLOCK(sc); 993 return (EINVAL); 994 } 995 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 996 997 /* copy dst */ 998 src = sc->gif_pdst; 999 dst = (struct sockaddr *) 1000 &(((struct if_laddrreq *)data)->dstaddr); 1001 size = sizeof (((struct if_laddrreq *)data)->dstaddr); 1002 if (src->sa_len > size) { 1003 GIF_UNLOCK(sc); 1004 return (EINVAL); 1005 } 1006 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 1007 GIF_UNLOCK(sc); 1008 break; 1009 1010 case SIOCSIFFLAGS: 1011 /* if_ioctl() takes care of it */ 1012 break; 1013 1014 default: 1015 error = EOPNOTSUPP; 1016 break; 1017 } 1018bad: 1019 return (error); 1020} 1021 1022static void 1023gif_delete_tunnel(struct gif_softc *sc) 1024{ 1025 GIF_LOCK_ASSERT(sc); 1026 if (sc->gif_psrc) { 1027 FREE((caddr_t)sc->gif_psrc, M_IFADDR); 1028 sc->gif_psrc = NULL; 1029 } 1030 if (sc->gif_pdst) { 1031 FREE((caddr_t)sc->gif_pdst, M_IFADDR); 1032 sc->gif_pdst = NULL; 1033 } 1034 ROUTE_RELEASE(&sc->gif_ro); 1035 /* change the IFF_UP flag as well? */ 1036} 1037