LCOV - code coverage report
Current view: top level - netmpls - mpls_input.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 196 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: mpls_input.c,v 1.68 2018/01/12 06:57:56 jca Exp $     */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2008 Claudio Jeker <claudio@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : #include "mpe.h"
      20             : 
      21             : #include <sys/param.h>
      22             : #include <sys/mbuf.h>
      23             : #include <sys/systm.h>
      24             : #include <sys/socket.h>
      25             : 
      26             : #include <net/if.h>
      27             : #include <net/if_var.h>
      28             : #include <net/if_types.h>
      29             : #include <net/netisr.h>
      30             : #include <net/route.h>
      31             : 
      32             : #include <netinet/in.h>
      33             : #include <netinet/ip.h>
      34             : #include <netinet/ip_var.h>
      35             : #include <netinet/ip_icmp.h>
      36             : 
      37             : #ifdef INET6
      38             : #include <netinet/ip6.h>
      39             : #endif /* INET6 */
      40             : 
      41             : #include <netmpls/mpls.h>
      42             : 
      43             : #ifdef MPLS_DEBUG
      44             : #define MPLS_LABEL_GET(l)       ((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET)
      45             : #define MPLS_TTL_GET(l)         (ntohl((l) & MPLS_TTL_MASK))
      46             : #endif
      47             : 
      48             : struct mbuf     *mpls_ip_adjttl(struct mbuf *, u_int8_t);
      49             : #ifdef INET6
      50             : struct mbuf     *mpls_ip6_adjttl(struct mbuf *, u_int8_t);
      51             : #endif
      52             : 
      53             : struct mbuf     *mpls_do_error(struct mbuf *, int, int, int);
      54             : 
      55             : void
      56           0 : mpls_input(struct ifnet *ifp, struct mbuf *m)
      57             : {
      58             :         struct sockaddr_mpls *smpls;
      59           0 :         struct sockaddr_mpls sa_mpls;
      60             :         struct shim_hdr *shim;
      61             :         struct rtentry *rt;
      62             :         struct rt_mpls *rt_mpls;
      63             :         uint8_t ttl;
      64             :         int hasbos;
      65             : 
      66           0 :         if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
      67           0 :                 m_freem(m);
      68           0 :                 return;
      69             :         }
      70             : 
      71             :         /* drop all broadcast and multicast packets */
      72           0 :         if (m->m_flags & (M_BCAST | M_MCAST)) {
      73           0 :                 m_freem(m);
      74           0 :                 return;
      75             :         }
      76             : 
      77           0 :         if (m->m_len < sizeof(*shim)) {
      78           0 :                 m = m_pullup(m, sizeof(*shim));
      79           0 :                 if (m == NULL)
      80           0 :                         return;
      81             :         }
      82             : 
      83           0 :         shim = mtod(m, struct shim_hdr *);
      84             : #ifdef MPLS_DEBUG
      85             :         printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n",
      86             :             ifp->if_xname, MPLS_LABEL_GET(shim->shim_label),
      87             :             MPLS_TTL_GET(shim->shim_label),
      88             :             MPLS_BOS_ISSET(shim->shim_label));
      89             : #endif
      90             : 
      91             :         /* check and decrement TTL */
      92           0 :         ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
      93           0 :         if (--ttl == 0) {
      94             :                 /* TTL exceeded */
      95           0 :                 m = mpls_do_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0);
      96           0 :                 if (m == NULL)
      97           0 :                         return;
      98             : 
      99           0 :                 shim = mtod(m, struct shim_hdr *);
     100           0 :                 ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
     101           0 :         }
     102           0 :         hasbos = MPLS_BOS_ISSET(shim->shim_label);
     103             : 
     104           0 :         bzero(&sa_mpls, sizeof(sa_mpls));
     105             :         smpls = &sa_mpls;
     106           0 :         smpls->smpls_family = AF_MPLS;
     107           0 :         smpls->smpls_len = sizeof(*smpls);
     108           0 :         smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
     109             : 
     110           0 :         if (ntohl(smpls->smpls_label) < MPLS_LABEL_RESERVED_MAX) {
     111           0 :                 m = mpls_shim_pop(m);
     112           0 :                 if (m == NULL)
     113           0 :                         return;
     114           0 :                 if (!hasbos) {
     115             :                         /*
     116             :                          * RFC 4182 relaxes the position of the
     117             :                          * explicit NULL labels. They no longer need
     118             :                          * to be at the beginning of the stack.
     119             :                          * In this case the label is ignored and the decision
     120             :                          * is made based on the lower one.
     121             :                          */
     122           0 :                         shim = mtod(m, struct shim_hdr *);
     123           0 :                         smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
     124           0 :                         hasbos = MPLS_BOS_ISSET(shim->shim_label);
     125             :                 } else {
     126           0 :                         switch (ntohl(smpls->smpls_label)) {
     127             :                         case MPLS_LABEL_IPV4NULL:
     128             : do_v4:
     129           0 :                                 if ((m = mpls_ip_adjttl(m, ttl)) == NULL)
     130           0 :                                         return;
     131           0 :                                 ipv4_input(ifp, m);
     132           0 :                                 return;
     133             : #ifdef INET6
     134             :                         case MPLS_LABEL_IPV6NULL:
     135             : do_v6:
     136           0 :                                 if ((m = mpls_ip6_adjttl(m, ttl)) == NULL)
     137           0 :                                         return;
     138           0 :                                 ipv6_input(ifp, m);
     139           0 :                                 return;
     140             : #endif  /* INET6 */
     141             :                         case MPLS_LABEL_IMPLNULL:
     142           0 :                                 if (m->m_len < sizeof(u_char) &&
     143           0 :                                     (m = m_pullup(m, sizeof(u_char))) == NULL)
     144           0 :                                         return;
     145           0 :                                 switch (*mtod(m, u_char *) >> 4) {
     146             :                                 case IPVERSION:
     147             :                                         goto do_v4;
     148             : #ifdef INET6
     149             :                                 case IPV6_VERSION >> 4:
     150             :                                         goto do_v6;
     151             : #endif
     152             :                                 default:
     153           0 :                                         m_freem(m);
     154           0 :                                         return;
     155             :                                 }
     156             :                         default:
     157             :                                 /* Other cases are not handled for now */
     158           0 :                                 m_freem(m);
     159           0 :                                 return;
     160             :                         }
     161             :                 }
     162           0 :         }
     163             : 
     164             :         ifp = NULL;
     165             : 
     166           0 :         rt = rtalloc(smplstosa(smpls), RT_RESOLVE, m->m_pkthdr.ph_rtableid);
     167           0 :         if (rt == NULL) {
     168             :                 /* no entry for this label */
     169             : #ifdef MPLS_DEBUG
     170             :                 printf("MPLS_DEBUG: label not found\n");
     171             : #endif
     172           0 :                 m_freem(m);
     173           0 :                 return;
     174             :         }
     175             : 
     176           0 :         rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
     177           0 :         if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) {
     178             : #ifdef MPLS_DEBUG
     179             :                 printf("MPLS_DEBUG: no MPLS information attached\n");
     180             : #endif
     181           0 :                 m_freem(m);
     182           0 :                 goto done;
     183             :         }
     184             : 
     185           0 :         switch (rt_mpls->mpls_operation) {
     186             :         case MPLS_OP_POP:
     187           0 :                 m = mpls_shim_pop(m);
     188           0 :                 if (m == NULL)
     189             :                         goto done;
     190           0 :                 if (!hasbos)
     191             :                         /* just forward to gw */
     192             :                         break;
     193             : 
     194             :                 /* last label popped so decide where to push it to */
     195           0 :                 ifp = if_get(rt->rt_ifidx);
     196           0 :                 if (ifp == NULL) {
     197           0 :                         m_freem(m);
     198           0 :                         goto done;
     199             :                 }
     200             : #if NMPE > 0
     201           0 :                 if (ifp->if_type == IFT_MPLS) {
     202           0 :                         smpls = satosmpls(rt_key(rt));
     203           0 :                         mpe_input(m, ifp, smpls, ttl);
     204           0 :                         goto done;
     205             :                 }
     206             : #endif
     207           0 :                 if (ifp->if_type == IFT_MPLSTUNNEL) {
     208           0 :                         ifp->if_output(ifp, m, rt_key(rt), rt);
     209           0 :                         goto done;
     210             :                 }
     211             : 
     212           0 :                 KASSERT(rt->rt_gateway);
     213             : 
     214           0 :                 switch(rt->rt_gateway->sa_family) {
     215             :                 case AF_INET:
     216           0 :                         if ((m = mpls_ip_adjttl(m, ttl)) == NULL)
     217             :                                 goto done;
     218             :                         break;
     219             : #ifdef INET6
     220             :                 case AF_INET6:
     221           0 :                         if ((m = mpls_ip6_adjttl(m, ttl)) == NULL)
     222             :                                 goto done;
     223             :                         break;
     224             : #endif
     225             :                 default:
     226           0 :                         m_freem(m);
     227           0 :                         goto done;
     228             :                 }
     229             : 
     230             :                 /* shortcut sending out the packet */
     231           0 :                 if (!ISSET(ifp->if_xflags, IFXF_MPLS))
     232           0 :                         (*ifp->if_output)(ifp, m, rt->rt_gateway, rt);
     233             :                 else
     234           0 :                         (*ifp->if_ll_output)(ifp, m, rt->rt_gateway, rt);
     235             :                 goto done;
     236             :         case MPLS_OP_PUSH:
     237             :                 /* this does not make much sense but it does not hurt */
     238           0 :                 m = mpls_shim_push(m, rt_mpls);
     239           0 :                 break;
     240             :         case MPLS_OP_SWAP:
     241           0 :                 m = mpls_shim_swap(m, rt_mpls);
     242           0 :                 break;
     243             :         default:
     244           0 :                 m_freem(m);
     245           0 :                 goto done;
     246             :         }
     247             : 
     248           0 :         if (m == NULL)
     249             :                 goto done;
     250             : 
     251             :         /* refetch label and write back TTL */
     252           0 :         shim = mtod(m, struct shim_hdr *);
     253           0 :         shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl);
     254             : 
     255           0 :         ifp = if_get(rt->rt_ifidx);
     256           0 :         if (ifp == NULL) {
     257           0 :                 m_freem(m);
     258           0 :                 goto done;
     259             :         }
     260             : #ifdef MPLS_DEBUG
     261             :         printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n",
     262             :             ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family,
     263             :             MPLS_LABEL_GET(smpls->smpls_label),
     264             :             MPLS_LABEL_GET(rt_mpls->mpls_label));
     265             : #endif
     266             : 
     267             :         /* Output iface is not MPLS-enabled */
     268           0 :         if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
     269             : #ifdef MPLS_DEBUG
     270             :                 printf("MPLS_DEBUG: interface %s not mpls enabled\n",
     271             :                     ifp->if_xname);
     272             : #endif
     273           0 :                 m_freem(m);
     274           0 :                 goto done;
     275             :         }
     276             : 
     277           0 :         (*ifp->if_ll_output)(ifp, m, smplstosa(smpls), rt);
     278             : done:
     279           0 :         if_put(ifp);
     280           0 :         rtfree(rt);
     281           0 : }
     282             : 
     283             : struct mbuf *
     284           0 : mpls_ip_adjttl(struct mbuf *m, u_int8_t ttl)
     285             : {
     286             :         struct ip *ip;
     287             :         int hlen;
     288             : 
     289           0 :         if (mpls_mapttl_ip) {
     290           0 :                 if (m->m_len < sizeof(struct ip) &&
     291           0 :                     (m = m_pullup(m, sizeof(struct ip))) == NULL)
     292           0 :                         return NULL;
     293           0 :                 ip = mtod(m, struct ip *);
     294           0 :                 hlen = ip->ip_hl << 2;
     295           0 :                 if (m->m_len < hlen) {
     296           0 :                         if ((m = m_pullup(m, hlen)) == NULL)
     297           0 :                                 return NULL;
     298           0 :                         ip = mtod(m, struct ip *);
     299           0 :                 }
     300             :                 /* make sure we have a valid header */
     301           0 :                 if (in_cksum(m, hlen) != 0) {
     302           0 :                         m_freem(m);
     303           0 :                         return NULL;
     304             :                 }
     305             : 
     306             :                 /* set IP ttl from MPLS ttl */
     307           0 :                 ip->ip_ttl = ttl;
     308             : 
     309             :                 /* recalculate checksum */
     310           0 :                 ip->ip_sum = 0;
     311           0 :                 ip->ip_sum = in_cksum(m, hlen);
     312           0 :         }
     313           0 :         return m;
     314           0 : }
     315             : 
     316             : #ifdef INET6
     317             : struct mbuf *
     318           0 : mpls_ip6_adjttl(struct mbuf *m, u_int8_t ttl)
     319             : {
     320             :         struct ip6_hdr *ip6hdr;
     321             : 
     322           0 :         if (mpls_mapttl_ip6) {
     323           0 :                 if (m->m_len < sizeof(struct ip6_hdr) &&
     324           0 :                     (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
     325           0 :                         return NULL;
     326             : 
     327           0 :                 ip6hdr = mtod(m, struct ip6_hdr *);
     328             : 
     329             :                 /* set IPv6 ttl from MPLS ttl */
     330           0 :                 ip6hdr->ip6_hlim = ttl;
     331           0 :         }
     332           0 :         return m;
     333           0 : }
     334             : #endif  /* INET6 */
     335             : 
     336             : struct mbuf *
     337           0 : mpls_do_error(struct mbuf *m, int type, int code, int destmtu)
     338             : {
     339           0 :         struct shim_hdr stack[MPLS_INKERNEL_LOOP_MAX];
     340           0 :         struct sockaddr_mpls sa_mpls;
     341             :         struct sockaddr_mpls *smpls;
     342             :         struct rtentry *rt = NULL;
     343             :         struct shim_hdr *shim;
     344             :         struct in_ifaddr *ia;
     345             :         struct icmp *icp;
     346             :         struct ip *ip;
     347             :         int nstk, error;
     348             : 
     349           0 :         for (nstk = 0; nstk < MPLS_INKERNEL_LOOP_MAX; nstk++) {
     350           0 :                 if (m->m_len < sizeof(*shim) &&
     351           0 :                     (m = m_pullup(m, sizeof(*shim))) == NULL)
     352           0 :                         return (NULL);
     353           0 :                 stack[nstk] = *mtod(m, struct shim_hdr *);
     354           0 :                 m_adj(m, sizeof(*shim));
     355           0 :                 if (MPLS_BOS_ISSET(stack[nstk].shim_label))
     356             :                         break;
     357             :         }
     358           0 :         shim = &stack[0];
     359             : 
     360           0 :         if (m->m_len < sizeof(u_char) &&
     361           0 :             (m = m_pullup(m, sizeof(u_char))) == NULL)
     362           0 :                 return (NULL);
     363           0 :         switch (*mtod(m, u_char *) >> 4) {
     364             :         case IPVERSION:
     365           0 :                 if (m->m_len < sizeof(*ip) &&
     366           0 :                     (m = m_pullup(m, sizeof(*ip))) == NULL)
     367           0 :                         return (NULL);
     368           0 :                 m = icmp_do_error(m, type, code, 0, destmtu);
     369           0 :                 if (m == NULL)
     370           0 :                         return (NULL);
     371             : 
     372           0 :                 if (icmp_do_exthdr(m, ICMP_EXT_MPLS, 1, stack,
     373           0 :                     (nstk + 1) * sizeof(*shim)))
     374           0 :                         return (NULL);
     375             : 
     376             :                 /* set ip_src to something usable, based on the MPLS label */
     377           0 :                 bzero(&sa_mpls, sizeof(sa_mpls));
     378             :                 smpls = &sa_mpls;
     379           0 :                 smpls->smpls_family = AF_MPLS;
     380           0 :                 smpls->smpls_len = sizeof(*smpls);
     381           0 :                 smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
     382             : 
     383           0 :                 rt = rtalloc(smplstosa(smpls), RT_RESOLVE, 0);
     384           0 :                 if (rt == NULL) {
     385             :                         /* no entry for this label */
     386           0 :                         m_freem(m);
     387           0 :                         return (NULL);
     388             :                 }
     389           0 :                 if (rt->rt_ifa->ifa_addr->sa_family == AF_INET)
     390           0 :                         ia = ifatoia(rt->rt_ifa);
     391             :                 else {
     392             :                         /* XXX this needs fixing, if the MPLS is on an IP
     393             :                          * less interface we need to find some other IP to
     394             :                          * use as source.
     395             :                          */
     396           0 :                         rtfree(rt);
     397           0 :                         m_freem(m);
     398           0 :                         return (NULL);
     399             :                 }
     400             :                 /* It is safe to dereference ``ia'' iff ``rt'' is valid. */
     401           0 :                 error = icmp_reflect(m, NULL, ia);
     402           0 :                 rtfree(rt);
     403           0 :                 if (error)
     404           0 :                         return (NULL);
     405             : 
     406           0 :                 ip = mtod(m, struct ip *);
     407             :                 /* stuff to fix up which is normaly done in ip_output */
     408           0 :                 ip->ip_v = IPVERSION;
     409           0 :                 ip->ip_id = htons(ip_randomid());
     410           0 :                 ip->ip_sum = 0;
     411           0 :                 ip->ip_sum = in_cksum(m, sizeof(*ip));
     412             : 
     413             :                 /* stolen from icmp_send() */
     414           0 :                 icp = (struct icmp *)(mtod(m, caddr_t) + sizeof(*ip));
     415           0 :                 icp->icmp_cksum = 0;
     416           0 :                 icp->icmp_cksum = in4_cksum(m, 0, sizeof(*ip),
     417           0 :                     ntohs(ip->ip_len) - sizeof(*ip));
     418             : 
     419             :                 break;
     420             : #ifdef INET6
     421             :         case IPV6_VERSION >> 4:
     422             : #endif
     423             :         default:
     424           0 :                 m_freem(m);
     425           0 :                 return (NULL);
     426             :         }
     427             : 
     428             :         /* add mpls stack back to new packet */
     429           0 :         M_PREPEND(m, (nstk + 1) * sizeof(*shim), M_NOWAIT);
     430           0 :         if (m == NULL)
     431           0 :                 return (NULL);
     432           0 :         m_copyback(m, 0, (nstk + 1) * sizeof(*shim), stack, M_NOWAIT);
     433             : 
     434             :         /* change TTL to default */
     435           0 :         shim = mtod(m, struct shim_hdr *);
     436           0 :         shim->shim_label =
     437           0 :             (shim->shim_label & ~MPLS_TTL_MASK) | htonl(mpls_defttl);
     438             : 
     439           0 :         return (m);
     440           0 : }

Generated by: LCOV version 1.13