The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_gif.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD: releng/5.0/sys/net/if_gif.c 106939 2002-11-15 00:00:15Z sam $ */
    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 
   86 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
   87 static LIST_HEAD(, gif_softc) gif_softc_list;
   88 
   89 void    (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
   90 void    (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
   91 void    (*ng_gif_attach_p)(struct ifnet *ifp);
   92 void    (*ng_gif_detach_p)(struct ifnet *ifp);
   93 
   94 int     gif_clone_create(struct if_clone *, int);
   95 void    gif_clone_destroy(struct ifnet *);
   96 
   97 struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif",
   98     gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT);
   99 
  100 static int gifmodevent(module_t, int, void *);
  101 
  102 SYSCTL_DECL(_net_link);
  103 SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
  104     "Generic Tunnel Interface");
  105 #ifndef MAX_GIF_NEST
  106 /*
  107  * This macro controls the default upper limitation on nesting of gif tunnels.
  108  * Since, setting a large value to this macro with a careless configuration
  109  * may introduce system crash, we don't allow any nestings by default.
  110  * If you need to configure nested gif tunnels, you can define this macro
  111  * in your kernel configuration file.  However, if you do so, please be
  112  * careful to configure the tunnels so that it won't make a loop.
  113  */
  114 #define MAX_GIF_NEST 1
  115 #endif
  116 static int max_gif_nesting = MAX_GIF_NEST;
  117 SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
  118     &max_gif_nesting, 0, "Max nested tunnels");
  119 
  120 /*
  121  * By default, we disallow creation of multiple tunnels between the same
  122  * pair of addresses.  Some applications require this functionality so
  123  * we allow control over this check here.
  124  */
  125 #ifdef XBONEHACK
  126 static int parallel_tunnels = 1;
  127 #else
  128 static int parallel_tunnels = 0;
  129 #endif
  130 SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
  131     &parallel_tunnels, 0, "Allow parallel tunnels?");
  132 
  133 int
  134 gif_clone_create(ifc, unit)
  135         struct if_clone *ifc;
  136         int unit;
  137 {
  138         struct gif_softc *sc;
  139 
  140         sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
  141         bzero(sc, sizeof(struct gif_softc));
  142 
  143         sc->gif_if.if_softc = sc;
  144         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 
  153 void
  154 gifattach0(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 
  177 void
  178 gif_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 
  207 static int
  208 gifmodevent(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 
  238 static moduledata_t gif_mod = {
  239         "if_gif",
  240         gifmodevent,
  241         0
  242 };
  243 
  244 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
  245 MODULE_VERSION(if_gif, 1);
  246 
  247 int
  248 gif_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         /* Bail on short packets */
  282         if (m->m_pkthdr.len < sizeof(ip))
  283                 return 0;
  284 
  285         m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
  286 
  287         switch (ip.ip_v) {
  288 #ifdef INET
  289         case 4:
  290                 if (sc->gif_psrc->sa_family != AF_INET ||
  291                     sc->gif_pdst->sa_family != AF_INET)
  292                         return 0;
  293                 return gif_encapcheck4(m, off, proto, arg);
  294 #endif
  295 #ifdef INET6
  296         case 6:
  297                 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
  298                         return 0;
  299                 if (sc->gif_psrc->sa_family != AF_INET6 ||
  300                     sc->gif_pdst->sa_family != AF_INET6)
  301                         return 0;
  302                 return gif_encapcheck6(m, off, proto, arg);
  303 #endif
  304         default:
  305                 return 0;
  306         }
  307 }
  308 
  309 int
  310 gif_output(ifp, m, dst, rt)
  311         struct ifnet *ifp;
  312         struct mbuf *m;
  313         struct sockaddr *dst;
  314         struct rtentry *rt;     /* added in net2 */
  315 {
  316         struct gif_softc *sc = (struct gif_softc*)ifp;
  317         int error = 0;
  318         static int called = 0;  /* XXX: MUTEX */
  319 
  320 #ifdef MAC
  321         error = mac_check_ifnet_transmit(ifp, m);
  322         if (error) {
  323                 m_freem(m);
  324                 goto end;
  325         }
  326 #endif
  327 
  328         /*
  329          * gif may cause infinite recursion calls when misconfigured.
  330          * We'll prevent this by introducing upper limit.
  331          * XXX: this mechanism may introduce another problem about
  332          *      mutual exclusion of the variable CALLED, especially if we
  333          *      use kernel thread.
  334          */
  335         if (++called > max_gif_nesting) {
  336                 log(LOG_NOTICE,
  337                     "gif_output: recursively called too many times(%d)\n",
  338                     called);
  339                 m_freem(m);
  340                 error = EIO;    /* is there better errno? */
  341                 goto end;
  342         }
  343 
  344         m->m_flags &= ~(M_BCAST|M_MCAST);
  345         if (!(ifp->if_flags & IFF_UP) ||
  346             sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
  347                 m_freem(m);
  348                 error = ENETDOWN;
  349                 goto end;
  350         }
  351 
  352         if (ifp->if_bpf) {
  353                 /*
  354                  * We need to prepend the address family as
  355                  * a four byte field.  Cons up a dummy header
  356                  * to pacify bpf.  This is safe because bpf
  357                  * will only read from the mbuf (i.e., it won't
  358                  * try to free it or keep a pointer a to it).
  359                  */
  360                 struct mbuf m0;
  361                 u_int32_t af = dst->sa_family;
  362 
  363                 m0.m_next = m;
  364                 m0.m_len = 4;
  365                 m0.m_data = (char *)&af;
  366                 
  367                 BPF_MTAP(ifp, &m0);
  368         }
  369         ifp->if_opackets++;     
  370         ifp->if_obytes += m->m_pkthdr.len;
  371 
  372         /* inner AF-specific encapsulation */
  373 
  374         /* XXX should we check if our outer source is legal? */
  375 
  376         /* dispatch to output logic based on outer AF */
  377         switch (sc->gif_psrc->sa_family) {
  378 #ifdef INET
  379         case AF_INET:
  380                 error = in_gif_output(ifp, dst->sa_family, m);
  381                 break;
  382 #endif
  383 #ifdef INET6
  384         case AF_INET6:
  385                 error = in6_gif_output(ifp, dst->sa_family, m);
  386                 break;
  387 #endif
  388         default:
  389                 m_freem(m);             
  390                 error = ENETDOWN;
  391                 goto end;
  392         }
  393 
  394   end:
  395         called = 0;             /* reset recursion counter */
  396         if (error)
  397                 ifp->if_oerrors++;
  398         return error;
  399 }
  400 
  401 void
  402 gif_input(m, af, ifp)
  403         struct mbuf *m;
  404         int af;
  405         struct ifnet *ifp;
  406 {
  407         int isr;
  408         struct ifqueue *ifq = NULL;
  409 
  410         if (ifp == NULL) {
  411                 /* just in case */
  412                 m_freem(m);
  413                 return;
  414         }
  415 
  416         m->m_pkthdr.rcvif = ifp;
  417 
  418 #ifdef MAC
  419         mac_create_mbuf_from_ifnet(ifp, m);
  420 #endif
  421 
  422         if (ifp->if_bpf) {
  423                 /*
  424                  * We need to prepend the address family as
  425                  * a four byte field.  Cons up a dummy header
  426                  * to pacify bpf.  This is safe because bpf
  427                  * will only read from the mbuf (i.e., it won't
  428                  * try to free it or keep a pointer a to it).
  429                  */
  430                 struct mbuf m0;
  431                 u_int32_t af1 = af;
  432                 
  433                 m0.m_next = m;
  434                 m0.m_len = 4;
  435                 m0.m_data = (char *)&af1;
  436                 
  437                 BPF_MTAP(ifp, &m0);
  438         }
  439 
  440         if (ng_gif_input_p != NULL) {
  441                 (*ng_gif_input_p)(ifp, &m, af);
  442                 if (m == NULL)
  443                         return;
  444         }
  445 
  446         /*
  447          * Put the packet to the network layer input queue according to the
  448          * specified address family.
  449          * Note: older versions of gif_input directly called network layer
  450          * input functions, e.g. ip6_input, here.  We changed the policy to
  451          * prevent too many recursive calls of such input functions, which
  452          * might cause kernel panic.  But the change may introduce another
  453          * problem; if the input queue is full, packets are discarded.
  454          * The kernel stack overflow really happened, and we believed
  455          * queue-full rarely occurs, so we changed the policy.
  456          */
  457         switch (af) {
  458 #ifdef INET
  459         case AF_INET:
  460                 ifq = &ipintrq;
  461                 isr = NETISR_IP;
  462                 break;
  463 #endif
  464 #ifdef INET6
  465         case AF_INET6:
  466                 ifq = &ip6intrq;
  467                 isr = NETISR_IPV6;
  468                 break;
  469 #endif
  470         default:
  471                 if (ng_gif_input_orphan_p != NULL)
  472                         (*ng_gif_input_orphan_p)(ifp, m, af);
  473                 else
  474                         m_freem(m);
  475                 return;
  476         }
  477 
  478         ifp->if_ipackets++;
  479         ifp->if_ibytes += m->m_pkthdr.len;
  480         (void) IF_HANDOFF(ifq, m, NULL);
  481         /* we need schednetisr since the address family may change */
  482         schednetisr(isr);
  483 
  484         return;
  485 }
  486 
  487 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
  488 int
  489 gif_ioctl(ifp, cmd, data)
  490         struct ifnet *ifp;
  491         u_long cmd;
  492         caddr_t data;
  493 {
  494         struct gif_softc *sc  = (struct gif_softc*)ifp;
  495         struct ifreq     *ifr = (struct ifreq*)data;
  496         int error = 0, size;
  497         struct sockaddr *dst, *src;
  498 #ifdef  SIOCSIFMTU /* xxx */
  499         u_long mtu;
  500 #endif
  501 
  502         switch (cmd) {
  503         case SIOCSIFADDR:
  504                 ifp->if_flags |= IFF_UP;
  505                 break;
  506                 
  507         case SIOCSIFDSTADDR:
  508                 break;
  509 
  510         case SIOCADDMULTI:
  511         case SIOCDELMULTI:
  512                 break;
  513 
  514 #ifdef  SIOCSIFMTU /* xxx */
  515         case SIOCGIFMTU:
  516                 break;
  517 
  518         case SIOCSIFMTU:
  519                 mtu = ifr->ifr_mtu;
  520                 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
  521                         return (EINVAL);
  522                 ifp->if_mtu = mtu;
  523                 break;
  524 #endif /* SIOCSIFMTU */
  525 
  526 #ifdef INET
  527         case SIOCSIFPHYADDR:
  528 #endif
  529 #ifdef INET6
  530         case SIOCSIFPHYADDR_IN6:
  531 #endif /* INET6 */
  532         case SIOCSLIFPHYADDR:
  533                 switch (cmd) {
  534 #ifdef INET
  535                 case SIOCSIFPHYADDR:
  536                         src = (struct sockaddr *)
  537                                 &(((struct in_aliasreq *)data)->ifra_addr);
  538                         dst = (struct sockaddr *)
  539                                 &(((struct in_aliasreq *)data)->ifra_dstaddr);
  540                         break;
  541 #endif
  542 #ifdef INET6
  543                 case SIOCSIFPHYADDR_IN6:
  544                         src = (struct sockaddr *)
  545                                 &(((struct in6_aliasreq *)data)->ifra_addr);
  546                         dst = (struct sockaddr *)
  547                                 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
  548                         break;
  549 #endif
  550                 case SIOCSLIFPHYADDR:
  551                         src = (struct sockaddr *)
  552                                 &(((struct if_laddrreq *)data)->addr);
  553                         dst = (struct sockaddr *)
  554                                 &(((struct if_laddrreq *)data)->dstaddr);
  555                         break;
  556                 default:
  557                         return EINVAL;
  558                 }
  559 
  560                 /* sa_family must be equal */
  561                 if (src->sa_family != dst->sa_family)
  562                         return EINVAL;
  563 
  564                 /* validate sa_len */
  565                 switch (src->sa_family) {
  566 #ifdef INET
  567                 case AF_INET:
  568                         if (src->sa_len != sizeof(struct sockaddr_in))
  569                                 return EINVAL;
  570                         break;
  571 #endif
  572 #ifdef INET6
  573                 case AF_INET6:
  574                         if (src->sa_len != sizeof(struct sockaddr_in6))
  575                                 return EINVAL;
  576                         break;
  577 #endif
  578                 default:
  579                         return EAFNOSUPPORT;
  580                 }
  581                 switch (dst->sa_family) {
  582 #ifdef INET
  583                 case AF_INET:
  584                         if (dst->sa_len != sizeof(struct sockaddr_in))
  585                                 return EINVAL;
  586                         break;
  587 #endif
  588 #ifdef INET6
  589                 case AF_INET6:
  590                         if (dst->sa_len != sizeof(struct sockaddr_in6))
  591                                 return EINVAL;
  592                         break;
  593 #endif
  594                 default:
  595                         return EAFNOSUPPORT;
  596                 }
  597 
  598                 /* check sa_family looks sane for the cmd */
  599                 switch (cmd) {
  600                 case SIOCSIFPHYADDR:
  601                         if (src->sa_family == AF_INET)
  602                                 break;
  603                         return EAFNOSUPPORT;
  604 #ifdef INET6
  605                 case SIOCSIFPHYADDR_IN6:
  606                         if (src->sa_family == AF_INET6)
  607                                 break;
  608                         return EAFNOSUPPORT;
  609 #endif /* INET6 */
  610                 case SIOCSLIFPHYADDR:
  611                         /* checks done in the above */
  612                         break;
  613                 }
  614 
  615                 error = gif_set_tunnel(&sc->gif_if, src, dst);
  616                 break;
  617 
  618 #ifdef SIOCDIFPHYADDR
  619         case SIOCDIFPHYADDR:
  620                 gif_delete_tunnel(&sc->gif_if);
  621                 break;
  622 #endif
  623                         
  624         case SIOCGIFPSRCADDR:
  625 #ifdef INET6
  626         case SIOCGIFPSRCADDR_IN6:
  627 #endif /* INET6 */
  628                 if (sc->gif_psrc == NULL) {
  629                         error = EADDRNOTAVAIL;
  630                         goto bad;
  631                 }
  632                 src = sc->gif_psrc;
  633                 switch (cmd) {
  634 #ifdef INET
  635                 case SIOCGIFPSRCADDR:
  636                         dst = &ifr->ifr_addr;
  637                         size = sizeof(ifr->ifr_addr);
  638                         break;
  639 #endif /* INET */
  640 #ifdef INET6
  641                 case SIOCGIFPSRCADDR_IN6:
  642                         dst = (struct sockaddr *)
  643                                 &(((struct in6_ifreq *)data)->ifr_addr);
  644                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
  645                         break;
  646 #endif /* INET6 */
  647                 default:
  648                         error = EADDRNOTAVAIL;
  649                         goto bad;
  650                 }
  651                 if (src->sa_len > size)
  652                         return EINVAL;
  653                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  654                 break;
  655                         
  656         case SIOCGIFPDSTADDR:
  657 #ifdef INET6
  658         case SIOCGIFPDSTADDR_IN6:
  659 #endif /* INET6 */
  660                 if (sc->gif_pdst == NULL) {
  661                         error = EADDRNOTAVAIL;
  662                         goto bad;
  663                 }
  664                 src = sc->gif_pdst;
  665                 switch (cmd) {
  666 #ifdef INET
  667                 case SIOCGIFPDSTADDR:
  668                         dst = &ifr->ifr_addr;
  669                         size = sizeof(ifr->ifr_addr);
  670                         break;
  671 #endif /* INET */
  672 #ifdef INET6
  673                 case SIOCGIFPDSTADDR_IN6:
  674                         dst = (struct sockaddr *)
  675                                 &(((struct in6_ifreq *)data)->ifr_addr);
  676                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
  677                         break;
  678 #endif /* INET6 */
  679                 default:
  680                         error = EADDRNOTAVAIL;
  681                         goto bad;
  682                 }
  683                 if (src->sa_len > size)
  684                         return EINVAL;
  685                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  686                 break;
  687 
  688         case SIOCGLIFPHYADDR:
  689                 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
  690                         error = EADDRNOTAVAIL;
  691                         goto bad;
  692                 }
  693 
  694                 /* copy src */
  695                 src = sc->gif_psrc;
  696                 dst = (struct sockaddr *)
  697                         &(((struct if_laddrreq *)data)->addr);
  698                 size = sizeof(((struct if_laddrreq *)data)->addr);
  699                 if (src->sa_len > size)
  700                         return EINVAL;
  701                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  702 
  703                 /* copy dst */
  704                 src = sc->gif_pdst;
  705                 dst = (struct sockaddr *)
  706                         &(((struct if_laddrreq *)data)->dstaddr);
  707                 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
  708                 if (src->sa_len > size)
  709                         return EINVAL;
  710                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  711                 break;
  712 
  713         case SIOCSIFFLAGS:
  714                 /* if_ioctl() takes care of it */
  715                 break;
  716 
  717         default:
  718                 error = EINVAL;
  719                 break;
  720         }
  721  bad:
  722         return error;
  723 }
  724 
  725 int
  726 gif_set_tunnel(ifp, src, dst)
  727         struct ifnet *ifp;
  728         struct sockaddr *src;
  729         struct sockaddr *dst;
  730 {
  731         struct gif_softc *sc = (struct gif_softc *)ifp;
  732         struct gif_softc *sc2;
  733         struct sockaddr *osrc, *odst, *sa;
  734         int s;
  735         int error = 0; 
  736 
  737         s = splnet();
  738 
  739         LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
  740                 if (sc2 == sc)
  741                         continue;
  742                 if (!sc2->gif_pdst || !sc2->gif_psrc)
  743                         continue;
  744                 if (sc2->gif_pdst->sa_family != dst->sa_family ||
  745                     sc2->gif_pdst->sa_len != dst->sa_len ||
  746                     sc2->gif_psrc->sa_family != src->sa_family ||
  747                     sc2->gif_psrc->sa_len != src->sa_len)
  748                         continue;
  749 
  750                 /*
  751                  * Disallow parallel tunnels unless instructed
  752                  * otherwise.
  753                  */
  754                 if (!parallel_tunnels &&
  755                     bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
  756                     bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
  757                         error = EADDRNOTAVAIL;
  758                         goto bad;
  759                 }
  760 
  761                 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
  762         }
  763 
  764         /* XXX we can detach from both, but be polite just in case */
  765         if (sc->gif_psrc)
  766                 switch (sc->gif_psrc->sa_family) {
  767 #ifdef INET
  768                 case AF_INET:
  769                         (void)in_gif_detach(sc);
  770                         break;
  771 #endif
  772 #ifdef INET6
  773                 case AF_INET6:
  774                         (void)in6_gif_detach(sc);
  775                         break;
  776 #endif
  777                 }
  778 
  779         osrc = sc->gif_psrc;
  780         sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
  781         bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
  782         sc->gif_psrc = sa;
  783 
  784         odst = sc->gif_pdst;
  785         sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
  786         bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
  787         sc->gif_pdst = sa;
  788 
  789         switch (sc->gif_psrc->sa_family) {
  790 #ifdef INET
  791         case AF_INET:
  792                 error = in_gif_attach(sc);
  793                 break;
  794 #endif
  795 #ifdef INET6
  796         case AF_INET6:
  797                 error = in6_gif_attach(sc);
  798                 break;
  799 #endif
  800         }
  801         if (error) {
  802                 /* rollback */
  803                 free((caddr_t)sc->gif_psrc, M_IFADDR);
  804                 free((caddr_t)sc->gif_pdst, M_IFADDR);
  805                 sc->gif_psrc = osrc;
  806                 sc->gif_pdst = odst;
  807                 goto bad;
  808         }
  809 
  810         if (osrc)
  811                 free((caddr_t)osrc, M_IFADDR);
  812         if (odst)
  813                 free((caddr_t)odst, M_IFADDR);
  814 
  815         if (sc->gif_psrc && sc->gif_pdst)
  816                 ifp->if_flags |= IFF_RUNNING;
  817         else
  818                 ifp->if_flags &= ~IFF_RUNNING;
  819         splx(s);
  820 
  821         return 0;
  822 
  823  bad:
  824         if (sc->gif_psrc && sc->gif_pdst)
  825                 ifp->if_flags |= IFF_RUNNING;
  826         else
  827                 ifp->if_flags &= ~IFF_RUNNING;
  828         splx(s);
  829 
  830         return error;
  831 }
  832 
  833 void
  834 gif_delete_tunnel(ifp)
  835         struct ifnet *ifp;
  836 {
  837         struct gif_softc *sc = (struct gif_softc *)ifp;
  838         int s;
  839 
  840         s = splnet();
  841 
  842         if (sc->gif_psrc) {
  843                 free((caddr_t)sc->gif_psrc, M_IFADDR);
  844                 sc->gif_psrc = NULL;
  845         }
  846         if (sc->gif_pdst) {
  847                 free((caddr_t)sc->gif_pdst, M_IFADDR);
  848                 sc->gif_pdst = NULL;
  849         }
  850         /* it is safe to detach from both */
  851 #ifdef INET
  852         (void)in_gif_detach(sc);
  853 #endif
  854 #ifdef INET6
  855         (void)in6_gif_detach(sc);
  856 #endif
  857 
  858         if (sc->gif_psrc && sc->gif_pdst)
  859                 ifp->if_flags |= IFF_RUNNING;
  860         else
  861                 ifp->if_flags &= ~IFF_RUNNING;
  862         splx(s);
  863 }

Cache object: 40762d8d848ae14dad4049f52433c378


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.