if_gif.c revision 105293
1178476Sjb/* $FreeBSD: head/sys/net/if_gif.c 105293 2002-10-16 19:49:37Z ume $ */ 2178476Sjb/* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ */ 3178476Sjb 4178476Sjb/* 5178476Sjb * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6178476Sjb * All rights reserved. 7178476Sjb * 8178476Sjb * Redistribution and use in source and binary forms, with or without 9178476Sjb * modification, are permitted provided that the following conditions 10178476Sjb * are met: 11178476Sjb * 1. Redistributions of source code must retain the above copyright 12178476Sjb * notice, this list of conditions and the following disclaimer. 13178476Sjb * 2. Redistributions in binary form must reproduce the above copyright 14178476Sjb * notice, this list of conditions and the following disclaimer in the 15178476Sjb * documentation and/or other materials provided with the distribution. 16178476Sjb * 3. Neither the name of the project nor the names of its contributors 17178476Sjb * may be used to endorse or promote products derived from this software 18178476Sjb * without specific prior written permission. 19178476Sjb * 20178476Sjb * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21178476Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22178476Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23178476Sjb * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24178476Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25178476Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26178476Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27178476Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28178476Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29178476Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30178476Sjb * SUCH DAMAGE. 31178476Sjb */ 32178476Sjb 33178476Sjb#include "opt_inet.h" 34178476Sjb#include "opt_inet6.h" 35178476Sjb#include "opt_mac.h" 36178476Sjb 37178476Sjb#include <sys/param.h> 38178476Sjb#include <sys/systm.h> 39178476Sjb#include <sys/kernel.h> 40178476Sjb#include <sys/mac.h> 41178476Sjb#include <sys/malloc.h> 42178476Sjb#include <sys/mbuf.h> 43178476Sjb#include <sys/socket.h> 44178476Sjb#include <sys/sockio.h> 45178476Sjb#include <sys/errno.h> 46178476Sjb#include <sys/time.h> 47178476Sjb#include <sys/sysctl.h> 48178476Sjb#include <sys/syslog.h> 49178476Sjb#include <sys/protosw.h> 50178476Sjb#include <sys/conf.h> 51178476Sjb#include <machine/cpu.h> 52178476Sjb 53178476Sjb#include <net/if.h> 54178476Sjb#include <net/if_types.h> 55178476Sjb#include <net/netisr.h> 56178476Sjb#include <net/route.h> 57178476Sjb#include <net/bpf.h> 58178476Sjb 59178476Sjb#include <netinet/in.h> 60178476Sjb#include <netinet/in_systm.h> 61178476Sjb#include <netinet/ip.h> 62178476Sjb#ifdef INET 63178476Sjb#include <netinet/in_var.h> 64178476Sjb#include <netinet/in_gif.h> 65178476Sjb#include <netinet/ip_var.h> 66178476Sjb#endif /* INET */ 67178476Sjb 68178476Sjb#ifdef INET6 69178476Sjb#ifndef INET 70178476Sjb#include <netinet/in.h> 71178476Sjb#endif 72178476Sjb#include <netinet6/in6_var.h> 73178476Sjb#include <netinet/ip6.h> 74178476Sjb#include <netinet6/ip6_var.h> 75178476Sjb#include <netinet6/in6_gif.h> 76178476Sjb#include <netinet6/ip6protosw.h> 77178476Sjb#endif /* INET6 */ 78178476Sjb 79178476Sjb#include <netinet/ip_encap.h> 80178476Sjb#include <net/if_gif.h> 81178476Sjb 82178476Sjb#include <net/net_osdep.h> 83178476Sjb 84178476Sjb#define GIFNAME "gif" 85178476Sjb 86178476Sjbstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 87178476Sjbstatic LIST_HEAD(, gif_softc) gif_softc_list; 88178476Sjb 89178476Sjbvoid (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 90178476Sjbvoid (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 91178476Sjbvoid (*ng_gif_attach_p)(struct ifnet *ifp); 92178476Sjbvoid (*ng_gif_detach_p)(struct ifnet *ifp); 93178476Sjb 94178476Sjbint gif_clone_create(struct if_clone *, int); 95178476Sjbvoid gif_clone_destroy(struct ifnet *); 96178476Sjb 97178476Sjbstruct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", 98178476Sjb gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT); 99178476Sjb 100178476Sjbstatic int gifmodevent(module_t, int, void *); 101178476Sjb 102178476SjbSYSCTL_DECL(_net_link); 103178476SjbSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 104178476Sjb "Generic Tunnel Interface"); 105178476Sjb#ifndef MAX_GIF_NEST 106178476Sjb/* 107178476Sjb * This macro controls the default upper limitation on nesting of gif tunnels. 108178476Sjb * Since, setting a large value to this macro with a careless configuration 109178476Sjb * may introduce system crash, we don't allow any nestings by default. 110178476Sjb * If you need to configure nested gif tunnels, you can define this macro 111178476Sjb * in your kernel configuration file. However, if you do so, please be 112178476Sjb * careful to configure the tunnels so that it won't make a loop. 113178476Sjb */ 114178476Sjb#define MAX_GIF_NEST 1 115178476Sjb#endif 116178476Sjbstatic int max_gif_nesting = MAX_GIF_NEST; 117178476SjbSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 118178476Sjb &max_gif_nesting, 0, "Max nested tunnels"); 119178476Sjb 120178476Sjb/* 121178476Sjb * By default, we disallow creation of multiple tunnels between the same 122178476Sjb * pair of addresses. Some applications require this functionality so 123178476Sjb * we allow control over this check here. 124178476Sjb */ 125178476Sjb#ifdef XBONEHACK 126178476Sjbstatic int parallel_tunnels = 1; 127178476Sjb#else 128178476Sjbstatic int parallel_tunnels = 0; 129178476Sjb#endif 130178476SjbSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 131178476Sjb ¶llel_tunnels, 0, "Allow parallel tunnels?"); 132178476Sjb 133178476Sjbint 134178476Sjbgif_clone_create(ifc, unit) 135178476Sjb struct if_clone *ifc; 136178476Sjb int unit; 137178476Sjb{ 138178476Sjb struct gif_softc *sc; 139178476Sjb 140178476Sjb sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK); 141178476Sjb bzero(sc, sizeof(struct gif_softc)); 142178476Sjb 143178476Sjb sc->gif_if.if_softc = sc; 144178476Sjb sc->gif_if.if_name = GIFNAME; 145 sc->gif_if.if_unit = unit; 146 147 gifattach0(sc); 148 149 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); 150 return (0); 151} 152 153void 154gifattach0(sc) 155 struct gif_softc *sc; 156{ 157 158 sc->encap_cookie4 = sc->encap_cookie6 = NULL; 159 160 sc->gif_if.if_addrlen = 0; 161 sc->gif_if.if_mtu = GIF_MTU; 162 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 163#if 0 164 /* turn off ingress filter */ 165 sc->gif_if.if_flags |= IFF_LINK2; 166#endif 167 sc->gif_if.if_ioctl = gif_ioctl; 168 sc->gif_if.if_output = gif_output; 169 sc->gif_if.if_type = IFT_GIF; 170 sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 171 if_attach(&sc->gif_if); 172 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 173 if (ng_gif_attach_p != NULL) 174 (*ng_gif_attach_p)(&sc->gif_if); 175} 176 177void 178gif_clone_destroy(ifp) 179 struct ifnet *ifp; 180{ 181 int err; 182 struct gif_softc *sc = ifp->if_softc; 183 184 gif_delete_tunnel(&sc->gif_if); 185 LIST_REMOVE(sc, gif_list); 186#ifdef INET6 187 if (sc->encap_cookie6 != NULL) { 188 err = encap_detach(sc->encap_cookie6); 189 KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 190 } 191#endif 192#ifdef INET 193 if (sc->encap_cookie4 != NULL) { 194 err = encap_detach(sc->encap_cookie4); 195 KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 196 } 197#endif 198 199 if (ng_gif_detach_p != NULL) 200 (*ng_gif_detach_p)(ifp); 201 bpfdetach(ifp); 202 if_detach(ifp); 203 204 free(sc, M_GIF); 205} 206 207static int 208gifmodevent(mod, type, data) 209 module_t mod; 210 int type; 211 void *data; 212{ 213 214 switch (type) { 215 case MOD_LOAD: 216 LIST_INIT(&gif_softc_list); 217 if_clone_attach(&gif_cloner); 218 219#ifdef INET6 220 ip6_gif_hlim = GIF_HLIM; 221#endif 222 223 break; 224 case MOD_UNLOAD: 225 if_clone_detach(&gif_cloner); 226 227 while (!LIST_EMPTY(&gif_softc_list)) 228 gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if); 229 230#ifdef INET6 231 ip6_gif_hlim = 0; 232#endif 233 break; 234 } 235 return 0; 236} 237 238static moduledata_t gif_mod = { 239 "if_gif", 240 gifmodevent, 241 0 242}; 243 244DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 245MODULE_VERSION(if_gif, 1); 246 247int 248gif_encapcheck(m, off, proto, arg) 249 const struct mbuf *m; 250 int off; 251 int proto; 252 void *arg; 253{ 254 struct ip ip; 255 struct gif_softc *sc; 256 257 sc = (struct gif_softc *)arg; 258 if (sc == NULL) 259 return 0; 260 261 if ((sc->gif_if.if_flags & IFF_UP) == 0) 262 return 0; 263 264 /* no physical address */ 265 if (!sc->gif_psrc || !sc->gif_pdst) 266 return 0; 267 268 switch (proto) { 269#ifdef INET 270 case IPPROTO_IPV4: 271 break; 272#endif 273#ifdef INET6 274 case IPPROTO_IPV6: 275 break; 276#endif 277 default: 278 return 0; 279 } 280 281 m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 282 283 switch (ip.ip_v) { 284#ifdef INET 285 case 4: 286 if (sc->gif_psrc->sa_family != AF_INET || 287 sc->gif_pdst->sa_family != AF_INET) 288 return 0; 289 return gif_encapcheck4(m, off, proto, arg); 290#endif 291#ifdef INET6 292 case 6: 293 if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 294 return 0; 295 if (sc->gif_psrc->sa_family != AF_INET6 || 296 sc->gif_pdst->sa_family != AF_INET6) 297 return 0; 298 return gif_encapcheck6(m, off, proto, arg); 299#endif 300 default: 301 return 0; 302 } 303} 304 305int 306gif_output(ifp, m, dst, rt) 307 struct ifnet *ifp; 308 struct mbuf *m; 309 struct sockaddr *dst; 310 struct rtentry *rt; /* added in net2 */ 311{ 312 struct gif_softc *sc = (struct gif_softc*)ifp; 313 int error = 0; 314 static int called = 0; /* XXX: MUTEX */ 315 316#ifdef MAC 317 error = mac_check_ifnet_transmit(ifp, m); 318 if (error) { 319 m_freem(m); 320 goto end; 321 } 322#endif 323 324 /* 325 * gif may cause infinite recursion calls when misconfigured. 326 * We'll prevent this by introducing upper limit. 327 * XXX: this mechanism may introduce another problem about 328 * mutual exclusion of the variable CALLED, especially if we 329 * use kernel thread. 330 */ 331 if (++called > max_gif_nesting) { 332 log(LOG_NOTICE, 333 "gif_output: recursively called too many times(%d)\n", 334 called); 335 m_freem(m); 336 error = EIO; /* is there better errno? */ 337 goto end; 338 } 339 340 m->m_flags &= ~(M_BCAST|M_MCAST); 341 if (!(ifp->if_flags & IFF_UP) || 342 sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 343 m_freem(m); 344 error = ENETDOWN; 345 goto end; 346 } 347 348 if (ifp->if_bpf) { 349 /* 350 * We need to prepend the address family as 351 * a four byte field. Cons up a dummy header 352 * to pacify bpf. This is safe because bpf 353 * will only read from the mbuf (i.e., it won't 354 * try to free it or keep a pointer a to it). 355 */ 356 struct mbuf m0; 357 u_int32_t af = dst->sa_family; 358 359 m0.m_next = m; 360 m0.m_len = 4; 361 m0.m_data = (char *)⁡ 362 363 bpf_mtap(ifp, &m0); 364 } 365 ifp->if_opackets++; 366 ifp->if_obytes += m->m_pkthdr.len; 367 368 /* inner AF-specific encapsulation */ 369 370 /* XXX should we check if our outer source is legal? */ 371 372 /* dispatch to output logic based on outer AF */ 373 switch (sc->gif_psrc->sa_family) { 374#ifdef INET 375 case AF_INET: 376 error = in_gif_output(ifp, dst->sa_family, m, rt); 377 break; 378#endif 379#ifdef INET6 380 case AF_INET6: 381 error = in6_gif_output(ifp, dst->sa_family, m, rt); 382 break; 383#endif 384 default: 385 m_freem(m); 386 error = ENETDOWN; 387 goto end; 388 } 389 390 end: 391 called = 0; /* reset recursion counter */ 392 if (error) 393 ifp->if_oerrors++; 394 return error; 395} 396 397void 398gif_input(m, af, gifp) 399 struct mbuf *m; 400 int af; 401 struct ifnet *gifp; 402{ 403 int isr; 404 struct ifqueue *ifq = 0; 405 406 if (gifp == NULL) { 407 /* just in case */ 408 m_freem(m); 409 return; 410 } 411 412 m->m_pkthdr.rcvif = gifp; 413 414#ifdef MAC 415 mac_create_mbuf_from_ifnet(gifp, m); 416#endif 417 418 if (gifp->if_bpf) { 419 /* 420 * We need to prepend the address family as 421 * a four byte field. Cons up a dummy header 422 * to pacify bpf. This is safe because bpf 423 * will only read from the mbuf (i.e., it won't 424 * try to free it or keep a pointer a to it). 425 */ 426 struct mbuf m0; 427 u_int32_t af1 = af; 428 429 m0.m_next = m; 430 m0.m_len = 4; 431 m0.m_data = (char *)&af1; 432 433 bpf_mtap(gifp, &m0); 434 } 435 436 if (ng_gif_input_p != NULL) { 437 (*ng_gif_input_p)(gifp, &m, af); 438 if (m == NULL) 439 return; 440 } 441 442 /* 443 * Put the packet to the network layer input queue according to the 444 * specified address family. 445 * Note: older versions of gif_input directly called network layer 446 * input functions, e.g. ip6_input, here. We changed the policy to 447 * prevent too many recursive calls of such input functions, which 448 * might cause kernel panic. But the change may introduce another 449 * problem; if the input queue is full, packets are discarded. 450 * The kernel stack overflow really happened, and we believed 451 * queue-full rarely occurs, so we changed the policy. 452 */ 453 switch (af) { 454#ifdef INET 455 case AF_INET: 456 ifq = &ipintrq; 457 isr = NETISR_IP; 458 break; 459#endif 460#ifdef INET6 461 case AF_INET6: 462 ifq = &ip6intrq; 463 isr = NETISR_IPV6; 464 break; 465#endif 466 default: 467 if (ng_gif_input_orphan_p != NULL) 468 (*ng_gif_input_orphan_p)(gifp, m, af); 469 else 470 m_freem(m); 471 return; 472 } 473 474 gifp->if_ipackets++; 475 gifp->if_ibytes += m->m_pkthdr.len; 476 (void) IF_HANDOFF(ifq, m, NULL); 477 /* we need schednetisr since the address family may change */ 478 schednetisr(isr); 479 480 return; 481} 482 483/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 484int 485gif_ioctl(ifp, cmd, data) 486 struct ifnet *ifp; 487 u_long cmd; 488 caddr_t data; 489{ 490 struct gif_softc *sc = (struct gif_softc*)ifp; 491 struct ifreq *ifr = (struct ifreq*)data; 492 int error = 0, size; 493 struct sockaddr *dst, *src; 494 495 switch (cmd) { 496 case SIOCSIFADDR: 497 ifp->if_flags |= IFF_UP; 498 break; 499 500 case SIOCSIFDSTADDR: 501 break; 502 503 case SIOCADDMULTI: 504 case SIOCDELMULTI: 505 break; 506 507#ifdef SIOCSIFMTU /* xxx */ 508 case SIOCGIFMTU: 509 break; 510 511 case SIOCSIFMTU: 512 { 513 u_long mtu; 514 mtu = ifr->ifr_mtu; 515 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { 516 return (EINVAL); 517 } 518 ifp->if_mtu = mtu; 519 } 520 break; 521#endif /* SIOCSIFMTU */ 522 523 case SIOCSIFPHYADDR: 524#ifdef INET6 525 case SIOCSIFPHYADDR_IN6: 526#endif /* INET6 */ 527 case SIOCSLIFPHYADDR: 528 switch (cmd) { 529#ifdef INET 530 case SIOCSIFPHYADDR: 531 src = (struct sockaddr *) 532 &(((struct in_aliasreq *)data)->ifra_addr); 533 dst = (struct sockaddr *) 534 &(((struct in_aliasreq *)data)->ifra_dstaddr); 535 break; 536#endif 537#ifdef INET6 538 case SIOCSIFPHYADDR_IN6: 539 src = (struct sockaddr *) 540 &(((struct in6_aliasreq *)data)->ifra_addr); 541 dst = (struct sockaddr *) 542 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 543 break; 544#endif 545 case SIOCSLIFPHYADDR: 546 src = (struct sockaddr *) 547 &(((struct if_laddrreq *)data)->addr); 548 dst = (struct sockaddr *) 549 &(((struct if_laddrreq *)data)->dstaddr); 550 break; 551 default: 552 return EINVAL; 553 } 554 555 /* sa_family must be equal */ 556 if (src->sa_family != dst->sa_family) 557 return EINVAL; 558 559 /* validate sa_len */ 560 switch (src->sa_family) { 561#ifdef INET 562 case AF_INET: 563 if (src->sa_len != sizeof(struct sockaddr_in)) 564 return EINVAL; 565 break; 566#endif 567#ifdef INET6 568 case AF_INET6: 569 if (src->sa_len != sizeof(struct sockaddr_in6)) 570 return EINVAL; 571 break; 572#endif 573 default: 574 return EAFNOSUPPORT; 575 } 576 switch (dst->sa_family) { 577#ifdef INET 578 case AF_INET: 579 if (dst->sa_len != sizeof(struct sockaddr_in)) 580 return EINVAL; 581 break; 582#endif 583#ifdef INET6 584 case AF_INET6: 585 if (dst->sa_len != sizeof(struct sockaddr_in6)) 586 return EINVAL; 587 break; 588#endif 589 default: 590 return EAFNOSUPPORT; 591 } 592 593 /* check sa_family looks sane for the cmd */ 594 switch (cmd) { 595 case SIOCSIFPHYADDR: 596 if (src->sa_family == AF_INET) 597 break; 598 return EAFNOSUPPORT; 599#ifdef INET6 600 case SIOCSIFPHYADDR_IN6: 601 if (src->sa_family == AF_INET6) 602 break; 603 return EAFNOSUPPORT; 604#endif /* INET6 */ 605 case SIOCSLIFPHYADDR: 606 /* checks done in the above */ 607 break; 608 } 609 610 error = gif_set_tunnel(&sc->gif_if, src, dst); 611 break; 612 613#ifdef SIOCDIFPHYADDR 614 case SIOCDIFPHYADDR: 615 gif_delete_tunnel(&sc->gif_if); 616 break; 617#endif 618 619 case SIOCGIFPSRCADDR: 620#ifdef INET6 621 case SIOCGIFPSRCADDR_IN6: 622#endif /* INET6 */ 623 if (sc->gif_psrc == NULL) { 624 error = EADDRNOTAVAIL; 625 goto bad; 626 } 627 src = sc->gif_psrc; 628 switch (cmd) { 629#ifdef INET 630 case SIOCGIFPSRCADDR: 631 dst = &ifr->ifr_addr; 632 size = sizeof(ifr->ifr_addr); 633 break; 634#endif /* INET */ 635#ifdef INET6 636 case SIOCGIFPSRCADDR_IN6: 637 dst = (struct sockaddr *) 638 &(((struct in6_ifreq *)data)->ifr_addr); 639 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 640 break; 641#endif /* INET6 */ 642 default: 643 error = EADDRNOTAVAIL; 644 goto bad; 645 } 646 if (src->sa_len > size) 647 return EINVAL; 648 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 649 break; 650 651 case SIOCGIFPDSTADDR: 652#ifdef INET6 653 case SIOCGIFPDSTADDR_IN6: 654#endif /* INET6 */ 655 if (sc->gif_pdst == NULL) { 656 error = EADDRNOTAVAIL; 657 goto bad; 658 } 659 src = sc->gif_pdst; 660 switch (cmd) { 661#ifdef INET 662 case SIOCGIFPDSTADDR: 663 dst = &ifr->ifr_addr; 664 size = sizeof(ifr->ifr_addr); 665 break; 666#endif /* INET */ 667#ifdef INET6 668 case SIOCGIFPDSTADDR_IN6: 669 dst = (struct sockaddr *) 670 &(((struct in6_ifreq *)data)->ifr_addr); 671 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 672 break; 673#endif /* INET6 */ 674 default: 675 error = EADDRNOTAVAIL; 676 goto bad; 677 } 678 if (src->sa_len > size) 679 return EINVAL; 680 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 681 break; 682 683 case SIOCGLIFPHYADDR: 684 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 685 error = EADDRNOTAVAIL; 686 goto bad; 687 } 688 689 /* copy src */ 690 src = sc->gif_psrc; 691 dst = (struct sockaddr *) 692 &(((struct if_laddrreq *)data)->addr); 693 size = sizeof(((struct if_laddrreq *)data)->addr); 694 if (src->sa_len > size) 695 return EINVAL; 696 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 697 698 /* copy dst */ 699 src = sc->gif_pdst; 700 dst = (struct sockaddr *) 701 &(((struct if_laddrreq *)data)->dstaddr); 702 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 703 if (src->sa_len > size) 704 return EINVAL; 705 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 706 break; 707 708 case SIOCSIFFLAGS: 709 /* if_ioctl() takes care of it */ 710 break; 711 712 default: 713 error = EINVAL; 714 break; 715 } 716 bad: 717 return error; 718} 719 720int 721gif_set_tunnel(ifp, src, dst) 722 struct ifnet *ifp; 723 struct sockaddr *src; 724 struct sockaddr *dst; 725{ 726 struct gif_softc *sc = (struct gif_softc *)ifp; 727 struct gif_softc *sc2; 728 struct sockaddr *osrc, *odst, *sa; 729 int s; 730 int error = 0; 731 732 s = splnet(); 733 734 LIST_FOREACH(sc2, &gif_softc_list, gif_list) { 735 if (sc2 == sc) 736 continue; 737 if (!sc2->gif_pdst || !sc2->gif_psrc) 738 continue; 739 if (sc2->gif_pdst->sa_family != dst->sa_family || 740 sc2->gif_pdst->sa_len != dst->sa_len || 741 sc2->gif_psrc->sa_family != src->sa_family || 742 sc2->gif_psrc->sa_len != src->sa_len) 743 continue; 744 745 /* 746 * Disallow parallel tunnels unless instructed 747 * otherwise. 748 */ 749 if (!parallel_tunnels && 750 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 751 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 752 error = EADDRNOTAVAIL; 753 goto bad; 754 } 755 756 /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 757 } 758 759 /* XXX we can detach from both, but be polite just in case */ 760 if (sc->gif_psrc) 761 switch (sc->gif_psrc->sa_family) { 762#ifdef INET 763 case AF_INET: 764 (void)in_gif_detach(sc); 765 break; 766#endif 767#ifdef INET6 768 case AF_INET6: 769 (void)in6_gif_detach(sc); 770 break; 771#endif 772 } 773 774 osrc = sc->gif_psrc; 775 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 776 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 777 sc->gif_psrc = sa; 778 779 odst = sc->gif_pdst; 780 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 781 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 782 sc->gif_pdst = sa; 783 784 switch (sc->gif_psrc->sa_family) { 785#ifdef INET 786 case AF_INET: 787 error = in_gif_attach(sc); 788 break; 789#endif 790#ifdef INET6 791 case AF_INET6: 792 error = in6_gif_attach(sc); 793 break; 794#endif 795 } 796 if (error) { 797 /* rollback */ 798 free((caddr_t)sc->gif_psrc, M_IFADDR); 799 free((caddr_t)sc->gif_pdst, M_IFADDR); 800 sc->gif_psrc = osrc; 801 sc->gif_pdst = odst; 802 goto bad; 803 } 804 805 if (osrc) 806 free((caddr_t)osrc, M_IFADDR); 807 if (odst) 808 free((caddr_t)odst, M_IFADDR); 809 810 if (sc->gif_psrc && sc->gif_pdst) 811 ifp->if_flags |= IFF_RUNNING; 812 else 813 ifp->if_flags &= ~IFF_RUNNING; 814 splx(s); 815 816 return 0; 817 818 bad: 819 if (sc->gif_psrc && sc->gif_pdst) 820 ifp->if_flags |= IFF_RUNNING; 821 else 822 ifp->if_flags &= ~IFF_RUNNING; 823 splx(s); 824 825 return error; 826} 827 828void 829gif_delete_tunnel(ifp) 830 struct ifnet *ifp; 831{ 832 struct gif_softc *sc = (struct gif_softc *)ifp; 833 int s; 834 835 s = splnet(); 836 837 if (sc->gif_psrc) { 838 free((caddr_t)sc->gif_psrc, M_IFADDR); 839 sc->gif_psrc = NULL; 840 } 841 if (sc->gif_pdst) { 842 free((caddr_t)sc->gif_pdst, M_IFADDR); 843 sc->gif_pdst = NULL; 844 } 845 /* it is safe to detach from both */ 846#ifdef INET 847 (void)in_gif_detach(sc); 848#endif 849#ifdef INET6 850 (void)in6_gif_detach(sc); 851#endif 852 853 if (sc->gif_psrc && sc->gif_pdst) 854 ifp->if_flags |= IFF_RUNNING; 855 else 856 ifp->if_flags &= ~IFF_RUNNING; 857 splx(s); 858} 859