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.49.2.1 2004/05/20 12:24:05 grant Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Heiko W.Rupp <hwr@pilhuhn.de>
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * Encapsulate L3 protocols into IP
   41  * See RFC 1701 and 1702 for more details.
   42  * If_gre is compatible with Cisco GRE tunnels, so you can
   43  * have a NetBSD box as the other end of a tunnel interface of a Cisco
   44  * router. See gre(4) for more details.
   45  * Also supported:  IP in IP encaps (proto 55) as of RFC 2004
   46  */
   47 
   48 #include <sys/cdefs.h>
   49 __KERNEL_RCSID(0, "$NetBSD: if_gre.c,v 1.49.2.1 2004/05/20 12:24:05 grant Exp $");
   50 
   51 #include "opt_inet.h"
   52 #include "opt_ns.h"
   53 #include "bpfilter.h"
   54 
   55 #include <sys/param.h>
   56 #include <sys/malloc.h>
   57 #include <sys/mbuf.h>
   58 #include <sys/proc.h>
   59 #include <sys/protosw.h>
   60 #include <sys/socket.h>
   61 #include <sys/ioctl.h>
   62 #include <sys/queue.h>
   63 #if __NetBSD__
   64 #include <sys/systm.h>
   65 #endif
   66 
   67 #include <machine/cpu.h>
   68 
   69 #include <net/ethertypes.h>
   70 #include <net/if.h>
   71 #include <net/if_types.h>
   72 #include <net/netisr.h>
   73 #include <net/route.h>
   74 
   75 #ifdef INET
   76 #include <netinet/in.h>
   77 #include <netinet/in_systm.h>
   78 #include <netinet/in_var.h>
   79 #include <netinet/ip.h>
   80 #include <netinet/ip_var.h>
   81 #else
   82 #error "Huh? if_gre without inet?"
   83 #endif
   84 
   85 #ifdef NS
   86 #include <netns/ns.h>
   87 #include <netns/ns_if.h>
   88 #endif
   89 
   90 #ifdef NETATALK
   91 #include <netatalk/at.h>
   92 #include <netatalk/at_var.h>
   93 #include <netatalk/at_extern.h>
   94 #endif
   95 
   96 #if NBPFILTER > 0
   97 #include <sys/time.h>
   98 #include <net/bpf.h>
   99 #endif
  100 
  101 #include <net/if_gre.h>
  102 
  103 /*
  104  * It is not easy to calculate the right value for a GRE MTU.
  105  * We leave this task to the admin and use the same default that
  106  * other vendors use.
  107  */
  108 #define GREMTU 1476
  109 
  110 struct gre_softc_head gre_softc_list;
  111 int ip_gre_ttl = GRE_TTL;
  112 
  113 int     gre_clone_create __P((struct if_clone *, int));
  114 void    gre_clone_destroy __P((struct ifnet *));
  115 
  116 struct if_clone gre_cloner =
  117     IF_CLONE_INITIALIZER("gre", gre_clone_create, gre_clone_destroy);
  118 
  119 int gre_compute_route(struct gre_softc *sc);
  120 
  121 void    greattach __P((int));
  122 
  123 /* ARGSUSED */
  124 void
  125 greattach(count)
  126         int count;
  127 {
  128 
  129         LIST_INIT(&gre_softc_list);
  130         if_clone_attach(&gre_cloner);
  131 }
  132 
  133 int
  134 gre_clone_create(ifc, unit)
  135         struct if_clone *ifc;
  136         int unit;
  137 {
  138         struct gre_softc *sc;
  139 
  140         sc = malloc(sizeof(struct gre_softc), M_DEVBUF, M_WAITOK);
  141         memset(sc, 0, sizeof(struct gre_softc));
  142 
  143         sprintf(sc->sc_if.if_xname, "%s%d", ifc->ifc_name, unit);
  144         sc->sc_if.if_softc = sc;
  145         sc->sc_if.if_type = IFT_TUNNEL;
  146         sc->sc_if.if_addrlen = 0;
  147         sc->sc_if.if_hdrlen = 24; /* IP + GRE */
  148         sc->sc_if.if_dlt = DLT_NULL;
  149         sc->sc_if.if_mtu = GREMTU;
  150         sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
  151         sc->sc_if.if_output = gre_output;
  152         sc->sc_if.if_ioctl = gre_ioctl;
  153         sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
  154         sc->g_proto = IPPROTO_GRE;
  155         sc->sc_if.if_flags |= IFF_LINK0;
  156         if_attach(&sc->sc_if);
  157         if_alloc_sadl(&sc->sc_if);
  158 #if NBPFILTER > 0
  159         bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int32_t));
  160 #endif
  161         LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
  162         return (0);
  163 }
  164 
  165 void
  166 gre_clone_destroy(ifp)
  167         struct ifnet *ifp;
  168 {
  169         struct gre_softc *sc = ifp->if_softc;
  170 
  171         LIST_REMOVE(sc, sc_list);
  172 #if NBPFILTER > 0
  173         bpfdetach(ifp);
  174 #endif
  175         if_detach(ifp);
  176         free(sc, M_DEVBUF);
  177 }
  178 
  179 /*
  180  * The output routine. Takes a packet and encapsulates it in the protocol
  181  * given by sc->g_proto. See also RFC 1701 and RFC 2004
  182  */
  183 int
  184 gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
  185            struct rtentry *rt)
  186 {
  187         int error = 0;
  188         struct gre_softc *sc = ifp->if_softc;
  189         struct greip *gh;
  190         struct ip *ip;
  191         u_int16_t etype = 0;
  192         struct mobile_h mob_h;
  193 
  194         if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 0 ||
  195             sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
  196                 m_freem(m);
  197                 error = ENETDOWN;
  198                 goto end;
  199         }
  200 
  201         gh = NULL;
  202         ip = NULL;
  203 
  204 #if NBPFILTER >0
  205         if (ifp->if_bpf) {
  206                 /* see comment of other if_foo.c files */
  207                 struct mbuf m0;
  208                 u_int32_t af = dst->sa_family;
  209 
  210                 m0.m_next = m;
  211                 m0.m_len = 4;
  212                 m0.m_data = (char *)&af;
  213 
  214                 bpf_mtap(ifp->if_bpf, &m0);
  215         }
  216 #endif
  217 
  218         m->m_flags &= ~(M_BCAST|M_MCAST);
  219 
  220         if (sc->g_proto == IPPROTO_MOBILE) {
  221                 if (dst->sa_family == AF_INET) {
  222                         struct mbuf *m0;
  223                         int msiz;
  224 
  225                         ip = mtod(m, struct ip *);
  226 
  227                         memset(&mob_h, 0, MOB_H_SIZ_L);
  228                         mob_h.proto = (ip->ip_p) << 8;
  229                         mob_h.odst = ip->ip_dst.s_addr;
  230                         ip->ip_dst.s_addr = sc->g_dst.s_addr;
  231 
  232                         /*
  233                          * If the packet comes from our host, we only change
  234                          * the destination address in the IP header.
  235                          * Else we also need to save and change the source
  236                          */
  237                         if (in_hosteq(ip->ip_src, sc->g_src)) {
  238                                 msiz = MOB_H_SIZ_S;
  239                         } else {
  240                                 mob_h.proto |= MOB_H_SBIT;
  241                                 mob_h.osrc = ip->ip_src.s_addr;
  242                                 ip->ip_src.s_addr = sc->g_src.s_addr;
  243                                 msiz = MOB_H_SIZ_L;
  244                         }
  245                         HTONS(mob_h.proto);
  246                         mob_h.hcrc = gre_in_cksum((u_int16_t *)&mob_h, msiz);
  247 
  248                         if ((m->m_data - msiz) < m->m_pktdat) {
  249                                 /* need new mbuf */
  250                                 MGETHDR(m0, M_DONTWAIT, MT_HEADER);
  251                                 if (m0 == NULL) {
  252                                         IF_DROP(&ifp->if_snd);
  253                                         m_freem(m);
  254                                         error = ENOBUFS;
  255                                         goto end;
  256                                 }
  257                                 m0->m_next = m;
  258                                 m->m_data += sizeof(struct ip);
  259                                 m->m_len -= sizeof(struct ip);
  260                                 m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
  261                                 m0->m_len = msiz + sizeof(struct ip);
  262                                 m0->m_data += max_linkhdr;
  263                                 memcpy(mtod(m0, caddr_t), (caddr_t)ip,
  264                                        sizeof(struct ip));
  265                                 m = m0;
  266                         } else {  /* we have some space left in the old one */
  267                                 m->m_data -= msiz;
  268                                 m->m_len += msiz;
  269                                 m->m_pkthdr.len += msiz;
  270                                 memmove(mtod(m, caddr_t), ip,
  271                                         sizeof(struct ip));
  272                         }
  273                         ip = mtod(m, struct ip *);
  274                         memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz);
  275                         ip->ip_len = htons(ntohs(ip->ip_len) + msiz);
  276                 } else {  /* AF_INET */
  277                         IF_DROP(&ifp->if_snd);
  278                         m_freem(m);
  279                         error = EINVAL;
  280                         goto end;
  281                 }
  282         } else if (sc->g_proto == IPPROTO_GRE) {
  283                 switch (dst->sa_family) {
  284                 case AF_INET:
  285                         ip = mtod(m, struct ip *);
  286                         etype = ETHERTYPE_IP;
  287                         break;
  288 #ifdef NETATALK
  289                 case AF_APPLETALK:
  290                         etype = ETHERTYPE_ATALK;
  291                         break;
  292 #endif
  293 #ifdef NS
  294                 case AF_NS:
  295                         etype = ETHERTYPE_NS;
  296                         break;
  297 #endif
  298                 default:
  299                         IF_DROP(&ifp->if_snd);
  300                         m_freem(m);
  301                         error = EAFNOSUPPORT;
  302                         goto end;
  303                 }
  304                 M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
  305         } else {
  306                 IF_DROP(&ifp->if_snd);
  307                 m_freem(m);
  308                 error = EINVAL;
  309                 goto end;
  310         }
  311 
  312         if (m == NULL) {        /* impossible */
  313                 IF_DROP(&ifp->if_snd);
  314                 error = ENOBUFS;
  315                 goto end;
  316         }
  317 
  318         gh = mtod(m, struct greip *);
  319         if (sc->g_proto == IPPROTO_GRE) {
  320                 /* we don't have any GRE flags for now */
  321 
  322                 memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
  323                 gh->gi_ptype = htons(etype);
  324         }
  325 
  326         gh->gi_pr = sc->g_proto;
  327         if (sc->g_proto != IPPROTO_MOBILE) {
  328                 gh->gi_src = sc->g_src;
  329                 gh->gi_dst = sc->g_dst;
  330                 ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
  331                 ((struct ip*)gh)->ip_ttl = ip_gre_ttl;
  332                 ((struct ip*)gh)->ip_tos = ip->ip_tos;
  333                 gh->gi_len = htons(m->m_pkthdr.len);
  334         }
  335 
  336         ifp->if_opackets++;
  337         ifp->if_obytes += m->m_pkthdr.len;
  338         /* send it off */
  339         error = ip_output(m, NULL, &sc->route, 0,
  340             (struct ip_moptions *)NULL, (struct socket *)NULL);
  341   end:
  342         if (error)
  343                 ifp->if_oerrors++;
  344         return (error);
  345 }
  346 
  347 int
  348 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  349 {
  350         struct proc *p = curproc;       /* XXX */
  351         struct ifreq *ifr = (struct ifreq *)data;
  352         struct if_laddrreq *lifr = (struct if_laddrreq *)data;
  353         struct gre_softc *sc = ifp->if_softc;
  354         int s;
  355         struct sockaddr_in si;
  356         struct sockaddr *sa = NULL;
  357         int error;
  358 
  359         error = 0;
  360 
  361         s = splnet();
  362         switch (cmd) {
  363         case SIOCSIFADDR:
  364                 ifp->if_flags |= IFF_UP;
  365                 break;
  366         case SIOCSIFDSTADDR: 
  367                 break;
  368         case SIOCSIFFLAGS:
  369                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  370                         break;
  371                 if ((ifr->ifr_flags & IFF_LINK0) != 0)
  372                         sc->g_proto = IPPROTO_GRE;
  373                 else
  374                         sc->g_proto = IPPROTO_MOBILE;
  375                 break;
  376         case SIOCSIFMTU:
  377                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  378                         break;
  379                 if (ifr->ifr_mtu < 576) {
  380                         error = EINVAL;
  381                         break;
  382                 }
  383                 ifp->if_mtu = ifr->ifr_mtu;
  384                 break;
  385         case SIOCGIFMTU:
  386                 ifr->ifr_mtu = sc->sc_if.if_mtu;
  387                 break;
  388         case SIOCADDMULTI:
  389         case SIOCDELMULTI:
  390                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  391                         break;
  392                 if (ifr == 0) {
  393                         error = EAFNOSUPPORT;
  394                         break;
  395                 }
  396                 switch (ifr->ifr_addr.sa_family) {
  397 #ifdef INET
  398                 case AF_INET:
  399                         break;
  400 #endif
  401                 default:
  402                         error = EAFNOSUPPORT;
  403                         break;
  404                 }
  405                 break;
  406         case GRESPROTO:
  407                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  408                         break;
  409                 sc->g_proto = ifr->ifr_flags;
  410                 switch (sc->g_proto) {
  411                 case IPPROTO_GRE:
  412                         ifp->if_flags |= IFF_LINK0;
  413                         break;
  414                 case IPPROTO_MOBILE:
  415                         ifp->if_flags &= ~IFF_LINK0;
  416                         break;
  417                 default:
  418                         error = EPROTONOSUPPORT;
  419                         break;
  420                 }
  421                 break;
  422         case GREGPROTO:
  423                 ifr->ifr_flags = sc->g_proto;
  424                 break;
  425         case GRESADDRS:
  426         case GRESADDRD:
  427                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  428                         break;
  429                 /*
  430                  * set tunnel endpoints, compute a less specific route
  431                  * to the remote end and mark if as up
  432                  */
  433                 sa = &ifr->ifr_addr;
  434                 if (cmd == GRESADDRS)
  435                         sc->g_src = (satosin(sa))->sin_addr;
  436                 if (cmd == GRESADDRD)
  437                         sc->g_dst = (satosin(sa))->sin_addr;
  438         recompute:
  439                 if ((sc->g_src.s_addr != INADDR_ANY) &&
  440                     (sc->g_dst.s_addr != INADDR_ANY)) {
  441                         if (sc->route.ro_rt != 0) /* free old route */
  442                                 RTFREE(sc->route.ro_rt);
  443                         if (gre_compute_route(sc) == 0)
  444                                 ifp->if_flags |= IFF_RUNNING;
  445                         else
  446                                 ifp->if_flags &= ~IFF_RUNNING;
  447                 }
  448                 break;
  449         case GREGADDRS:
  450                 memset(&si, 0, sizeof(si));
  451                 si.sin_family = AF_INET;
  452                 si.sin_len = sizeof(struct sockaddr_in);
  453                 si.sin_addr.s_addr = sc->g_src.s_addr;
  454                 sa = sintosa(&si);
  455                 ifr->ifr_addr = *sa;
  456                 break;
  457         case GREGADDRD:
  458                 memset(&si, 0, sizeof(si));
  459                 si.sin_family = AF_INET;
  460                 si.sin_len = sizeof(struct sockaddr_in);
  461                 si.sin_addr.s_addr = sc->g_dst.s_addr;
  462                 sa = sintosa(&si);
  463                 ifr->ifr_addr = *sa;
  464                 break;
  465         case SIOCSLIFPHYADDR:
  466                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  467                         break;
  468                 if (lifr->addr.ss_family != AF_INET ||
  469                     lifr->dstaddr.ss_family != AF_INET) {
  470                         error = EAFNOSUPPORT;
  471                         break;
  472                 }
  473                 if (lifr->addr.ss_len != sizeof(si) ||
  474                     lifr->dstaddr.ss_len != sizeof(si)) {
  475                         error = EINVAL;
  476                         break;
  477                 }
  478                 sc->g_src = (satosin((struct sockadrr *)&lifr->addr))->sin_addr;
  479                 sc->g_dst =
  480                     (satosin((struct sockadrr *)&lifr->dstaddr))->sin_addr;
  481                 goto recompute;
  482         case SIOCDIFPHYADDR:
  483                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  484                         break;
  485                 sc->g_src.s_addr = INADDR_ANY;
  486                 sc->g_dst.s_addr = INADDR_ANY;
  487                 break;
  488         case SIOCGLIFPHYADDR:
  489                 if (sc->g_src.s_addr == INADDR_ANY ||
  490                     sc->g_dst.s_addr == INADDR_ANY) {
  491                         error = EADDRNOTAVAIL;
  492                         break;
  493                 }
  494                 memset(&si, 0, sizeof(si));
  495                 si.sin_family = AF_INET;
  496                 si.sin_len = sizeof(struct sockaddr_in);
  497                 si.sin_addr.s_addr = sc->g_src.s_addr;
  498                 memcpy(&lifr->addr, &si, sizeof(si));
  499                 si.sin_addr.s_addr = sc->g_dst.s_addr;
  500                 memcpy(&lifr->dstaddr, &si, sizeof(si));
  501                 break;
  502         default:
  503                 error = EINVAL;
  504                 break;
  505         }
  506 
  507         splx(s);
  508         return (error);
  509 }
  510 
  511 /*
  512  * computes a route to our destination that is not the one
  513  * which would be taken by ip_output(), as this one will loop back to
  514  * us. If the interface is p2p as  a--->b, then a routing entry exists
  515  * If we now send a packet to b (e.g. ping b), this will come down here
  516  * gets src=a, dst=b tacked on and would from ip_output() sent back to
  517  * if_gre.
  518  * Goal here is to compute a route to b that is less specific than
  519  * a-->b. We know that this one exists as in normal operation we have
  520  * at least a default route which matches.
  521  */
  522 int
  523 gre_compute_route(struct gre_softc *sc)
  524 {
  525         struct route *ro;
  526         u_int32_t a, b, c;
  527 
  528         ro = &sc->route;
  529 
  530         memset(ro, 0, sizeof(struct route));
  531         ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
  532         ro->ro_dst.sa_family = AF_INET;
  533         ro->ro_dst.sa_len = sizeof(ro->ro_dst);
  534 
  535         /*
  536          * toggle last bit, so our interface is not found, but a less
  537          * specific route. I'd rather like to specify a shorter mask,
  538          * but this is not possible. Should work though. XXX
  539          * there is a simpler way ...
  540          */
  541         if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
  542                 a = ntohl(sc->g_dst.s_addr);
  543                 b = a & 0x01;
  544                 c = a & 0xfffffffe;
  545                 b = b ^ 0x01;
  546                 a = b | c;
  547                 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
  548                     = htonl(a);
  549         }
  550 
  551 #ifdef DIAGNOSTIC
  552         printf("%s: searching for a route to %s", sc->sc_if.if_xname,
  553             inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr));
  554 #endif
  555 
  556         rtalloc(ro);
  557 
  558         /*
  559          * check if this returned a route at all and this route is no
  560          * recursion to ourself
  561          */
  562         if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp->if_softc == sc) {
  563 #ifdef DIAGNOSTIC
  564                 if (ro->ro_rt == NULL)
  565                         printf(" - no route found!\n");
  566                 else
  567                         printf(" - route loops back to ourself!\n");
  568 #endif
  569                 return EADDRNOTAVAIL;
  570         }
  571 
  572         /*
  573          * now change it back - else ip_output will just drop
  574          * the route and search one to this interface ...
  575          */
  576         if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
  577                 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
  578 
  579 #ifdef DIAGNOSTIC
  580         printf(", choosing %s with gateway %s", ro->ro_rt->rt_ifp->if_xname,
  581             inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr));
  582         printf("\n");
  583 #endif
  584 
  585         return 0;
  586 }
  587 
  588 /*
  589  * do a checksum of a buffer - much like in_cksum, which operates on
  590  * mbufs.
  591  */
  592 u_int16_t
  593 gre_in_cksum(u_int16_t *p, u_int len)
  594 {
  595         u_int32_t sum = 0;
  596         int nwords = len >> 1;
  597 
  598         while (nwords-- != 0)
  599                 sum += *p++;
  600 
  601         if (len & 1) {
  602                 union {
  603                         u_short w;
  604                         u_char c[2];
  605                 } u;
  606                 u.c[0] = *(u_char *)p;
  607                 u.c[1] = 0;
  608                 sum += u.w;
  609         }
  610 
  611         /* end-around-carry */
  612         sum = (sum >> 16) + (sum & 0xffff);
  613         sum += (sum >> 16);
  614         return (~sum);
  615 }

Cache object: 2a38536df6a0baaecbf1ebb42200680f


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