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/netinet/in_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 /*
    2  * $FreeBSD: src/sys/netinet/in_gif.c,v 1.5.2.11 2003/01/23 21:06:45 sam Exp $
    3  * $DragonFly: src/sys/netinet/in_gif.c,v 1.18 2008/10/27 02:56:30 sephe Exp $
    4  * $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $
    5  */
    6 /*
    7  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    8  * All rights reserved.
    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. Neither the name of the project nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 
   35 #include "opt_inet.h"
   36 #include "opt_inet6.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/socket.h>
   41 #include <sys/sockio.h>
   42 #include <sys/mbuf.h>
   43 #include <sys/errno.h>
   44 #include <sys/kernel.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/protosw.h>
   47 
   48 #include <sys/malloc.h>
   49 
   50 #include <machine/stdarg.h>
   51 
   52 #include <net/if.h>
   53 #include <net/route.h>
   54 
   55 #include <netinet/in.h>
   56 #include <netinet/in_systm.h>
   57 #include <netinet/ip.h>
   58 #include <netinet/ip_var.h>
   59 #include <netinet/in_gif.h>
   60 #include <netinet/in_var.h>
   61 #include <netinet/ip_encap.h>
   62 #include <netinet/ip_ecn.h>
   63 
   64 #ifdef INET6
   65 #include <netinet/ip6.h>
   66 #endif
   67 
   68 #include <net/gif/if_gif.h>     
   69 #include <net/net_osdep.h>
   70 
   71 #include <sys/thread2.h>        /* ipstat */
   72 
   73 #ifdef INET
   74 static int gif_validate4 (const struct ip *, struct gif_softc *,
   75                           struct ifnet *);
   76 
   77 extern  struct domain inetdomain;
   78 const struct protosw in_gif_protosw =
   79     {
   80         .pr_type = SOCK_RAW,
   81         .pr_domain = &inetdomain,
   82         .pr_protocol = 0 /*IPPROTO_IPV[46]*/,
   83         .pr_flags = PR_ATOMIC|PR_ADDR,
   84 
   85         .pr_input = in_gif_input,
   86         .pr_output = rip_output,
   87         .pr_ctlinput = NULL,
   88         .pr_ctloutput = rip_ctloutput,
   89 
   90         .pr_ctlport = NULL,
   91         .pr_usrreqs = &rip_usrreqs
   92     };
   93 
   94 int ip_gif_ttl = GIF_TTL;
   95 SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
   96         &ip_gif_ttl, 0, "TTL of GIF packet");
   97 
   98 int
   99 in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
  100 {
  101         struct gif_softc *sc = (struct gif_softc*)ifp;
  102         struct route *ro = &sc->gif_ro[mycpu->gd_cpuid];
  103         struct sockaddr_in *dst = (struct sockaddr_in *)&ro->ro_dst;
  104         struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
  105         struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
  106         struct ip iphdr;        /* capsule IP header, host byte ordered */
  107         int proto, error;
  108         u_int8_t tos;
  109 
  110         if (sin_src == NULL || sin_dst == NULL ||
  111             sin_src->sin_family != AF_INET ||
  112             sin_dst->sin_family != AF_INET) {
  113                 m_freem(m);
  114                 return EAFNOSUPPORT;
  115         }
  116 
  117         switch (family) {
  118 #ifdef INET
  119         case AF_INET:
  120             {
  121                 struct ip *ip;
  122 
  123                 proto = IPPROTO_IPV4;
  124                 if (m->m_len < sizeof *ip) {
  125                         m = m_pullup(m, sizeof *ip);
  126                         if (!m)
  127                                 return ENOBUFS;
  128                 }
  129                 ip = mtod(m, struct ip *);
  130                 tos = ip->ip_tos;
  131                 break;
  132             }
  133 #endif
  134 #ifdef INET6
  135         case AF_INET6:
  136             {
  137                 struct ip6_hdr *ip6;
  138                 proto = IPPROTO_IPV6;
  139                 if (m->m_len < sizeof *ip6) {
  140                         m = m_pullup(m, sizeof *ip6);
  141                         if (!m)
  142                                 return ENOBUFS;
  143                 }
  144                 ip6 = mtod(m, struct ip6_hdr *);
  145                 tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
  146                 break;
  147             }
  148 #endif
  149         default:
  150 #ifdef DEBUG
  151                 kprintf("in_gif_output: warning: unknown family %d passed\n",
  152                         family);
  153 #endif
  154                 m_freem(m);
  155                 return EAFNOSUPPORT;
  156         }
  157 
  158         bzero(&iphdr, sizeof iphdr);
  159         iphdr.ip_src = sin_src->sin_addr;
  160         /* bidirectional configured tunnel mode */
  161         if (sin_dst->sin_addr.s_addr != INADDR_ANY)
  162                 iphdr.ip_dst = sin_dst->sin_addr;
  163         else {
  164                 m_freem(m);
  165                 return ENETUNREACH;
  166         }
  167         iphdr.ip_p = proto;
  168         /* version will be set in ip_output() */
  169         iphdr.ip_ttl = ip_gif_ttl;
  170         iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
  171         if (ifp->if_flags & IFF_LINK1)
  172                 ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos);
  173         else
  174                 ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos);
  175 
  176         /* prepend new IP header */
  177         M_PREPEND(m, sizeof(struct ip), MB_DONTWAIT);
  178         if (m && m->m_len < sizeof(struct ip))
  179                 m = m_pullup(m, sizeof(struct ip));
  180         if (m == NULL) {
  181                 kprintf("ENOBUFS in in_gif_output %d\n", __LINE__);
  182                 return ENOBUFS;
  183         }
  184         bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
  185 
  186         if (dst->sin_family != sin_dst->sin_family ||
  187             dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
  188                 /* cache route doesn't match */
  189                 dst->sin_family = sin_dst->sin_family;
  190                 dst->sin_len = sizeof(struct sockaddr_in);
  191                 dst->sin_addr = sin_dst->sin_addr;
  192                 if (ro->ro_rt != NULL) {
  193                         RTFREE(ro->ro_rt);
  194                         ro->ro_rt = NULL;
  195                 }
  196 #if 0
  197                 sc->gif_if.if_mtu = GIF_MTU;
  198 #endif
  199         }
  200 
  201         if (ro->ro_rt == NULL) {
  202                 rtalloc(ro);
  203                 if (ro->ro_rt == NULL) {
  204                         m_freem(m);
  205                         return ENETUNREACH;
  206                 }
  207 
  208                 /* if it constitutes infinite encapsulation, punt. */
  209                 if (ro->ro_rt->rt_ifp == ifp) {
  210                         m_freem(m);
  211                         return ENETUNREACH;     /* XXX */
  212                 }
  213 #if 0
  214                 ifp->if_mtu = ro->ro_rt->rt_ifp->if_mtu - sizeof(struct ip);
  215 #endif
  216         }
  217 
  218         error = ip_output(m, NULL, ro, 0, NULL, NULL);
  219         return(error);
  220 }
  221 
  222 int
  223 in_gif_input(struct mbuf **mp, int *offp, int proto)
  224 {
  225         struct mbuf *m = *mp;
  226         struct ifnet *gifp = NULL;
  227         struct ip *ip;
  228         int af;
  229         u_int8_t otos;
  230         int off;
  231 
  232         off = *offp;
  233         *mp = NULL;
  234 
  235         ip = mtod(m, struct ip *);
  236 
  237         gifp = (struct ifnet *)encap_getarg(m);
  238 
  239         if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
  240                 m_freem(m);
  241                 ipstat.ips_nogif++;
  242                 return(IPPROTO_DONE);
  243         }
  244 
  245         otos = ip->ip_tos;
  246         m_adj(m, off);
  247 
  248         switch (proto) {
  249 #ifdef INET
  250         case IPPROTO_IPV4:
  251             {
  252                 struct ip *ip;
  253                 af = AF_INET;
  254                 if (m->m_len < sizeof *ip) {
  255                         m = m_pullup(m, sizeof *ip);
  256                         if (!m)
  257                                 return(IPPROTO_DONE);
  258                 }
  259                 ip = mtod(m, struct ip *);
  260                 if (gifp->if_flags & IFF_LINK1)
  261                         ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos);
  262                 else
  263                         ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos);
  264                 break;
  265             }
  266 #endif
  267 #ifdef INET6
  268         case IPPROTO_IPV6:
  269             {
  270                 struct ip6_hdr *ip6;
  271                 u_int8_t itos;
  272                 af = AF_INET6;
  273                 if (m->m_len < sizeof *ip6) {
  274                         m = m_pullup(m, sizeof *ip6);
  275                         if (!m)
  276                                 return(IPPROTO_DONE);
  277                 }
  278                 ip6 = mtod(m, struct ip6_hdr *);
  279                 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
  280                 if (gifp->if_flags & IFF_LINK1)
  281                         ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
  282                 else
  283                         ip_ecn_egress(ECN_NOCARE, &otos, &itos);
  284                 ip6->ip6_flow &= ~htonl(0xff << 20);
  285                 ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
  286                 break;
  287             }
  288 #endif /* INET6 */
  289         default:
  290                 ipstat.ips_nogif++;
  291                 m_freem(m);
  292                 return(IPPROTO_DONE);
  293         }
  294         gif_input(m, af, gifp);
  295         return(IPPROTO_DONE);
  296 }
  297 
  298 /*
  299  * validate outer address.
  300  */
  301 static int
  302 gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp)
  303 {
  304         struct sockaddr_in *src, *dst;
  305         struct in_ifaddr_container *iac;
  306 
  307         src = (struct sockaddr_in *)sc->gif_psrc;
  308         dst = (struct sockaddr_in *)sc->gif_pdst;
  309 
  310         /* check for address match */
  311         if (src->sin_addr.s_addr != ip->ip_dst.s_addr ||
  312             dst->sin_addr.s_addr != ip->ip_src.s_addr)
  313                 return 0;
  314 
  315         /* martian filters on outer source - NOT done in ip_input! */
  316         if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)))
  317                 return 0;
  318         switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) {
  319         case 0: case 127: case 255:
  320                 return 0;
  321         }
  322         /* reject packets with broadcast on source */
  323         TAILQ_FOREACH(iac, &in_ifaddrheads[mycpuid], ia_link) {
  324                 struct in_ifaddr *ia4 = iac->ia;
  325 
  326                 if (!(ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST))
  327                         continue;
  328                 if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
  329                         return 0;
  330         }
  331 
  332         /* ingress filters on outer source */
  333         if (!(sc->gif_if.if_flags & IFF_LINK2) && ifp != NULL) {
  334                 struct sockaddr_in sin;
  335                 struct rtentry *rt;
  336 
  337                 bzero(&sin, sizeof sin);
  338                 sin.sin_family = AF_INET;
  339                 sin.sin_len = sizeof(struct sockaddr_in);
  340                 sin.sin_addr = ip->ip_src;
  341                 rt = rtpurelookup((struct sockaddr *)&sin);
  342                 if (rt != NULL)
  343                         --rt->rt_refcnt;
  344                 if (rt == NULL || rt->rt_ifp != ifp) {
  345 #if 0
  346                         log(LOG_WARNING, "%s: packet from 0x%x dropped "
  347                             "due to ingress filter\n", if_name(&sc->gif_if),
  348                             (u_int32_t)ntohl(sin.sin_addr.s_addr));
  349 #endif
  350                         return 0;
  351                 }
  352         }
  353 
  354         return 32 * 2;
  355 }
  356 
  357 /*
  358  * we know that we are in IFF_UP, outer address available, and outer family
  359  * matched the physical addr family.  see gif_encapcheck().
  360  */
  361 int
  362 gif_encapcheck4(const struct mbuf *m, int off, int proto, void *arg)
  363 {
  364         struct ip ip;
  365         struct gif_softc *sc;
  366         struct ifnet *ifp;
  367 
  368         /* sanity check done in caller */
  369         sc = (struct gif_softc *)arg;
  370 
  371         /* LINTED const cast */
  372         m_copydata(__DECONST(struct mbuf *, m), 0, sizeof ip, (caddr_t)&ip);
  373         ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
  374 
  375         return gif_validate4(&ip, sc, ifp);
  376 }
  377 
  378 int
  379 in_gif_attach(struct gif_softc *sc)
  380 {
  381         sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck,
  382             &in_gif_protosw, sc);
  383         if (sc->encap_cookie4 == NULL)
  384                 return EEXIST;
  385         return 0;
  386 }
  387 
  388 int
  389 in_gif_detach(struct gif_softc *sc)
  390 {
  391         int error;
  392 
  393         error = encap_detach(sc->encap_cookie4);
  394         if (error == 0)
  395                 sc->encap_cookie4 = NULL;
  396         return error;
  397 }
  398 
  399 #endif /* INET */

Cache object: 01244a52a5cb5ece32f3c42f6dd1877b


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