1/* 2 * Copyright (c) 2000-2008 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 86#include <netinet/in.h> 87#include <netinet/in_systm.h> 88#include <netinet/ip.h> 89#if INET 90#include <netinet/in_var.h> 91#include <netinet/in_gif.h> 92#include <netinet/ip_var.h> 93#endif /* INET */ 94 95#if INET6 96#include <netinet6/in6_var.h> 97#include <netinet/ip6.h> 98#include <netinet6/ip6_var.h> 99#include <netinet6/in6_gif.h> 100#include <netinet6/ip6protosw.h> 101#endif /* INET6 */ 102 103#include <netinet/ip_encap.h> 104#include <net/dlil.h> 105#include <net/if_gif.h> 106 107#include <net/net_osdep.h> 108 109#if CONFIG_MACF_NET 110#include <security/mac_framework.h> 111#endif 112 113#define GIFNAME "gif" 114#define GIFDEV "if_gif" 115#define GIF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */ 116 117#ifndef __APPLE__ 118static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 119#endif 120 121TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs); 122 123#ifdef __APPLE__ 124void gifattach(void); 125static int gif_encapcheck(const struct mbuf*, int, int, void*); 126static errno_t gif_output(ifnet_t ifp, mbuf_t m); 127static errno_t gif_input(ifnet_t ifp, protocol_family_t protocol_family, 128 mbuf_t m, char *frame_header); 129static errno_t gif_ioctl(ifnet_t ifp, u_long cmd, void *data); 130 131int ngif = 0; /* number of interfaces */ 132#endif 133 134#if INET 135struct protosw in_gif_protosw = 136{ SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, 137 in_gif_input, 0, 0, 0, 138 0, 139 0, 0, 0, 0, 140 0, 141 &rip_usrreqs, 142 0, rip_unlock, 0, {0, 0}, 0, {0} 143}; 144#endif 145#if INET6 146struct ip6protosw in6_gif_protosw = 147{ SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, 148 in6_gif_input, 0, 0, 0, 149 0, 150 0, 0, 0, 0, 151 0, 152 &rip6_usrreqs, 153 0, rip_unlock, 0, {0, 0}, 0, {0} 154 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 *); 162 163#ifdef __APPLE__ 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 gif_demux( 176 ifnet_t ifp, 177 __unused mbuf_t m, 178 __unused char *frame_header, 179 protocol_family_t *protocol_family) 180{ 181 /* Only one protocol may be attached to a gif interface. */ 182 *protocol_family = ((struct gif_softc*)ifnet_softc(ifp))->gif_proto; 183 184 return 0; 185} 186 187static errno_t 188gif_add_proto( 189 ifnet_t ifp, 190 protocol_family_t protocol_family, 191 __unused const struct ifnet_demux_desc *demux_array, 192 __unused u_int32_t demux_count) 193{ 194 /* Only one protocol may be attached at a time */ 195 struct gif_softc* gif = ifnet_softc(ifp); 196 197 if (gif->gif_proto != 0) 198 printf("gif_add_proto: request add_proto for gif%d\n", ifnet_unit(ifp)); 199 200 gif->gif_proto = protocol_family; 201 202 return 0; 203} 204 205static errno_t 206gif_del_proto( 207 ifnet_t ifp, 208 protocol_family_t protocol_family) 209{ 210 if (((struct gif_softc*)ifnet_softc(ifp))->gif_proto == protocol_family) 211 ((struct gif_softc*)ifnet_softc(ifp))->gif_proto = 0; 212 213 return 0; 214} 215 216/* Glue code to attach inet to a gif interface through DLIL */ 217static errno_t 218gif_attach_proto_family( 219 ifnet_t ifp, 220 protocol_family_t protocol_family) 221{ 222 struct ifnet_attach_proto_param reg; 223 errno_t stat; 224 225 bzero(®, sizeof(reg)); 226 reg.input = gif_input; 227 228 stat = ifnet_attach_protocol(ifp, protocol_family, ®); 229 if (stat && stat != EEXIST) { 230 printf("gif_attach_proto_family can't attach interface fam=%d\n", 231 protocol_family); 232 } 233 234 return stat; 235} 236 237#endif 238 239/* Function to setup the first gif interface */ 240__private_extern__ void 241gifattach(void) 242{ 243 errno_t result; 244 struct ifnet_clone_params ifnet_clone_params; 245 struct if_clone *ifc = NULL; 246 247 /* Init the list of interfaces */ 248 TAILQ_INIT(&gifs); 249 250 /* Register protocol registration functions */ 251 result = proto_register_plumber(PF_INET, APPLE_IF_FAM_GIF, 252 gif_attach_proto_family, NULL); 253 if (result != 0) 254 printf("proto_register_plumber failed for AF_INET error=%d\n", result); 255 256 result = proto_register_plumber(PF_INET6, APPLE_IF_FAM_GIF, 257 gif_attach_proto_family, NULL); 258 if (result != 0) 259 printf("proto_register_plumber failed for AF_INET6 error=%d\n", result); 260 261 ifnet_clone_params.ifc_name = "gif"; 262 ifnet_clone_params.ifc_create = gif_clone_create; 263 ifnet_clone_params.ifc_destroy = gif_clone_destroy; 264 265 result = ifnet_clone_attach(&ifnet_clone_params, &gif_cloner); 266 if (result != 0) 267 printf("gifattach: ifnet_clone_attach failed %d\n", result); 268 269 /* Create first device */ 270 ifc = if_clone_lookup("gif", NULL); 271 gif_clone_create(ifc, 0, NULL); 272} 273 274static errno_t 275gif_set_bpf_tap( 276 ifnet_t ifp, 277 bpf_tap_mode mode, 278 bpf_packet_func callback) 279{ 280 struct gif_softc *sc = ifnet_softc(ifp); 281 282 sc->tap_mode = mode; 283 sc->tap_callback = callback; 284 285 return 0; 286} 287 288 289static int 290gif_clone_create(struct if_clone *ifc, uint32_t unit, __unused void *params) 291{ 292 struct gif_softc *sc = NULL; 293 struct ifnet_init_params gif_init; 294 errno_t result = 0; 295 296 /* Can't create more than GIF_MAXUNIT */ 297 if (ngif >= GIF_MAXUNIT) 298 return (ENXIO); 299 300 sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK); 301 if (sc == NULL) { 302 log(LOG_ERR, "gif_clone_create: failed to allocate gif%d\n", unit); 303 return ENOBUFS; 304 } 305 bzero(sc, sizeof(struct gif_softc)); 306 307 /* use the interface name as the unique id for ifp recycle */ 308 snprintf(sc->gif_ifname, sizeof(sc->gif_ifname), "%s%d", 309 ifc->ifc_name, unit); 310 311 bzero(&gif_init, sizeof(gif_init)); 312 gif_init.uniqueid = sc->gif_ifname; 313 gif_init.uniqueid_len = strlen(sc->gif_ifname); 314 gif_init.name = GIFNAME; 315 gif_init.unit = unit; 316 gif_init.type = IFT_GIF; 317 gif_init.family = IFNET_FAMILY_GIF; 318 gif_init.output = gif_output; 319 gif_init.demux = gif_demux; 320 gif_init.add_proto = gif_add_proto; 321 gif_init.del_proto = gif_del_proto; 322 gif_init.softc = sc; 323 gif_init.ioctl = gif_ioctl; 324 gif_init.set_bpf_tap = gif_set_bpf_tap; 325 326 result = ifnet_allocate(&gif_init, &sc->gif_if); 327 if (result != 0) { 328 printf("gif_clone_create, ifnet_allocate failed - %d\n", result); 329 _FREE(sc, M_DEVBUF); 330 return ENOBUFS; 331 } 332 333 sc->encap_cookie4 = sc->encap_cookie6 = NULL; 334#if INET 335 sc->encap_cookie4 = encap_attach_func(AF_INET, -1, 336 gif_encapcheck, &in_gif_protosw, sc); 337 if (sc->encap_cookie4 == NULL) { 338 printf("%s: unable to attach encap4\n", if_name(sc->gif_if)); 339 ifnet_release(sc->gif_if); 340 FREE(sc, M_DEVBUF); 341 return ENOBUFS; 342 } 343#endif 344#if INET6 345 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, 346 gif_encapcheck, (struct protosw*)&in6_gif_protosw, sc); 347 if (sc->encap_cookie6 == NULL) { 348 if (sc->encap_cookie4) { 349 encap_detach(sc->encap_cookie4); 350 sc->encap_cookie4 = NULL; 351 } 352 printf("%s: unable to attach encap6\n", if_name(sc->gif_if)); 353 ifnet_release(sc->gif_if); 354 FREE(sc, M_DEVBUF); 355 return ENOBUFS; 356 } 357#endif 358 sc->gif_called = 0; 359 ifnet_set_mtu(sc->gif_if, GIF_MTU); 360 ifnet_set_flags(sc->gif_if, IFF_POINTOPOINT | IFF_MULTICAST, 0xffff); 361#if 0 362 /* turn off ingress filter */ 363 sc->gif_if.if_flags |= IFF_LINK2; 364#endif 365 result = ifnet_attach(sc->gif_if, NULL); 366 if (result != 0) { 367 printf("gif_clone_create - ifnet_attach failed - %d\n", result); 368 ifnet_release(sc->gif_if); 369 if (sc->encap_cookie4) { 370 encap_detach(sc->encap_cookie4); 371 sc->encap_cookie4 = NULL; 372 } 373 if (sc->encap_cookie6) { 374 encap_detach(sc->encap_cookie6); 375 sc->encap_cookie6 = NULL; 376 } 377 FREE(sc, M_DEVBUF); 378 return result; 379 } 380#if CONFIG_MACF_NET 381 mac_ifnet_label_init(&sc->gif_if); 382#endif 383 bpfattach(sc->gif_if, DLT_NULL, sizeof(u_int)); 384 TAILQ_INSERT_TAIL(&gifs, sc, gif_link); 385 ngif++; 386 return 0; 387} 388 389static int 390gif_clone_destroy(struct ifnet *ifp) 391{ 392#if defined(INET) || defined(INET6) 393 int err = 0; 394#endif 395 struct gif_softc *sc = ifp->if_softc; 396 397 TAILQ_REMOVE(&gifs, sc, gif_link); 398 399 gif_delete_tunnel(sc); 400#ifdef INET6 401 if (sc->encap_cookie6 != NULL) { 402 err = encap_detach(sc->encap_cookie6); 403 KASSERT(err == 0, ("gif_clone_destroy: Unexpected error detaching encap_cookie6")); 404 } 405#endif 406#ifdef INET 407 if (sc->encap_cookie4 != NULL) { 408 err = encap_detach(sc->encap_cookie4); 409 KASSERT(err == 0, ("gif_clone_destroy: Unexpected error detaching encap_cookie4")); 410 } 411#endif 412 err = ifnet_set_flags(ifp, 0, IFF_UP); 413 if (err != 0) { 414 printf("gif_clone_destroy: ifnet_set_flags failed %d\n", err); 415 } 416 417 err = ifnet_detach(ifp); 418 if (err != 0) 419 panic("gif_clone_destroy: ifnet_detach(%p) failed %d\n", ifp, err); 420 FREE(sc, M_DEVBUF); 421 ngif--; 422 return 0; 423} 424 425static int 426gif_encapcheck( 427 const struct mbuf *m, 428 int off, 429 int proto, 430 void *arg) 431{ 432 struct ip ip; 433 struct gif_softc *sc; 434 435 sc = (struct gif_softc *)arg; 436 if (sc == NULL) 437 return 0; 438 439 if ((ifnet_flags(sc->gif_if) & IFF_UP) == 0) 440 return 0; 441 442 /* no physical address */ 443 if (!sc->gif_psrc || !sc->gif_pdst) 444 return 0; 445 446 switch (proto) { 447#if INET 448 case IPPROTO_IPV4: 449 break; 450#endif 451#if INET6 452 case IPPROTO_IPV6: 453 break; 454#endif 455 default: 456 return 0; 457 } 458 459 mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof(ip), &ip); 460 461 switch (ip.ip_v) { 462#if INET 463 case 4: 464 if (sc->gif_psrc->sa_family != AF_INET || 465 sc->gif_pdst->sa_family != AF_INET) 466 return 0; 467 return gif_encapcheck4(m, off, proto, arg); 468#endif 469#if INET6 470 case 6: 471 if (sc->gif_psrc->sa_family != AF_INET6 || 472 sc->gif_pdst->sa_family != AF_INET6) 473 return 0; 474 return gif_encapcheck6(m, off, proto, arg); 475#endif 476 default: 477 return 0; 478 } 479} 480 481static errno_t 482gif_output( 483 ifnet_t ifp, 484 mbuf_t m) 485{ 486 struct gif_softc *sc = ifnet_softc(ifp); 487 int error = 0; 488 489 /* 490 max_gif_nesting check used to live here. It doesn't anymore 491 because there is no guaruntee that we won't be called 492 concurrently from more than one thread. 493 */ 494 495 m->m_flags &= ~(M_BCAST|M_MCAST); 496 if (!(ifnet_flags(ifp) & IFF_UP) || 497 sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 498 ifnet_touch_lastchange(ifp); 499 m_freem(m); /* free it here not in dlil_output */ 500 error = ENETDOWN; 501 goto end; 502 } 503 504 bpf_tap_out(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto)); 505 506 /* inner AF-specific encapsulation */ 507 508 /* XXX should we check if our outer source is legal? */ 509 510 /* dispatch to output logic based on outer AF */ 511 switch (sc->gif_psrc->sa_family) { 512#if INET 513 case AF_INET: 514 error = in_gif_output(ifp, sc->gif_proto, m, NULL); 515 break; 516#endif 517#if INET6 518 case AF_INET6: 519 error = in6_gif_output(ifp, sc->gif_proto, m, NULL); 520 break; 521#endif 522 default: 523 error = ENETDOWN; 524 goto end; 525 } 526 527 end: 528 if (error) { 529 /* the mbuf was freed either by in_gif_output or in here */ 530 ifnet_stat_increment_out(ifp, 0, 0, 1); 531 } 532 else { 533 ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0); 534 } 535 if (error == 0) 536 error = EJUSTRETURN; /* if no error, packet got sent already */ 537 return error; 538} 539 540/* 541 * gif_input is the input handler for IP and IPv6 attached to gif 542 */ 543static errno_t 544gif_input( 545 ifnet_t ifp, 546 protocol_family_t protocol_family, 547 mbuf_t m, 548 __unused char *frame_header) 549{ 550 struct gif_softc *sc = ifnet_softc(ifp); 551 552 bpf_tap_in(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto)); 553 554 /* 555 * Put the packet to the network layer input queue according to the 556 * specified address family. 557 * Note: older versions of gif_input directly called network layer 558 * input functions, e.g. ip6_input, here. We changed the policy to 559 * prevent too many recursive calls of such input functions, which 560 * might cause kernel panic. But the change may introduce another 561 * problem; if the input queue is full, packets are discarded. 562 * We believed it rarely occurs and changed the policy. If we find 563 * it occurs more times than we thought, we may change the policy 564 * again. 565 */ 566 if (proto_input(protocol_family, m) != 0) { 567 ifnet_stat_increment_in(ifp, 0, 0, 1); 568 m_freem(m); 569 } else 570 ifnet_stat_increment_in(ifp, 1, m->m_pkthdr.len, 0); 571 572 return (0); 573} 574 575/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 576static errno_t 577gif_ioctl( 578 ifnet_t ifp, 579 u_long cmd, 580 void *data) 581{ 582 struct gif_softc *sc = ifnet_softc(ifp); 583 struct ifreq *ifr = (struct ifreq*)data; 584 int error = 0, size; 585 struct sockaddr *dst = NULL, *src = NULL; 586 struct sockaddr *sa; 587 struct ifnet *ifp2; 588 struct gif_softc *sc2; 589 590 switch (cmd) { 591 case SIOCSIFADDR: 592 break; 593 594 case SIOCSIFDSTADDR: 595 break; 596 597 case SIOCADDMULTI: 598 case SIOCDELMULTI: 599 break; 600 601#ifdef SIOCSIFMTU /* xxx */ 602 case SIOCGIFMTU: 603 break; 604 605 case SIOCSIFMTU: 606 { 607 u_int32_t mtu; 608 mtu = ifr->ifr_mtu; 609 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { 610 return (EINVAL); 611 } 612 ifnet_set_mtu(ifp, mtu); 613 } 614 break; 615#endif /* SIOCSIFMTU */ 616 617 case SIOCSIFPHYADDR: 618#if INET6 619 case SIOCSIFPHYADDR_IN6_32: 620 case SIOCSIFPHYADDR_IN6_64: 621#endif /* INET6 */ 622 case SIOCSLIFPHYADDR: 623 switch (cmd) { 624#if INET 625 case SIOCSIFPHYADDR: 626 src = (struct sockaddr *) 627 &(((struct in_aliasreq *)data)->ifra_addr); 628 dst = (struct sockaddr *) 629 &(((struct in_aliasreq *)data)->ifra_dstaddr); 630 break; 631#endif 632#if INET6 633 case SIOCSIFPHYADDR_IN6_32: { 634 struct in6_aliasreq_32 *ifra_32 = 635 (struct in6_aliasreq_32 *)data; 636 637 src = (struct sockaddr *)&ifra_32->ifra_addr; 638 dst = (struct sockaddr *)&ifra_32->ifra_dstaddr; 639 break; 640 } 641 642 case SIOCSIFPHYADDR_IN6_64: { 643 struct in6_aliasreq_64 *ifra_64 = 644 (struct in6_aliasreq_64 *)data; 645 646 src = (struct sockaddr *)&ifra_64->ifra_addr; 647 dst = (struct sockaddr *)&ifra_64->ifra_dstaddr; 648 break; 649 } 650#endif 651 case SIOCSLIFPHYADDR: 652 src = (struct sockaddr *) 653 &(((struct if_laddrreq *)data)->addr); 654 dst = (struct sockaddr *) 655 &(((struct if_laddrreq *)data)->dstaddr); 656 } 657 658 /* sa_family must be equal */ 659 if (src->sa_family != dst->sa_family) 660 return EINVAL; 661 662 /* validate sa_len */ 663 switch (src->sa_family) { 664#if INET 665 case AF_INET: 666 if (src->sa_len != sizeof(struct sockaddr_in)) 667 return EINVAL; 668 break; 669#endif 670#if INET6 671 case AF_INET6: 672 if (src->sa_len != sizeof(struct sockaddr_in6)) 673 return EINVAL; 674 break; 675#endif 676 default: 677 return EAFNOSUPPORT; 678 } 679 switch (dst->sa_family) { 680#if INET 681 case AF_INET: 682 if (dst->sa_len != sizeof(struct sockaddr_in)) 683 return EINVAL; 684 break; 685#endif 686#if INET6 687 case AF_INET6: 688 if (dst->sa_len != sizeof(struct sockaddr_in6)) 689 return EINVAL; 690 break; 691#endif 692 default: 693 return EAFNOSUPPORT; 694 } 695 696 /* check sa_family looks sane for the cmd */ 697 switch (cmd) { 698 case SIOCSIFPHYADDR: 699 if (src->sa_family == AF_INET) 700 break; 701 return EAFNOSUPPORT; 702#if INET6 703 case SIOCSIFPHYADDR_IN6_32: 704 case SIOCSIFPHYADDR_IN6_64: 705 if (src->sa_family == AF_INET6) 706 break; 707 return EAFNOSUPPORT; 708#endif /* INET6 */ 709 case SIOCSLIFPHYADDR: 710 /* checks done in the above */ 711 break; 712 } 713 714 ifnet_head_lock_shared(); 715 TAILQ_FOREACH(ifp2, &ifnet_head, if_link) { 716 if (strcmp(ifnet_name(ifp2), GIFNAME) != 0) 717 continue; 718 sc2 = ifnet_softc(ifp2); 719 if (sc2 == sc) 720 continue; 721 if (!sc2->gif_pdst || !sc2->gif_psrc) 722 continue; 723 if (sc2->gif_pdst->sa_family != dst->sa_family || 724 sc2->gif_pdst->sa_len != dst->sa_len || 725 sc2->gif_psrc->sa_family != src->sa_family || 726 sc2->gif_psrc->sa_len != src->sa_len) 727 continue; 728#ifndef XBONEHACK 729 /* can't configure same pair of address onto two gifs */ 730 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 731 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 732 error = EADDRNOTAVAIL; 733 ifnet_head_done(); 734 goto bad; 735 } 736#endif 737 738 /* can't configure multiple multi-dest interfaces */ 739#define multidest(x) \ 740 (((struct sockaddr_in *)(void *)(x))->sin_addr.s_addr == INADDR_ANY) 741#if INET6 742#define multidest6(x) \ 743 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(void *)(x))->sin6_addr)) 744#endif 745 if (dst->sa_family == AF_INET && 746 multidest(dst) && multidest(sc2->gif_pdst)) { 747 error = EADDRNOTAVAIL; 748 ifnet_head_done(); 749 goto bad; 750 } 751#if INET6 752 if (dst->sa_family == AF_INET6 && 753 multidest6(dst) && multidest6(sc2->gif_pdst)) { 754 error = EADDRNOTAVAIL; 755 ifnet_head_done(); 756 goto bad; 757 } 758#endif 759 } 760 ifnet_head_done(); 761 762 if (sc->gif_psrc) 763 FREE((caddr_t)sc->gif_psrc, M_IFADDR); 764 sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, M_WAITOK); 765 if (sa == NULL) 766 return ENOBUFS; 767 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 768 sc->gif_psrc = sa; 769 770 if (sc->gif_pdst) 771 FREE((caddr_t)sc->gif_pdst, M_IFADDR); 772 sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, M_WAITOK); 773 if (sa == NULL) 774 return ENOBUFS; 775 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 776 sc->gif_pdst = sa; 777 778 ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING | IFF_UP); 779 780 error = 0; 781 break; 782 783#ifdef SIOCDIFPHYADDR 784 case SIOCDIFPHYADDR: 785 if (sc->gif_psrc) { 786 FREE((caddr_t)sc->gif_psrc, M_IFADDR); 787 sc->gif_psrc = NULL; 788 } 789 if (sc->gif_pdst) { 790 FREE((caddr_t)sc->gif_pdst, M_IFADDR); 791 sc->gif_pdst = NULL; 792 } 793 /* change the IFF_{UP, RUNNING} flag as well? */ 794 break; 795#endif 796 797 case SIOCGIFPSRCADDR: 798#if INET6 799 case SIOCGIFPSRCADDR_IN6: 800#endif /* INET6 */ 801 if (sc->gif_psrc == NULL) { 802 error = EADDRNOTAVAIL; 803 goto bad; 804 } 805 src = sc->gif_psrc; 806 switch (cmd) { 807#if INET 808 case SIOCGIFPSRCADDR: 809 dst = &ifr->ifr_addr; 810 size = sizeof(ifr->ifr_addr); 811 break; 812#endif /* INET */ 813#if INET6 814 case SIOCGIFPSRCADDR_IN6: 815 dst = (struct sockaddr *) 816 &(((struct in6_ifreq *)data)->ifr_addr); 817 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 818 break; 819#endif /* INET6 */ 820 default: 821 error = EADDRNOTAVAIL; 822 goto bad; 823 } 824 if (src->sa_len > size) 825 return EINVAL; 826 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 827 break; 828 829 case SIOCGIFPDSTADDR: 830#if INET6 831 case SIOCGIFPDSTADDR_IN6: 832#endif /* INET6 */ 833 if (sc->gif_pdst == NULL) { 834 error = EADDRNOTAVAIL; 835 goto bad; 836 } 837 src = sc->gif_pdst; 838 switch (cmd) { 839#if INET 840 case SIOCGIFPDSTADDR: 841 dst = &ifr->ifr_addr; 842 size = sizeof(ifr->ifr_addr); 843 break; 844#endif /* INET */ 845#if INET6 846 case SIOCGIFPDSTADDR_IN6: 847 dst = (struct sockaddr *) 848 &(((struct in6_ifreq *)data)->ifr_addr); 849 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 850 break; 851#endif /* INET6 */ 852 default: 853 error = EADDRNOTAVAIL; 854 goto bad; 855 } 856 if (src->sa_len > size) 857 return EINVAL; 858 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 859 break; 860 861 case SIOCGLIFPHYADDR: 862 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 863 error = EADDRNOTAVAIL; 864 goto bad; 865 } 866 867 /* copy src */ 868 src = sc->gif_psrc; 869 dst = (struct sockaddr *) 870 &(((struct if_laddrreq *)data)->addr); 871 size = sizeof(((struct if_laddrreq *)data)->addr); 872 if (src->sa_len > size) 873 return EINVAL; 874 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 875 876 /* copy dst */ 877 src = sc->gif_pdst; 878 dst = (struct sockaddr *) 879 &(((struct if_laddrreq *)data)->dstaddr); 880 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 881 if (src->sa_len > size) 882 return EINVAL; 883 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 884 break; 885 886 case SIOCSIFFLAGS: 887 /* if_ioctl() takes care of it */ 888 break; 889 890 default: 891 error = EOPNOTSUPP; 892 break; 893 } 894 bad: 895 return error; 896} 897 898/* This function is not used in our stack */ 899void 900gif_delete_tunnel(sc) 901 struct gif_softc *sc; 902{ 903 /* XXX: NetBSD protects this function with splsoftnet() */ 904 905 if (sc->gif_psrc) { 906 FREE((caddr_t)sc->gif_psrc, M_IFADDR); 907 sc->gif_psrc = NULL; 908 } 909 if (sc->gif_pdst) { 910 FREE((caddr_t)sc->gif_pdst, M_IFADDR); 911 sc->gif_pdst = NULL; 912 } 913 /* change the IFF_UP flag as well? */ 914} 915