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_gre.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 /*      $NetBSD: if_gre.c,v 1.42 2002/08/14 00:23:27 itojun Exp $ */
    2 /*       $FreeBSD: releng/5.2/sys/net/if_gre.c 122699 2003-11-14 20:58:00Z bms $ */
    3 
    4 /*
    5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Heiko W.Rupp <hwr@pilhuhn.de>
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Encapsulate L3 protocols into IP
   42  * See RFC 1701 and 1702 for more details.
   43  * If_gre is compatible with Cisco GRE tunnels, so you can
   44  * have a NetBSD box as the other end of a tunnel interface of a Cisco
   45  * router. See gre(4) for more details.
   46  * Also supported:  IP in IP encaps (proto 55) as of RFC 2004
   47  */
   48 
   49 #include "opt_atalk.h"
   50 #include "opt_inet.h"
   51 #include "opt_inet6.h"
   52 
   53 #include <sys/param.h>
   54 #include <sys/kernel.h>
   55 #include <sys/malloc.h>
   56 #include <sys/mbuf.h>
   57 #include <sys/protosw.h>
   58 #include <sys/socket.h>
   59 #include <sys/sockio.h>
   60 #include <sys/sysctl.h>
   61 #include <sys/systm.h>
   62 
   63 #include <net/ethernet.h>
   64 #include <net/if.h>
   65 #include <net/if_types.h>
   66 #include <net/route.h>
   67 
   68 #ifdef INET
   69 #include <netinet/in.h>
   70 #include <netinet/in_systm.h>
   71 #include <netinet/in_var.h>
   72 #include <netinet/ip.h>
   73 #include <netinet/ip_gre.h>
   74 #include <netinet/ip_var.h>
   75 #include <netinet/ip_encap.h>
   76 #else
   77 #error "Huh? if_gre without inet?"
   78 #endif
   79 
   80 #include <net/bpf.h>
   81 
   82 #include <net/net_osdep.h>
   83 #include <net/if_gre.h>
   84 
   85 /*
   86  * It is not easy to calculate the right value for a GRE MTU.
   87  * We leave this task to the admin and use the same default that
   88  * other vendors use.
   89  */
   90 #define GREMTU  1476
   91 
   92 #define GRENAME "gre"
   93 
   94 static MALLOC_DEFINE(M_GRE, GRENAME, "Generic Routing Encapsulation");
   95 
   96 struct gre_softc_head gre_softc_list;
   97 
   98 static int      gre_clone_create(struct if_clone *, int);
   99 static void     gre_clone_destroy(struct ifnet *);
  100 static int      gre_ioctl(struct ifnet *, u_long, caddr_t);
  101 static int      gre_output(struct ifnet *, struct mbuf *, struct sockaddr *,
  102                     struct rtentry *rt);
  103 
  104 static struct if_clone gre_cloner =
  105     IF_CLONE_INITIALIZER("gre", gre_clone_create, gre_clone_destroy, 0, IF_MAXUNIT);
  106 
  107 static int gre_compute_route(struct gre_softc *sc);
  108 
  109 static void     greattach(void);
  110 
  111 #ifdef INET
  112 extern struct domain inetdomain;
  113 static const struct protosw in_gre_protosw =
  114 { SOCK_RAW,     &inetdomain,    IPPROTO_GRE,    PR_ATOMIC|PR_ADDR,
  115   (pr_input_t*)gre_input, (pr_output_t*)rip_output, rip_ctlinput, rip_ctloutput,
  116   0,
  117   0,            0,              0,              0,
  118   &rip_usrreqs
  119 };
  120 static const struct protosw in_mobile_protosw =
  121 { SOCK_RAW,     &inetdomain,    IPPROTO_MOBILE, PR_ATOMIC|PR_ADDR,
  122   (pr_input_t*)gre_mobile_input, (pr_output_t*)rip_output, rip_ctlinput, rip_ctloutput,
  123   0,
  124   0,            0,              0,              0,
  125   &rip_usrreqs
  126 };
  127 #endif
  128 
  129 SYSCTL_DECL(_net_link);
  130 SYSCTL_NODE(_net_link, IFT_OTHER, gre, CTLFLAG_RW, 0,
  131     "Generic Routing Encapsulation");
  132 #ifndef MAX_GRE_NEST
  133 /*
  134  * This macro controls the default upper limitation on nesting of gre tunnels.
  135  * Since, setting a large value to this macro with a careless configuration
  136  * may introduce system crash, we don't allow any nestings by default.
  137  * If you need to configure nested gre tunnels, you can define this macro
  138  * in your kernel configuration file.  However, if you do so, please be
  139  * careful to configure the tunnels so that it won't make a loop.
  140  */
  141 #define MAX_GRE_NEST 1
  142 #endif
  143 static int max_gre_nesting = MAX_GRE_NEST;
  144 SYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW,
  145     &max_gre_nesting, 0, "Max nested tunnels");
  146 
  147 /* ARGSUSED */
  148 static void
  149 greattach(void)
  150 {
  151 
  152         LIST_INIT(&gre_softc_list);
  153         if_clone_attach(&gre_cloner);
  154 }
  155 
  156 static int
  157 gre_clone_create(ifc, unit)
  158         struct if_clone *ifc;
  159         int unit;
  160 {
  161         struct gre_softc *sc;
  162 
  163         sc = malloc(sizeof(struct gre_softc), M_GRE, M_WAITOK);
  164         memset(sc, 0, sizeof(struct gre_softc));
  165 
  166         if_initname(&sc->sc_if, ifc->ifc_name, unit);
  167         sc->sc_if.if_softc = sc;
  168         sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
  169         sc->sc_if.if_type = IFT_OTHER;
  170         sc->sc_if.if_addrlen = 0;
  171         sc->sc_if.if_hdrlen = 24; /* IP + GRE */
  172         sc->sc_if.if_mtu = GREMTU;
  173         sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
  174         sc->sc_if.if_output = gre_output;
  175         sc->sc_if.if_ioctl = gre_ioctl;
  176         sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
  177         sc->g_proto = IPPROTO_GRE;
  178         sc->sc_if.if_flags |= IFF_LINK0;
  179         sc->encap = NULL;
  180         sc->called = 0;
  181         if_attach(&sc->sc_if);
  182         bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int32_t));
  183         LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
  184         return (0);
  185 }
  186 
  187 static void
  188 gre_clone_destroy(ifp)
  189         struct ifnet *ifp;
  190 {
  191         struct gre_softc *sc = ifp->if_softc;
  192 
  193 #ifdef INET
  194         if (sc->encap != NULL)
  195                 encap_detach(sc->encap);
  196 #endif
  197         LIST_REMOVE(sc, sc_list);
  198         bpfdetach(ifp);
  199         if_detach(ifp);
  200         free(sc, M_GRE);
  201 }
  202 
  203 /*
  204  * The output routine. Takes a packet and encapsulates it in the protocol
  205  * given by sc->g_proto. See also RFC 1701 and RFC 2004
  206  */
  207 static int
  208 gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
  209            struct rtentry *rt)
  210 {
  211         int error = 0;
  212         struct gre_softc *sc = ifp->if_softc;
  213         struct greip *gh;
  214         struct ip *ip;
  215         u_char osrc;
  216         u_short etype = 0;
  217         struct mobile_h mob_h;
  218 
  219         /*
  220          * gre may cause infinite recursion calls when misconfigured.
  221          * We'll prevent this by introducing upper limit.
  222          */
  223         if (++(sc->called) > max_gre_nesting) {
  224                 printf("%s: gre_output: recursively called too many "
  225                        "times(%d)\n", if_name(&sc->sc_if), sc->called);
  226                 m_freem(m);
  227                 error = EIO;    /* is there better errno? */
  228                 goto end;
  229         }
  230 
  231         if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 0 ||
  232             sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
  233                 m_freem(m);
  234                 error = ENETDOWN;
  235                 goto end;
  236         }
  237 
  238         gh = NULL;
  239         ip = NULL;
  240         osrc = 0;
  241 
  242         if (ifp->if_bpf) {
  243                 /* see comment of other if_foo.c files */
  244                 struct mbuf m0;
  245                 u_int32_t af = dst->sa_family;
  246 
  247                 m0.m_next = m;
  248                 m0.m_len = 4;
  249                 m0.m_data = (char *)&af;
  250 
  251                 BPF_MTAP(ifp, &m0);
  252         }
  253 
  254         m->m_flags &= ~(M_BCAST|M_MCAST);
  255 
  256         if (sc->g_proto == IPPROTO_MOBILE) {
  257                 if (dst->sa_family == AF_INET) {
  258                         struct mbuf *m0;
  259                         int msiz;
  260 
  261                         ip = mtod(m, struct ip *);
  262 
  263                         /*
  264                          * RFC2004 specifies that fragmented diagrams shouldn't
  265                          * be encapsulated.
  266                          */
  267                         if ((ip->ip_off & IP_MF) != 0) {
  268                                 _IF_DROP(&ifp->if_snd);
  269                                 m_freem(m);
  270                                 error = EINVAL;    /* is there better errno? */
  271                                 goto end;
  272                         }
  273                         memset(&mob_h, 0, MOB_H_SIZ_L);
  274                         mob_h.proto = (ip->ip_p) << 8;
  275                         mob_h.odst = ip->ip_dst.s_addr;
  276                         ip->ip_dst.s_addr = sc->g_dst.s_addr;
  277 
  278                         /*
  279                          * If the packet comes from our host, we only change
  280                          * the destination address in the IP header.
  281                          * Else we also need to save and change the source
  282                          */
  283                         if (in_hosteq(ip->ip_src, sc->g_src)) {
  284                                 msiz = MOB_H_SIZ_S;
  285                         } else {
  286                                 mob_h.proto |= MOB_H_SBIT;
  287                                 mob_h.osrc = ip->ip_src.s_addr;
  288                                 ip->ip_src.s_addr = sc->g_src.s_addr;
  289                                 msiz = MOB_H_SIZ_L;
  290                         }
  291                         mob_h.proto = htons(mob_h.proto);
  292                         mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz);
  293 
  294                         if ((m->m_data - msiz) < m->m_pktdat) {
  295                                 /* need new mbuf */
  296                                 MGETHDR(m0, M_DONTWAIT, MT_HEADER);
  297                                 if (m0 == NULL) {
  298                                         _IF_DROP(&ifp->if_snd);
  299                                         m_freem(m);
  300                                         error = ENOBUFS;
  301                                         goto end;
  302                                 }
  303                                 m0->m_next = m;
  304                                 m->m_data += sizeof(struct ip);
  305                                 m->m_len -= sizeof(struct ip);
  306                                 m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
  307                                 m0->m_len = msiz + sizeof(struct ip);
  308                                 m0->m_data += max_linkhdr;
  309                                 memcpy(mtod(m0, caddr_t), (caddr_t)ip,
  310                                        sizeof(struct ip));
  311                                 m = m0;
  312                         } else {  /* we have some space left in the old one */
  313                                 m->m_data -= msiz;
  314                                 m->m_len += msiz;
  315                                 m->m_pkthdr.len += msiz;
  316                                 bcopy(ip, mtod(m, caddr_t),
  317                                         sizeof(struct ip));
  318                         }
  319                         ip = mtod(m, struct ip *);
  320                         memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz);
  321                         ip->ip_len = ntohs(ip->ip_len) + msiz;
  322                 } else {  /* AF_INET */
  323                         _IF_DROP(&ifp->if_snd);
  324                         m_freem(m);
  325                         error = EINVAL;
  326                         goto end;
  327                 }
  328         } else if (sc->g_proto == IPPROTO_GRE) {
  329                 switch (dst->sa_family) {
  330                 case AF_INET:
  331                         ip = mtod(m, struct ip *);
  332                         etype = ETHERTYPE_IP;
  333                         break;
  334 #ifdef NETATALK
  335                 case AF_APPLETALK:
  336                         etype = ETHERTYPE_ATALK;
  337                         break;
  338 #endif
  339                 default:
  340                         _IF_DROP(&ifp->if_snd);
  341                         m_freem(m);
  342                         error = EAFNOSUPPORT;
  343                         goto end;
  344                 }
  345                 M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
  346         } else {
  347                 _IF_DROP(&ifp->if_snd);
  348                 m_freem(m);
  349                 error = EINVAL;
  350                 goto end;
  351         }
  352 
  353         if (m == NULL) {        /* impossible */
  354                 _IF_DROP(&ifp->if_snd);
  355                 error = ENOBUFS;
  356                 goto end;
  357         }
  358 
  359         gh = mtod(m, struct greip *);
  360         if (sc->g_proto == IPPROTO_GRE) {
  361                 /* we don't have any GRE flags for now */
  362 
  363                 memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
  364                 gh->gi_ptype = htons(etype);
  365         }
  366 
  367         gh->gi_pr = sc->g_proto;
  368         if (sc->g_proto != IPPROTO_MOBILE) {
  369                 gh->gi_src = sc->g_src;
  370                 gh->gi_dst = sc->g_dst;
  371                 ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
  372                 ((struct ip*)gh)->ip_ttl = GRE_TTL;
  373                 ((struct ip*)gh)->ip_tos = ip->ip_tos;
  374                 ((struct ip*)gh)->ip_id = ip->ip_id;
  375                 gh->gi_len = m->m_pkthdr.len;
  376         }
  377 
  378         ifp->if_opackets++;
  379         ifp->if_obytes += m->m_pkthdr.len;
  380         /* send it off */
  381         error = ip_output(m, NULL, &sc->route, 0, NULL, NULL);
  382   end:
  383         sc->called = 0;
  384         if (error)
  385                 ifp->if_oerrors++;
  386         return (error);
  387 }
  388 
  389 static int
  390 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  391 {
  392         struct ifreq *ifr = (struct ifreq *)data;
  393         struct if_laddrreq *lifr = (struct if_laddrreq *)data;
  394         struct in_aliasreq *aifr = (struct in_aliasreq *)data;
  395         struct gre_softc *sc = ifp->if_softc;
  396         int s;
  397         struct sockaddr_in si;
  398         struct sockaddr *sa = NULL;
  399         int error;
  400         struct sockaddr_in sp, sm, dp, dm;
  401 
  402         error = 0;
  403 
  404         s = splnet();
  405         switch (cmd) {
  406         case SIOCSIFADDR:
  407                 ifp->if_flags |= IFF_UP;
  408                 break;
  409         case SIOCSIFDSTADDR: 
  410                 break;
  411         case SIOCSIFFLAGS:
  412                 if ((error = suser(curthread)) != 0)
  413                         break;
  414                 if ((ifr->ifr_flags & IFF_LINK0) != 0)
  415                         sc->g_proto = IPPROTO_GRE;
  416                 else
  417                         sc->g_proto = IPPROTO_MOBILE;
  418                 goto recompute;
  419         case SIOCSIFMTU:
  420                 if ((error = suser(curthread)) != 0)
  421                         break;
  422                 if (ifr->ifr_mtu < 576) {
  423                         error = EINVAL;
  424                         break;
  425                 }
  426                 ifp->if_mtu = ifr->ifr_mtu;
  427                 break;
  428         case SIOCGIFMTU:
  429                 ifr->ifr_mtu = sc->sc_if.if_mtu;
  430                 break;
  431         case SIOCADDMULTI:
  432         case SIOCDELMULTI:
  433                 if ((error = suser(curthread)) != 0)
  434                         break;
  435                 if (ifr == 0) {
  436                         error = EAFNOSUPPORT;
  437                         break;
  438                 }
  439                 switch (ifr->ifr_addr.sa_family) {
  440 #ifdef INET
  441                 case AF_INET:
  442                         break;
  443 #endif
  444                 default:
  445                         error = EAFNOSUPPORT;
  446                         break;
  447                 }
  448                 break;
  449         case GRESPROTO:
  450                 if ((error = suser(curthread)) != 0)
  451                         break;
  452                 sc->g_proto = ifr->ifr_flags;
  453                 switch (sc->g_proto) {
  454                 case IPPROTO_GRE:
  455                         ifp->if_flags |= IFF_LINK0;
  456                         break;
  457                 case IPPROTO_MOBILE:
  458                         ifp->if_flags &= ~IFF_LINK0;
  459                         break;
  460                 default:
  461                         error = EPROTONOSUPPORT;
  462                         break;
  463                 }
  464                 goto recompute;
  465         case GREGPROTO:
  466                 ifr->ifr_flags = sc->g_proto;
  467                 break;
  468         case GRESADDRS:
  469         case GRESADDRD:
  470                 if ((error = suser(curthread)) != 0)
  471                         break;
  472                 /*
  473                  * set tunnel endpoints, compute a less specific route
  474                  * to the remote end and mark if as up
  475                  */
  476                 sa = &ifr->ifr_addr;
  477                 if (cmd == GRESADDRS)
  478                         sc->g_src = (satosin(sa))->sin_addr;
  479                 if (cmd == GRESADDRD)
  480                         sc->g_dst = (satosin(sa))->sin_addr;
  481         recompute:
  482 #ifdef INET
  483                 if (sc->encap != NULL) {
  484                         encap_detach(sc->encap);
  485                         sc->encap = NULL;
  486                 }
  487 #endif
  488                 if ((sc->g_src.s_addr != INADDR_ANY) &&
  489                     (sc->g_dst.s_addr != INADDR_ANY)) {
  490                         bzero(&sp, sizeof(sp));
  491                         bzero(&sm, sizeof(sm));
  492                         bzero(&dp, sizeof(dp));
  493                         bzero(&dm, sizeof(dm));
  494                         sp.sin_len = sm.sin_len = dp.sin_len = dm.sin_len =
  495                             sizeof(struct sockaddr_in);
  496                         sp.sin_family = sm.sin_family = dp.sin_family =
  497                             dm.sin_family = AF_INET;
  498                         sp.sin_addr = sc->g_src;
  499                         dp.sin_addr = sc->g_dst;
  500                         sm.sin_addr.s_addr = dm.sin_addr.s_addr = 
  501                             INADDR_BROADCAST;
  502 #ifdef INET
  503                         sc->encap = encap_attach(AF_INET, sc->g_proto,
  504                             sintosa(&sp), sintosa(&sm), sintosa(&dp),
  505                             sintosa(&dm), (sc->g_proto == IPPROTO_GRE) ?
  506                                 &in_gre_protosw : &in_mobile_protosw, sc);
  507                         if (sc->encap == NULL)
  508                                 printf("%s: unable to attach encap\n",
  509                                     if_name(&sc->sc_if));
  510 #endif
  511                         if (sc->route.ro_rt != 0) /* free old route */
  512                                 RTFREE(sc->route.ro_rt);
  513                         if (gre_compute_route(sc) == 0)
  514                                 ifp->if_flags |= IFF_RUNNING;
  515                         else
  516                                 ifp->if_flags &= ~IFF_RUNNING;
  517                 }
  518                 break;
  519         case GREGADDRS:
  520                 memset(&si, 0, sizeof(si));
  521                 si.sin_family = AF_INET;
  522                 si.sin_len = sizeof(struct sockaddr_in);
  523                 si.sin_addr.s_addr = sc->g_src.s_addr;
  524                 sa = sintosa(&si);
  525                 ifr->ifr_addr = *sa;
  526                 break;
  527         case GREGADDRD:
  528                 memset(&si, 0, sizeof(si));
  529                 si.sin_family = AF_INET;
  530                 si.sin_len = sizeof(struct sockaddr_in);
  531                 si.sin_addr.s_addr = sc->g_dst.s_addr;
  532                 sa = sintosa(&si);
  533                 ifr->ifr_addr = *sa;
  534                 break;
  535         case SIOCSIFPHYADDR:
  536                 if ((error = suser(curthread)) != 0)
  537                         break;
  538                 if (aifr->ifra_addr.sin_family != AF_INET ||
  539                     aifr->ifra_dstaddr.sin_family != AF_INET) {
  540                         error = EAFNOSUPPORT;
  541                         break;
  542                 }
  543                 if (aifr->ifra_addr.sin_len != sizeof(si) ||
  544                     aifr->ifra_dstaddr.sin_len != sizeof(si)) {
  545                         error = EINVAL;
  546                         break;
  547                 }
  548                 sc->g_src = aifr->ifra_addr.sin_addr;
  549                 sc->g_dst = aifr->ifra_dstaddr.sin_addr;
  550                 goto recompute;
  551         case SIOCSLIFPHYADDR:
  552                 if ((error = suser(curthread)) != 0)
  553                         break;
  554                 if (lifr->addr.ss_family != AF_INET ||
  555                     lifr->dstaddr.ss_family != AF_INET) {
  556                         error = EAFNOSUPPORT;
  557                         break;
  558                 }
  559                 if (lifr->addr.ss_len != sizeof(si) ||
  560                     lifr->dstaddr.ss_len != sizeof(si)) {
  561                         error = EINVAL;
  562                         break;
  563                 }
  564                 sc->g_src = (satosin((struct sockadrr *)&lifr->addr))->sin_addr;
  565                 sc->g_dst =
  566                     (satosin((struct sockadrr *)&lifr->dstaddr))->sin_addr;
  567                 goto recompute;
  568         case SIOCDIFPHYADDR:
  569                 if ((error = suser(curthread)) != 0)
  570                         break;
  571                 sc->g_src.s_addr = INADDR_ANY;
  572                 sc->g_dst.s_addr = INADDR_ANY;
  573                 goto recompute;
  574         case SIOCGLIFPHYADDR:
  575                 if (sc->g_src.s_addr == INADDR_ANY ||
  576                     sc->g_dst.s_addr == INADDR_ANY) {
  577                         error = EADDRNOTAVAIL;
  578                         break;
  579                 }
  580                 memset(&si, 0, sizeof(si));
  581                 si.sin_family = AF_INET;
  582                 si.sin_len = sizeof(struct sockaddr_in);
  583                 si.sin_addr.s_addr = sc->g_src.s_addr;
  584                 memcpy(&lifr->addr, &si, sizeof(si));
  585                 si.sin_addr.s_addr = sc->g_dst.s_addr;
  586                 memcpy(&lifr->dstaddr, &si, sizeof(si));
  587                 break;
  588         case SIOCGIFPSRCADDR:
  589 #ifdef INET6
  590         case SIOCGIFPSRCADDR_IN6:
  591 #endif
  592                 if (sc->g_src.s_addr == INADDR_ANY) {
  593                         error = EADDRNOTAVAIL;
  594                         break;
  595                 }
  596                 memset(&si, 0, sizeof(si));
  597                 si.sin_family = AF_INET;
  598                 si.sin_len = sizeof(struct sockaddr_in);
  599                 si.sin_addr.s_addr = sc->g_src.s_addr;
  600                 bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
  601                 break;
  602         case SIOCGIFPDSTADDR:
  603 #ifdef INET6
  604         case SIOCGIFPDSTADDR_IN6:
  605 #endif
  606                 if (sc->g_dst.s_addr == INADDR_ANY) {
  607                         error = EADDRNOTAVAIL;
  608                         break;
  609                 }
  610                 memset(&si, 0, sizeof(si));
  611                 si.sin_family = AF_INET;
  612                 si.sin_len = sizeof(struct sockaddr_in);
  613                 si.sin_addr.s_addr = sc->g_dst.s_addr;
  614                 bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
  615                 break;
  616         default:
  617                 error = EINVAL;
  618                 break;
  619         }
  620 
  621         splx(s);
  622         return (error);
  623 }
  624 
  625 /*
  626  * computes a route to our destination that is not the one
  627  * which would be taken by ip_output(), as this one will loop back to
  628  * us. If the interface is p2p as  a--->b, then a routing entry exists
  629  * If we now send a packet to b (e.g. ping b), this will come down here
  630  * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
  631  * if_gre.
  632  * Goal here is to compute a route to b that is less specific than
  633  * a-->b. We know that this one exists as in normal operation we have
  634  * at least a default route which matches.
  635  */
  636 static int
  637 gre_compute_route(struct gre_softc *sc)
  638 {
  639         struct route *ro;
  640         u_int32_t a, b, c;
  641 
  642         ro = &sc->route;
  643 
  644         memset(ro, 0, sizeof(struct route));
  645         ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
  646         ro->ro_dst.sa_family = AF_INET;
  647         ro->ro_dst.sa_len = sizeof(ro->ro_dst);
  648 
  649         /*
  650          * toggle last bit, so our interface is not found, but a less
  651          * specific route. I'd rather like to specify a shorter mask,
  652          * but this is not possible. Should work though. XXX
  653          * there is a simpler way ...
  654          */
  655         if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
  656                 a = ntohl(sc->g_dst.s_addr);
  657                 b = a & 0x01;
  658                 c = a & 0xfffffffe;
  659                 b = b ^ 0x01;
  660                 a = b | c;
  661                 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
  662                     = htonl(a);
  663         }
  664 
  665 #ifdef DIAGNOSTIC
  666         printf("%s: searching a route to %s", if_name(&sc->sc_if),
  667             inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr));
  668 #endif
  669 
  670         rtalloc(ro);
  671 
  672         /*
  673          * check if this returned a route at all and this route is no
  674          * recursion to ourself
  675          */
  676         if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp->if_softc == sc) {
  677 #ifdef DIAGNOSTIC
  678                 if (ro->ro_rt == NULL)
  679                         printf(" - no route found!\n");
  680                 else
  681                         printf(" - route loops back to ourself!\n");
  682 #endif
  683                 return EADDRNOTAVAIL;
  684         }
  685 
  686         /*
  687          * now change it back - else ip_output will just drop
  688          * the route and search one to this interface ...
  689          */
  690         if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
  691                 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
  692 
  693 #ifdef DIAGNOSTIC
  694         printf(", choosing %s with gateway %s", if_name(ro->ro_rt->rt_ifp),
  695             inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr));
  696         printf("\n");
  697 #endif
  698 
  699         return 0;
  700 }
  701 
  702 /*
  703  * do a checksum of a buffer - much like in_cksum, which operates on
  704  * mbufs.
  705  */
  706 u_short
  707 gre_in_cksum(u_short *p, u_int len)
  708 {
  709         u_int sum = 0;
  710         int nwords = len >> 1;
  711 
  712         while (nwords-- != 0)
  713                 sum += *p++;
  714 
  715         if (len & 1) {
  716                 union {
  717                         u_short w;
  718                         u_char c[2];
  719                 } u;
  720                 u.c[0] = *(u_char *)p;
  721                 u.c[1] = 0;
  722                 sum += u.w;
  723         }
  724 
  725         /* end-around-carry */
  726         sum = (sum >> 16) + (sum & 0xffff);
  727         sum += (sum >> 16);
  728         return (~sum);
  729 }
  730 
  731 static int
  732 gremodevent(module_t mod, int type, void *data)
  733 {
  734 
  735         switch (type) {
  736         case MOD_LOAD:
  737                 greattach();
  738                 break;
  739         case MOD_UNLOAD:
  740                 if_clone_detach(&gre_cloner);
  741 
  742                 while (!LIST_EMPTY(&gre_softc_list))
  743                         gre_clone_destroy(&LIST_FIRST(&gre_softc_list)->sc_if);
  744                 break;
  745         }
  746         return 0;
  747 }
  748 
  749 static moduledata_t gre_mod = {
  750         "if_gre",
  751         gremodevent,
  752         0
  753 };
  754 
  755 DECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
  756 MODULE_VERSION(if_gre, 1);

Cache object: f285a5c0336c80c66bef8cf9415a609c


[ 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.