root/net/if_gif.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gifattach
  2. gif_clone_create
  3. gif_clone_destroy
  4. gif_start
  5. gif_output
  6. gif_ioctl

    1 /*      $OpenBSD: if_gif.c,v 1.45 2007/05/26 17:13:30 jason Exp $       */
    2 /*      $KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 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 <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/mbuf.h>
   37 #include <sys/socket.h>
   38 #include <sys/sockio.h>
   39 #include <sys/syslog.h>
   40 
   41 #include <net/if.h>
   42 #include <net/if_types.h>
   43 #include <net/route.h>
   44 #include <net/bpf.h>
   45 
   46 #ifdef  INET
   47 #include <netinet/in.h>
   48 #include <netinet/in_systm.h>
   49 #include <netinet/in_var.h>
   50 #include <netinet/in_gif.h>
   51 #include <netinet/ip.h>
   52 #endif  /* INET */
   53 
   54 #ifdef INET6
   55 #ifndef INET
   56 #include <netinet/in.h>
   57 #endif
   58 #include <netinet/ip6.h>
   59 #include <netinet6/in6_gif.h>
   60 #endif /* INET6 */
   61 
   62 #include <net/if_gif.h>
   63 
   64 #include "bpfilter.h"
   65 #include "bridge.h"
   66 
   67 void    gifattach(int);
   68 int     gif_clone_create(struct if_clone *, int);
   69 int     gif_clone_destroy(struct ifnet *);
   70 
   71 /*
   72  * gif global variable definitions
   73  */
   74 struct gif_softc_head gif_softc_list;
   75 struct if_clone gif_cloner =
   76     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
   77 
   78 /* ARGSUSED */
   79 void
   80 gifattach(count)
   81         int count;
   82 {
   83         LIST_INIT(&gif_softc_list);
   84         if_clone_attach(&gif_cloner);
   85 }
   86 
   87 int
   88 gif_clone_create(ifc, unit)
   89         struct if_clone *ifc;
   90         int unit;
   91 {
   92         struct gif_softc *sc;
   93         int s;
   94 
   95         sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
   96         if (!sc)
   97                 return (ENOMEM);
   98         bzero(sc, sizeof(*sc));
   99 
  100         snprintf(sc->gif_if.if_xname, sizeof sc->gif_if.if_xname,
  101              "%s%d", ifc->ifc_name, unit);
  102         sc->gif_if.if_mtu    = GIF_MTU;
  103         sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
  104         sc->gif_if.if_ioctl  = gif_ioctl;
  105         sc->gif_if.if_start  = gif_start;
  106         sc->gif_if.if_output = gif_output;
  107         sc->gif_if.if_type   = IFT_GIF;
  108         IFQ_SET_MAXLEN(&sc->gif_if.if_snd, ifqmaxlen);
  109         IFQ_SET_READY(&sc->gif_if.if_snd);
  110         sc->gif_if.if_softc = sc;
  111         if_attach(&sc->gif_if);
  112         if_alloc_sadl(&sc->gif_if);
  113 
  114 #if NBPFILTER > 0
  115         bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL,
  116             sizeof(u_int));
  117 #endif
  118         s = splnet();
  119         LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
  120         splx(s);
  121 
  122         return (0);
  123 }
  124 
  125 int
  126 gif_clone_destroy(ifp)
  127         struct ifnet *ifp;
  128 {
  129         struct gif_softc *sc = ifp->if_softc;
  130         int s;
  131 
  132         s = splnet();
  133         LIST_REMOVE(sc, gif_list);
  134         splx(s);
  135 
  136         if_detach(ifp);
  137 
  138         if (sc->gif_psrc)
  139                 free((caddr_t)sc->gif_psrc, M_IFADDR);
  140         sc->gif_psrc = NULL;
  141         if (sc->gif_pdst)
  142                 free((caddr_t)sc->gif_pdst, M_IFADDR);
  143         sc->gif_pdst = NULL;
  144         free(sc, M_DEVBUF);
  145         return (0);
  146 }
  147 
  148 void
  149 gif_start(ifp)
  150         struct ifnet *ifp;
  151 {
  152         struct gif_softc *sc = (struct gif_softc*)ifp;
  153         struct mbuf *m;
  154         struct m_tag *mtag;
  155         int family;
  156         int s;
  157         u_int8_t tp;
  158 
  159         /* is interface up and running? */
  160         if ((ifp->if_flags & (IFF_OACTIVE | IFF_UP)) != IFF_UP ||
  161             sc->gif_psrc == NULL || sc->gif_pdst == NULL)
  162                 return;
  163 
  164         /* are the tunnel endpoints valid? */
  165 #ifdef INET
  166         if (sc->gif_psrc->sa_family != AF_INET)
  167 #endif
  168 #ifdef INET6
  169                 if (sc->gif_psrc->sa_family != AF_INET6)
  170 #endif
  171                         return;
  172 
  173         s = splnet();
  174         ifp->if_flags |= IFF_OACTIVE;
  175         splx(s);
  176 
  177         while (1) {
  178                 s = splnet();
  179                 IFQ_DEQUEUE(&ifp->if_snd, m);
  180                 splx(s);
  181 
  182                 if (m == NULL)
  183                         break;
  184 
  185                 /*
  186                  * gif may cause infinite recursion calls when misconfigured.
  187                  * We'll prevent this by detecting loops.
  188                  */
  189                 for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag;
  190                     mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) {
  191                         if (!bcmp((caddr_t)(mtag + 1), &ifp,
  192                             sizeof(struct ifnet *))) {
  193                                 IF_DROP(&ifp->if_snd);
  194                                 log(LOG_NOTICE, "gif_output: "
  195                                     "recursively called too many times\n");
  196                                 m_freem(m);
  197                                 break;
  198                         }
  199                 }
  200                 if (mtag)
  201                         continue;
  202 
  203                 mtag = m_tag_get(PACKET_TAG_GIF, sizeof(caddr_t), M_NOWAIT);
  204                 if (mtag == NULL) {
  205                         m_freem(m);
  206                         break;
  207                 }
  208                 bcopy(&ifp, mtag + 1, sizeof(caddr_t));
  209                 m_tag_prepend(m, mtag);
  210 
  211                 /*
  212                  * remove multicast and broadcast flags or encapsulated paket
  213                  * ends up as multicast or broadcast packet.
  214                  */
  215                 m->m_flags &= ~(M_BCAST|M_MCAST);
  216 
  217                 /* extract address family */
  218                 family = AF_UNSPEC;
  219                 tp = *mtod(m, u_int8_t *);
  220                 tp = (tp >> 4) & 0xff;  /* Get the IP version number. */
  221 #ifdef INET
  222                 if (tp == IPVERSION)
  223                         family = AF_INET;
  224 #endif
  225 #ifdef INET6
  226                 if (tp == (IPV6_VERSION >> 4))
  227                         family = AF_INET6;
  228 #endif
  229 
  230 #if NBRIDGE > 0
  231                 /*
  232                  * Check if the packet is comming via bridge and needs
  233                  * etherip encapsulation or not.
  234                  */
  235                 if (ifp->if_bridge && (m->m_flags & M_PROTO1)) {
  236                         m->m_flags &= ~M_PROTO1;
  237                         family = AF_LINK;
  238                 }
  239 #endif
  240 
  241 #if NBPFILTER > 0
  242                 if (ifp->if_bpf)
  243                         bpf_mtap_af(ifp->if_bpf, family, m, BPF_DIRECTION_OUT);
  244 #endif
  245                 ifp->if_opackets++;
  246                 ifp->if_obytes += m->m_pkthdr.len;
  247 
  248                 switch (sc->gif_psrc->sa_family) {
  249 #ifdef INET
  250                 case AF_INET:
  251                         in_gif_output(ifp, family, m);
  252                         break;
  253 #endif
  254 #ifdef INET6
  255                 case AF_INET6:
  256                         in6_gif_output(ifp, family, m);
  257                         break;
  258 #endif
  259                 default:
  260                         m_freem(m);
  261                         break;
  262                 }
  263         }
  264 
  265         ifp->if_flags &= ~IFF_OACTIVE;
  266 }
  267 
  268 int
  269 gif_output(ifp, m, dst, rt)
  270         struct ifnet *ifp;
  271         struct mbuf *m;
  272         struct sockaddr *dst;
  273         struct rtentry *rt;     /* added in net2 */
  274 {
  275         struct gif_softc *sc = (struct gif_softc*)ifp;
  276         int error = 0;
  277         int s;
  278 
  279         if (!(ifp->if_flags & IFF_UP) ||
  280             sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
  281                 m_freem(m);
  282                 error = ENETDOWN;
  283                 goto end;
  284         }
  285 
  286         switch (sc->gif_psrc->sa_family) {
  287 #ifdef INET
  288         case AF_INET:
  289                 break;
  290 #endif
  291 #ifdef INET6
  292         case AF_INET6:
  293                 break;
  294 #endif
  295         default:
  296                 m_freem(m);
  297                 error = ENETDOWN;
  298                 goto end;
  299         }
  300 
  301         s = splnet();
  302         /*
  303          * Queue message on interface, and start output if interface
  304          * not yet active.
  305          */
  306         IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
  307         if (error) {
  308                 /* mbuf is already freed */
  309                 splx(s);
  310                 return (error);
  311         }
  312         if ((ifp->if_flags & IFF_OACTIVE) == 0)
  313                 (*ifp->if_start)(ifp);
  314         splx(s);
  315         return (error);
  316 
  317 end:
  318         if (error)
  319                 ifp->if_oerrors++;
  320         return (error);
  321 }
  322 
  323 int
  324 gif_ioctl(ifp, cmd, data)
  325         struct ifnet *ifp;
  326         u_long cmd;
  327         caddr_t data;
  328 {
  329         struct gif_softc *sc  = (struct gif_softc*)ifp;
  330         struct ifreq     *ifr = (struct ifreq*)data;
  331         int error = 0, size;
  332         struct sockaddr *dst, *src;
  333         struct sockaddr *sa;
  334         int s;
  335         struct gif_softc *sc2;
  336 
  337         switch (cmd) {
  338         case SIOCSIFADDR:
  339                 break;
  340 
  341         case SIOCSIFDSTADDR:
  342                 break;
  343 
  344         case SIOCADDMULTI:
  345         case SIOCDELMULTI:
  346                 switch (ifr->ifr_addr.sa_family) {
  347 #ifdef INET
  348                 case AF_INET:   /* IP supports Multicast */
  349                         break;
  350 #endif /* INET */
  351 #ifdef INET6
  352                 case AF_INET6:  /* IP6 supports Multicast */
  353                         break;
  354 #endif /* INET6 */
  355                 default:  /* Other protocols doesn't support Multicast */
  356                         error = EAFNOSUPPORT;
  357                         break;
  358                 }
  359                 break;
  360 
  361         case SIOCSIFPHYADDR:
  362 #ifdef INET6
  363         case SIOCSIFPHYADDR_IN6:
  364 #endif /* INET6 */
  365         case SIOCSLIFPHYADDR:
  366                 switch (cmd) {
  367 #ifdef INET
  368                 case SIOCSIFPHYADDR:
  369                         src = (struct sockaddr *)
  370                                 &(((struct in_aliasreq *)data)->ifra_addr);
  371                         dst = (struct sockaddr *)
  372                                 &(((struct in_aliasreq *)data)->ifra_dstaddr);
  373                         break;
  374 #endif
  375 #ifdef INET6
  376                 case SIOCSIFPHYADDR_IN6:
  377                         src = (struct sockaddr *)
  378                                 &(((struct in6_aliasreq *)data)->ifra_addr);
  379                         dst = (struct sockaddr *)
  380                                 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
  381                         break;
  382 #endif
  383                 case SIOCSLIFPHYADDR:
  384                         src = (struct sockaddr *)
  385                                 &(((struct if_laddrreq *)data)->addr);
  386                         dst = (struct sockaddr *)
  387                                 &(((struct if_laddrreq *)data)->dstaddr);
  388                         break;
  389                 default:
  390                         return (EINVAL);
  391                 }
  392 
  393                 /* sa_family must be equal */
  394                 if (src->sa_family != dst->sa_family)
  395                         return (EINVAL);
  396 
  397                 /* validate sa_len */
  398                 switch (src->sa_family) {
  399 #ifdef INET
  400                 case AF_INET:
  401                         if (src->sa_len != sizeof(struct sockaddr_in))
  402                                 return (EINVAL);
  403                         break;
  404 #endif
  405 #ifdef INET6
  406                 case AF_INET6:
  407                         if (src->sa_len != sizeof(struct sockaddr_in6))
  408                                 return (EINVAL);
  409                         break;
  410 #endif
  411                 default:
  412                         return (EAFNOSUPPORT);
  413                 }
  414                 switch (dst->sa_family) {
  415 #ifdef INET
  416                 case AF_INET:
  417                         if (dst->sa_len != sizeof(struct sockaddr_in))
  418                                 return (EINVAL);
  419                         break;
  420 #endif
  421 #ifdef INET6
  422                 case AF_INET6:
  423                         if (dst->sa_len != sizeof(struct sockaddr_in6))
  424                                 return (EINVAL);
  425                         break;
  426 #endif
  427                 default:
  428                         return (EAFNOSUPPORT);
  429                 }
  430 
  431                 /* check sa_family looks sane for the cmd */
  432                 switch (cmd) {
  433                 case SIOCSIFPHYADDR:
  434                         if (src->sa_family == AF_INET)
  435                                 break;
  436                         return (EAFNOSUPPORT);
  437 #ifdef INET6
  438                 case SIOCSIFPHYADDR_IN6:
  439                         if (src->sa_family == AF_INET6)
  440                                 break;
  441                         return (EAFNOSUPPORT);
  442 #endif /* INET6 */
  443                 case SIOCSLIFPHYADDR:
  444                         /* checks done in the above */
  445                         break;
  446                 }
  447 
  448                 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
  449                         if (sc2 == sc)
  450                                 continue;
  451                         if (!sc2->gif_pdst || !sc2->gif_psrc)
  452                                 continue;
  453                         if (sc2->gif_pdst->sa_family != dst->sa_family ||
  454                             sc2->gif_pdst->sa_len != dst->sa_len ||
  455                             sc2->gif_psrc->sa_family != src->sa_family ||
  456                             sc2->gif_psrc->sa_len != src->sa_len)
  457                                 continue;
  458                         /* can't configure same pair of address onto two gifs */
  459                         if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
  460                             bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
  461                                 error = EADDRNOTAVAIL;
  462                                 goto bad;
  463                         }
  464 
  465                         /* can't configure multiple multi-dest interfaces */
  466 #define multidest(x) \
  467         (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
  468 #ifdef INET6
  469 #define multidest6(x) \
  470         (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
  471 #endif
  472                         if (dst->sa_family == AF_INET &&
  473                             multidest(dst) && multidest(sc2->gif_pdst)) {
  474                                 error = EADDRNOTAVAIL;
  475                                 goto bad;
  476                         }
  477 #ifdef INET6
  478                         if (dst->sa_family == AF_INET6 &&
  479                             multidest6(dst) && multidest6(sc2->gif_pdst)) {
  480                                 error = EADDRNOTAVAIL;
  481                                 goto bad;
  482                         }
  483 #endif
  484                 }
  485 
  486                 if (sc->gif_psrc)
  487                         free((caddr_t)sc->gif_psrc, M_IFADDR);
  488                 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
  489                 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
  490                 sc->gif_psrc = sa;
  491 
  492                 if (sc->gif_pdst)
  493                         free((caddr_t)sc->gif_pdst, M_IFADDR);
  494                 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
  495                 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
  496                 sc->gif_pdst = sa;
  497 
  498                 s = splnet();
  499                 ifp->if_flags |= IFF_RUNNING;
  500                 if_up(ifp);             /* send up RTM_IFINFO */
  501                 splx(s);
  502 
  503                 error = 0;
  504                 break;
  505 
  506 #ifdef SIOCDIFPHYADDR
  507         case SIOCDIFPHYADDR:
  508                 if (sc->gif_psrc) {
  509                         free((caddr_t)sc->gif_psrc, M_IFADDR);
  510                         sc->gif_psrc = NULL;
  511                 }
  512                 if (sc->gif_pdst) {
  513                         free((caddr_t)sc->gif_pdst, M_IFADDR);
  514                         sc->gif_pdst = NULL;
  515                 }
  516                 /* change the IFF_{UP, RUNNING} flag as well? */
  517                 break;
  518 #endif
  519 
  520         case SIOCGIFPSRCADDR:
  521 #ifdef INET6
  522         case SIOCGIFPSRCADDR_IN6:
  523 #endif /* INET6 */
  524                 if (sc->gif_psrc == NULL) {
  525                         error = EADDRNOTAVAIL;
  526                         goto bad;
  527                 }
  528                 src = sc->gif_psrc;
  529                 switch (cmd) {
  530 #ifdef INET
  531                 case SIOCGIFPSRCADDR:
  532                         dst = &ifr->ifr_addr;
  533                         size = sizeof(ifr->ifr_addr);
  534                         break;
  535 #endif /* INET */
  536 #ifdef INET6
  537                 case SIOCGIFPSRCADDR_IN6:
  538                         dst = (struct sockaddr *)
  539                                 &(((struct in6_ifreq *)data)->ifr_addr);
  540                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
  541                         break;
  542 #endif /* INET6 */
  543                 default:
  544                         error = EADDRNOTAVAIL;
  545                         goto bad;
  546                 }
  547                 if (src->sa_len > size)
  548                         return (EINVAL);
  549                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  550                 break;
  551 
  552         case SIOCGIFPDSTADDR:
  553 #ifdef INET6
  554         case SIOCGIFPDSTADDR_IN6:
  555 #endif /* INET6 */
  556                 if (sc->gif_pdst == NULL) {
  557                         error = EADDRNOTAVAIL;
  558                         goto bad;
  559                 }
  560                 src = sc->gif_pdst;
  561                 switch (cmd) {
  562 #ifdef INET
  563                 case SIOCGIFPDSTADDR:
  564                         dst = &ifr->ifr_addr;
  565                         size = sizeof(ifr->ifr_addr);
  566                         break;
  567 #endif /* INET */
  568 #ifdef INET6
  569                 case SIOCGIFPDSTADDR_IN6:
  570                         dst = (struct sockaddr *)
  571                                 &(((struct in6_ifreq *)data)->ifr_addr);
  572                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
  573                         break;
  574 #endif /* INET6 */
  575                 default:
  576                         error = EADDRNOTAVAIL;
  577                         goto bad;
  578                 }
  579                 if (src->sa_len > size)
  580                         return (EINVAL);
  581                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  582                 break;
  583 
  584         case SIOCGLIFPHYADDR:
  585                 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
  586                         error = EADDRNOTAVAIL;
  587                         goto bad;
  588                 }
  589 
  590                 /* copy src */
  591                 src = sc->gif_psrc;
  592                 dst = (struct sockaddr *)
  593                         &(((struct if_laddrreq *)data)->addr);
  594                 size = sizeof(((struct if_laddrreq *)data)->addr);
  595                 if (src->sa_len > size)
  596                         return (EINVAL);
  597                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  598 
  599                 /* copy dst */
  600                 src = sc->gif_pdst;
  601                 dst = (struct sockaddr *)
  602                         &(((struct if_laddrreq *)data)->dstaddr);
  603                 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
  604                 if (src->sa_len > size)
  605                         return (EINVAL);
  606                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  607                 break;
  608 
  609         case SIOCSIFFLAGS:
  610                 /* if_ioctl() takes care of it */
  611                 break;
  612 
  613         case SIOCSIFMTU:
  614                 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
  615                         error = EINVAL;
  616                 else
  617                         ifp->if_mtu = ifr->ifr_mtu;
  618                 break;
  619 
  620         default:
  621                 error = EINVAL;
  622                 break;
  623         }
  624  bad:
  625         return (error);
  626 }

/* [<][>][^][v][top][bottom][index][help] */