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