if_gif.c revision 102968
1/* $FreeBSD: head/sys/net/if_gif.c 102968 2002-09-05 15:35:38Z sobomax $ */ 2/* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ */ 3 4/* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include "opt_inet.h" 34#include "opt_inet6.h" 35#include "opt_mac.h" 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/kernel.h> 40#include <sys/mac.h> 41#include <sys/malloc.h> 42#include <sys/mbuf.h> 43#include <sys/socket.h> 44#include <sys/sockio.h> 45#include <sys/errno.h> 46#include <sys/time.h> 47#include <sys/sysctl.h> 48#include <sys/syslog.h> 49#include <sys/protosw.h> 50#include <sys/conf.h> 51#include <machine/cpu.h> 52 53#include <net/if.h> 54#include <net/if_types.h> 55#include <net/netisr.h> 56#include <net/route.h> 57#include <net/bpf.h> 58 59#include <netinet/in.h> 60#include <netinet/in_systm.h> 61#include <netinet/ip.h> 62#ifdef INET 63#include <netinet/in_var.h> 64#include <netinet/in_gif.h> 65#include <netinet/ip_var.h> 66#endif /* INET */ 67 68#ifdef INET6 69#ifndef INET 70#include <netinet/in.h> 71#endif 72#include <netinet6/in6_var.h> 73#include <netinet/ip6.h> 74#include <netinet6/ip6_var.h> 75#include <netinet6/in6_gif.h> 76#include <netinet6/ip6protosw.h> 77#endif /* INET6 */ 78 79#include <netinet/ip_encap.h> 80#include <net/if_gif.h> 81 82#include <net/net_osdep.h> 83 84#define GIFNAME "gif" 85 86static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 87static LIST_HEAD(, gif_softc) gif_softc_list; 88 89void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 90void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 91void (*ng_gif_attach_p)(struct ifnet *ifp); 92void (*ng_gif_detach_p)(struct ifnet *ifp); 93 94int gif_clone_create(struct if_clone *, int); 95void gif_clone_destroy(struct ifnet *); 96 97struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", 98 gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT); 99 100static int gifmodevent(module_t, int, void *); 101void gif_delete_tunnel(struct gif_softc *); 102static int gif_encapcheck(const struct mbuf *, int, int, void *); 103 104#ifdef INET 105extern struct domain inetdomain; 106struct protosw in_gif_protosw = 107{ SOCK_RAW, &inetdomain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, 108 in_gif_input, (pr_output_t*)rip_output, 0, rip_ctloutput, 109 0, 110 0, 0, 0, 0, 111 &rip_usrreqs 112}; 113#endif 114#ifdef INET6 115extern struct domain inet6domain; 116struct ip6protosw in6_gif_protosw = 117{ SOCK_RAW, &inet6domain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, 118 in6_gif_input, rip6_output, 0, rip6_ctloutput, 119 0, 120 0, 0, 0, 0, 121 &rip6_usrreqs 122}; 123#endif 124 125SYSCTL_DECL(_net_link); 126SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 127 "Generic Tunnel Interface"); 128#ifndef MAX_GIF_NEST 129/* 130 * This macro controls the default upper limitation on nesting of gif tunnels. 131 * Since, setting a large value to this macro with a careless configuration 132 * may introduce system crash, we don't allow any nestings by default. 133 * If you need to configure nested gif tunnels, you can define this macro 134 * in your kernel configuration file. However, if you do so, please be 135 * careful to configure the tunnels so that it won't make a loop. 136 */ 137#define MAX_GIF_NEST 1 138#endif 139static int max_gif_nesting = MAX_GIF_NEST; 140SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 141 &max_gif_nesting, 0, "Max nested tunnels"); 142 143/* 144 * By default, we disallow creation of multiple tunnels between the same 145 * pair of addresses. Some applications require this functionality so 146 * we allow control over this check here. 147 */ 148#ifdef XBONEHACK 149static int parallel_tunnels = 1; 150#else 151static int parallel_tunnels = 0; 152#endif 153SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 154 ¶llel_tunnels, 0, "Allow parallel tunnels?"); 155 156int 157gif_clone_create(ifc, unit) 158 struct if_clone *ifc; 159 int unit; 160{ 161 struct gif_softc *sc; 162 163 sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK); 164 bzero(sc, sizeof(struct gif_softc)); 165 166 sc->gif_if.if_softc = sc; 167 sc->gif_if.if_name = GIFNAME; 168 sc->gif_if.if_unit = unit; 169 170 sc->encap_cookie4 = sc->encap_cookie6 = NULL; 171#ifdef INET 172 sc->encap_cookie4 = encap_attach_func(AF_INET, -1, 173 gif_encapcheck, (struct protosw*)&in_gif_protosw, sc); 174 if (sc->encap_cookie4 == NULL) { 175 printf("%s: unable to attach encap4\n", if_name(&sc->gif_if)); 176 free(sc, M_GIF); 177 return (EIO); /* XXX */ 178 } 179#endif 180#ifdef INET6 181 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, 182 gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc); 183 if (sc->encap_cookie6 == NULL) { 184 if (sc->encap_cookie4) { 185 encap_detach(sc->encap_cookie4); 186 sc->encap_cookie4 = NULL; 187 } 188 printf("%s: unable to attach encap6\n", if_name(&sc->gif_if)); 189 free(sc, M_GIF); 190 return (EIO); /* XXX */ 191 } 192#endif 193 194 sc->gif_if.if_mtu = GIF_MTU; 195 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 196#if 0 197 /* turn off ingress filter */ 198 sc->gif_if.if_flags |= IFF_LINK2; 199#endif 200 sc->gif_if.if_ioctl = gif_ioctl; 201 sc->gif_if.if_output = gif_output; 202 sc->gif_if.if_type = IFT_GIF; 203 sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 204 sc->called = 0; 205 if_attach(&sc->gif_if); 206 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 207 if (ng_gif_attach_p != NULL) 208 (*ng_gif_attach_p)(&sc->gif_if); 209 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_link); 210 return (0); 211} 212 213void 214gif_clone_destroy(ifp) 215 struct ifnet *ifp; 216{ 217 int err; 218 struct gif_softc *sc = ifp->if_softc; 219 220 gif_delete_tunnel(sc); 221 LIST_REMOVE(sc, gif_link); 222 if (sc->encap_cookie4 != NULL) { 223 err = encap_detach(sc->encap_cookie4); 224 KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 225 } 226 if (sc->encap_cookie6 != NULL) { 227 err = encap_detach(sc->encap_cookie6); 228 KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 229 } 230 231 if (ng_gif_detach_p != NULL) 232 (*ng_gif_detach_p)(ifp); 233 bpfdetach(ifp); 234 if_detach(ifp); 235 236 free(sc, M_GIF); 237} 238 239static int 240gifmodevent(mod, type, data) 241 module_t mod; 242 int type; 243 void *data; 244{ 245 246 switch (type) { 247 case MOD_LOAD: 248 LIST_INIT(&gif_softc_list); 249 if_clone_attach(&gif_cloner); 250 251#ifdef INET6 252 ip6_gif_hlim = GIF_HLIM; 253#endif 254 255 break; 256 case MOD_UNLOAD: 257 if_clone_detach(&gif_cloner); 258 259 while (!LIST_EMPTY(&gif_softc_list)) 260 gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if); 261 262#ifdef INET6 263 ip6_gif_hlim = 0; 264#endif 265 break; 266 } 267 return 0; 268} 269 270static moduledata_t gif_mod = { 271 "if_gif", 272 gifmodevent, 273 0 274}; 275 276DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 277MODULE_VERSION(if_gif, 1); 278 279static int 280gif_encapcheck(m, off, proto, arg) 281 const struct mbuf *m; 282 int off; 283 int proto; 284 void *arg; 285{ 286 struct ip ip; 287 struct gif_softc *sc; 288 289 sc = (struct gif_softc *)arg; 290 if (sc == NULL) 291 return 0; 292 293 if ((sc->gif_if.if_flags & IFF_UP) == 0) 294 return 0; 295 296 /* no physical address */ 297 if (!sc->gif_psrc || !sc->gif_pdst) 298 return 0; 299 300 switch (proto) { 301#ifdef INET 302 case IPPROTO_IPV4: 303 break; 304#endif 305#ifdef INET6 306 case IPPROTO_IPV6: 307 break; 308#endif 309 default: 310 return 0; 311 } 312 313 m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 314 315 switch (ip.ip_v) { 316#ifdef INET 317 case 4: 318 if (sc->gif_psrc->sa_family != AF_INET || 319 sc->gif_pdst->sa_family != AF_INET) 320 return 0; 321 return gif_encapcheck4(m, off, proto, arg); 322#endif 323#ifdef INET6 324 case 6: 325 if (sc->gif_psrc->sa_family != AF_INET6 || 326 sc->gif_pdst->sa_family != AF_INET6) 327 return 0; 328 return gif_encapcheck6(m, off, proto, arg); 329#endif 330 default: 331 return 0; 332 } 333} 334 335int 336gif_output(ifp, m, dst, rt) 337 struct ifnet *ifp; 338 struct mbuf *m; 339 struct sockaddr *dst; 340 struct rtentry *rt; /* added in net2 */ 341{ 342 struct gif_softc *sc = (struct gif_softc*)ifp; 343 int error = 0; 344 345#ifdef MAC 346 error = mac_check_ifnet_transmit(ifp, m); 347 if (error) { 348 m_freem(m); 349 goto end; 350 } 351#endif 352 353 /* 354 * gif may cause infinite recursion calls when misconfigured. 355 * We'll prevent this by introducing upper limit. 356 */ 357 if (++(sc->called) > max_gif_nesting) { 358 log(LOG_NOTICE, 359 "gif_output: recursively called too many times(%d)\n", 360 sc->called); 361 m_freem(m); 362 error = EIO; /* is there better errno? */ 363 goto end; 364 } 365 366 m->m_flags &= ~(M_BCAST|M_MCAST); 367 if (!(ifp->if_flags & IFF_UP) || 368 sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 369 m_freem(m); 370 error = ENETDOWN; 371 goto end; 372 } 373 374 if (ifp->if_bpf) { 375 /* 376 * We need to prepend the address family as 377 * a four byte field. Cons up a dummy header 378 * to pacify bpf. This is safe because bpf 379 * will only read from the mbuf (i.e., it won't 380 * try to free it or keep a pointer a to it). 381 */ 382 struct mbuf m0; 383 u_int32_t af = dst->sa_family; 384 385 m0.m_next = m; 386 m0.m_len = 4; 387 m0.m_data = (char *)⁡ 388 389 bpf_mtap(ifp, &m0); 390 } 391 ifp->if_opackets++; 392 ifp->if_obytes += m->m_pkthdr.len; 393 394 /* inner AF-specific encapsulation */ 395 396 /* XXX should we check if our outer source is legal? */ 397 398 /* dispatch to output logic based on outer AF */ 399 switch (sc->gif_psrc->sa_family) { 400#ifdef INET 401 case AF_INET: 402 error = in_gif_output(ifp, dst->sa_family, m, rt); 403 break; 404#endif 405#ifdef INET6 406 case AF_INET6: 407 error = in6_gif_output(ifp, dst->sa_family, m, rt); 408 break; 409#endif 410 default: 411 m_freem(m); 412 error = ENETDOWN; 413 goto end; 414 } 415 416 end: 417 sc->called = 0; /* reset recursion counter */ 418 if (error) 419 ifp->if_oerrors++; 420 return error; 421} 422 423void 424gif_input(m, af, gifp) 425 struct mbuf *m; 426 int af; 427 struct ifnet *gifp; 428{ 429 int isr; 430 struct ifqueue *ifq = 0; 431 432 if (gifp == NULL) { 433 /* just in case */ 434 m_freem(m); 435 return; 436 } 437 438 m->m_pkthdr.rcvif = gifp; 439 440#ifdef MAC 441 mac_create_mbuf_from_ifnet(gifp, m); 442#endif 443 444 if (gifp->if_bpf) { 445 /* 446 * We need to prepend the address family as 447 * a four byte field. Cons up a dummy header 448 * to pacify bpf. This is safe because bpf 449 * will only read from the mbuf (i.e., it won't 450 * try to free it or keep a pointer a to it). 451 */ 452 struct mbuf m0; 453 u_int32_t af1 = af; 454 455 m0.m_next = m; 456 m0.m_len = 4; 457 m0.m_data = (char *)&af1; 458 459 bpf_mtap(gifp, &m0); 460 } 461 462 if (ng_gif_input_p != NULL) { 463 (*ng_gif_input_p)(gifp, &m, af); 464 if (m == NULL) 465 return; 466 } 467 468 /* 469 * Put the packet to the network layer input queue according to the 470 * specified address family. 471 * Note: older versions of gif_input directly called network layer 472 * input functions, e.g. ip6_input, here. We changed the policy to 473 * prevent too many recursive calls of such input functions, which 474 * might cause kernel panic. But the change may introduce another 475 * problem; if the input queue is full, packets are discarded. 476 * The kernel stack overflow really happened, and we believed 477 * queue-full rarely occurs, so we changed the policy. 478 */ 479 switch (af) { 480#ifdef INET 481 case AF_INET: 482 ifq = &ipintrq; 483 isr = NETISR_IP; 484 break; 485#endif 486#ifdef INET6 487 case AF_INET6: 488 ifq = &ip6intrq; 489 isr = NETISR_IPV6; 490 break; 491#endif 492 default: 493 if (ng_gif_input_orphan_p != NULL) 494 (*ng_gif_input_orphan_p)(gifp, m, af); 495 else 496 m_freem(m); 497 return; 498 } 499 500 gifp->if_ipackets++; 501 gifp->if_ibytes += m->m_pkthdr.len; 502 (void) IF_HANDOFF(ifq, m, NULL); 503 /* we need schednetisr since the address family may change */ 504 schednetisr(isr); 505 506 return; 507} 508 509/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 510int 511gif_ioctl(ifp, cmd, data) 512 struct ifnet *ifp; 513 u_long cmd; 514 caddr_t data; 515{ 516 struct gif_softc *sc = (struct gif_softc*)ifp; 517 struct ifreq *ifr = (struct ifreq*)data; 518 int error = 0, size; 519 struct sockaddr *dst, *src; 520 struct sockaddr *sa; 521 int s; 522 struct ifnet *ifp2; 523 struct gif_softc *sc2; 524 525 switch (cmd) { 526 case SIOCSIFADDR: 527 break; 528 529 case SIOCSIFDSTADDR: 530 break; 531 532 case SIOCADDMULTI: 533 case SIOCDELMULTI: 534 break; 535 536#ifdef SIOCSIFMTU /* xxx */ 537 case SIOCGIFMTU: 538 break; 539 540 case SIOCSIFMTU: 541 { 542 u_long mtu; 543 mtu = ifr->ifr_mtu; 544 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { 545 return (EINVAL); 546 } 547 ifp->if_mtu = mtu; 548 } 549 break; 550#endif /* SIOCSIFMTU */ 551 552 case SIOCSIFPHYADDR: 553#ifdef INET6 554 case SIOCSIFPHYADDR_IN6: 555#endif /* INET6 */ 556 case SIOCSLIFPHYADDR: 557 switch (cmd) { 558#ifdef INET 559 case SIOCSIFPHYADDR: 560 src = (struct sockaddr *) 561 &(((struct in_aliasreq *)data)->ifra_addr); 562 dst = (struct sockaddr *) 563 &(((struct in_aliasreq *)data)->ifra_dstaddr); 564 break; 565#endif 566#ifdef INET6 567 case SIOCSIFPHYADDR_IN6: 568 src = (struct sockaddr *) 569 &(((struct in6_aliasreq *)data)->ifra_addr); 570 dst = (struct sockaddr *) 571 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 572 break; 573#endif 574 case SIOCSLIFPHYADDR: 575 src = (struct sockaddr *) 576 &(((struct if_laddrreq *)data)->addr); 577 dst = (struct sockaddr *) 578 &(((struct if_laddrreq *)data)->dstaddr); 579 default: 580 error = EADDRNOTAVAIL; 581 goto bad; 582 } 583 584 /* sa_family must be equal */ 585 if (src->sa_family != dst->sa_family) 586 return EINVAL; 587 588 /* validate sa_len */ 589 switch (src->sa_family) { 590#ifdef INET 591 case AF_INET: 592 if (src->sa_len != sizeof(struct sockaddr_in)) 593 return EINVAL; 594 break; 595#endif 596#ifdef INET6 597 case AF_INET6: 598 if (src->sa_len != sizeof(struct sockaddr_in6)) 599 return EINVAL; 600 break; 601#endif 602 default: 603 return EAFNOSUPPORT; 604 } 605 switch (dst->sa_family) { 606#ifdef INET 607 case AF_INET: 608 if (dst->sa_len != sizeof(struct sockaddr_in)) 609 return EINVAL; 610 break; 611#endif 612#ifdef INET6 613 case AF_INET6: 614 if (dst->sa_len != sizeof(struct sockaddr_in6)) 615 return EINVAL; 616 break; 617#endif 618 default: 619 return EAFNOSUPPORT; 620 } 621 622 /* check sa_family looks sane for the cmd */ 623 switch (cmd) { 624 case SIOCSIFPHYADDR: 625 if (src->sa_family == AF_INET) 626 break; 627 return EAFNOSUPPORT; 628#ifdef INET6 629 case SIOCSIFPHYADDR_IN6: 630 if (src->sa_family == AF_INET6) 631 break; 632 return EAFNOSUPPORT; 633#endif /* INET6 */ 634 case SIOCSLIFPHYADDR: 635 /* checks done in the above */ 636 break; 637 } 638 639 TAILQ_FOREACH(ifp2, &ifnet, if_link) { 640 if (strcmp(ifp2->if_name, GIFNAME) != 0) 641 continue; 642 sc2 = ifp2->if_softc; 643 if (sc2 == sc) 644 continue; 645 if (!sc2->gif_pdst || !sc2->gif_psrc) 646 continue; 647 if (sc2->gif_pdst->sa_family != dst->sa_family || 648 sc2->gif_pdst->sa_len != dst->sa_len || 649 sc2->gif_psrc->sa_family != src->sa_family || 650 sc2->gif_psrc->sa_len != src->sa_len) 651 continue; 652 653 /* 654 * Disallow parallel tunnels unless instructed 655 * otherwise. 656 */ 657 if (!parallel_tunnels && 658 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 659 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 660 error = EADDRNOTAVAIL; 661 goto bad; 662 } 663 664 /* can't configure multiple multi-dest interfaces */ 665#define multidest(x) \ 666 (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY) 667#ifdef INET6 668#define multidest6(x) \ 669 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr)) 670#endif 671 if (dst->sa_family == AF_INET && 672 multidest(dst) && multidest(sc2->gif_pdst)) { 673 error = EADDRNOTAVAIL; 674 goto bad; 675 } 676#ifdef INET6 677 if (dst->sa_family == AF_INET6 && 678 multidest6(dst) && multidest6(sc2->gif_pdst)) { 679 error = EADDRNOTAVAIL; 680 goto bad; 681 } 682#endif 683 } 684 685 if (sc->gif_psrc) 686 free((caddr_t)sc->gif_psrc, M_IFADDR); 687 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 688 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 689 sc->gif_psrc = sa; 690 691 if (sc->gif_pdst) 692 free((caddr_t)sc->gif_pdst, M_IFADDR); 693 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 694 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 695 sc->gif_pdst = sa; 696 697 ifp->if_flags |= IFF_RUNNING; 698 s = splimp(); 699 if_up(ifp); /* mark interface UP and send up RTM_IFINFO */ 700 splx(s); 701 702 error = 0; 703 break; 704 705#ifdef SIOCDIFPHYADDR 706 case SIOCDIFPHYADDR: 707 if (sc->gif_psrc) { 708 free((caddr_t)sc->gif_psrc, M_IFADDR); 709 sc->gif_psrc = NULL; 710 } 711 if (sc->gif_pdst) { 712 free((caddr_t)sc->gif_pdst, M_IFADDR); 713 sc->gif_pdst = NULL; 714 } 715 /* change the IFF_{UP, RUNNING} flag as well? */ 716 break; 717#endif 718 719 case SIOCGIFPSRCADDR: 720#ifdef INET6 721 case SIOCGIFPSRCADDR_IN6: 722#endif /* INET6 */ 723 if (sc->gif_psrc == NULL) { 724 error = EADDRNOTAVAIL; 725 goto bad; 726 } 727 src = sc->gif_psrc; 728 switch (cmd) { 729#ifdef INET 730 case SIOCGIFPSRCADDR: 731 dst = &ifr->ifr_addr; 732 size = sizeof(ifr->ifr_addr); 733 break; 734#endif /* INET */ 735#ifdef INET6 736 case SIOCGIFPSRCADDR_IN6: 737 dst = (struct sockaddr *) 738 &(((struct in6_ifreq *)data)->ifr_addr); 739 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 740 break; 741#endif /* INET6 */ 742 default: 743 error = EADDRNOTAVAIL; 744 goto bad; 745 } 746 if (src->sa_len > size) 747 return EINVAL; 748 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 749 break; 750 751 case SIOCGIFPDSTADDR: 752#ifdef INET6 753 case SIOCGIFPDSTADDR_IN6: 754#endif /* INET6 */ 755 if (sc->gif_pdst == NULL) { 756 error = EADDRNOTAVAIL; 757 goto bad; 758 } 759 src = sc->gif_pdst; 760 switch (cmd) { 761#ifdef INET 762 case SIOCGIFPDSTADDR: 763 dst = &ifr->ifr_addr; 764 size = sizeof(ifr->ifr_addr); 765 break; 766#endif /* INET */ 767#ifdef INET6 768 case SIOCGIFPDSTADDR_IN6: 769 dst = (struct sockaddr *) 770 &(((struct in6_ifreq *)data)->ifr_addr); 771 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 772 break; 773#endif /* INET6 */ 774 default: 775 error = EADDRNOTAVAIL; 776 goto bad; 777 } 778 if (src->sa_len > size) 779 return EINVAL; 780 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 781 break; 782 783 case SIOCGLIFPHYADDR: 784 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 785 error = EADDRNOTAVAIL; 786 goto bad; 787 } 788 789 /* copy src */ 790 src = sc->gif_psrc; 791 dst = (struct sockaddr *) 792 &(((struct if_laddrreq *)data)->addr); 793 size = sizeof(((struct if_laddrreq *)data)->addr); 794 if (src->sa_len > size) 795 return EINVAL; 796 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 797 798 /* copy dst */ 799 src = sc->gif_pdst; 800 dst = (struct sockaddr *) 801 &(((struct if_laddrreq *)data)->dstaddr); 802 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 803 if (src->sa_len > size) 804 return EINVAL; 805 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 806 break; 807 808 case SIOCSIFFLAGS: 809 /* if_ioctl() takes care of it */ 810 break; 811 812 default: 813 error = EINVAL; 814 break; 815 } 816 bad: 817 return error; 818} 819 820void 821gif_delete_tunnel(sc) 822 struct gif_softc *sc; 823{ 824 /* XXX: NetBSD protects this function with splsoftnet() */ 825 826 if (sc->gif_psrc) { 827 free((caddr_t)sc->gif_psrc, M_IFADDR); 828 sc->gif_psrc = NULL; 829 } 830 if (sc->gif_pdst) { 831 free((caddr_t)sc->gif_pdst, M_IFADDR); 832 sc->gif_pdst = NULL; 833 } 834 /* change the IFF_UP flag as well? */ 835} 836