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

          Line data    Source code
       1             : /* $OpenBSD: if_mpe.c,v 1.64 2018/01/09 15:24:24 bluhm Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@spootnik.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             : #include "mpe.h"
      19             : 
      20             : #include <sys/param.h>
      21             : #include <sys/systm.h>
      22             : #include <sys/mbuf.h>
      23             : #include <sys/socket.h>
      24             : #include <sys/sockio.h>
      25             : #include <sys/ioctl.h>
      26             : 
      27             : #include <net/if.h>
      28             : #include <net/if_dl.h>
      29             : #include <net/if_var.h>
      30             : #include <net/if_types.h>
      31             : #include <net/netisr.h>
      32             : #include <net/route.h>
      33             : 
      34             : #include <netinet/in.h>
      35             : #include <netinet/ip.h>
      36             : 
      37             : #ifdef INET6
      38             : #include <netinet/ip6.h>
      39             : #endif /* INET6 */
      40             : 
      41             : #include "bpfilter.h"
      42             : #if NBPFILTER > 0
      43             : #include <net/bpf.h>
      44             : #endif
      45             : 
      46             : #include <netmpls/mpls.h>
      47             : 
      48             : #ifdef MPLS_DEBUG
      49             : #define DPRINTF(x)    do { if (mpedebug) printf x ; } while (0)
      50             : #else
      51             : #define DPRINTF(x)
      52             : #endif
      53             : 
      54             : void    mpeattach(int);
      55             : int     mpeoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
      56             :                        struct rtentry *);
      57             : int     mpeioctl(struct ifnet *, u_long, caddr_t);
      58             : void    mpestart(struct ifnet *);
      59             : int     mpe_clone_create(struct if_clone *, int);
      60             : int     mpe_clone_destroy(struct ifnet *);
      61             : 
      62             : LIST_HEAD(, mpe_softc)  mpeif_list;
      63             : struct if_clone mpe_cloner =
      64             :     IF_CLONE_INITIALIZER("mpe", mpe_clone_create, mpe_clone_destroy);
      65             : 
      66             : extern int      mpls_mapttl_ip;
      67             : #ifdef INET6
      68             : extern int      mpls_mapttl_ip6;
      69             : #endif
      70             : 
      71             : void
      72           0 : mpeattach(int nmpe)
      73             : {
      74           0 :         LIST_INIT(&mpeif_list);
      75           0 :         if_clone_attach(&mpe_cloner);
      76           0 : }
      77             : 
      78             : int
      79           0 : mpe_clone_create(struct if_clone *ifc, int unit)
      80             : {
      81             :         struct ifnet            *ifp;
      82             :         struct mpe_softc        *mpeif;
      83             : 
      84           0 :         mpeif = malloc(sizeof(*mpeif), M_DEVBUF, M_WAITOK|M_ZERO);
      85           0 :         mpeif->sc_unit = unit;
      86           0 :         ifp = &mpeif->sc_if;
      87           0 :         snprintf(ifp->if_xname, sizeof ifp->if_xname, "mpe%d", unit);
      88           0 :         ifp->if_flags = IFF_POINTOPOINT;
      89           0 :         ifp->if_xflags = IFXF_CLONED;
      90           0 :         ifp->if_softc = mpeif;
      91           0 :         ifp->if_mtu = MPE_MTU;
      92           0 :         ifp->if_ioctl = mpeioctl;
      93           0 :         ifp->if_output = mpeoutput;
      94           0 :         ifp->if_start = mpestart;
      95           0 :         ifp->if_type = IFT_MPLS;
      96           0 :         ifp->if_hdrlen = MPE_HDRLEN;
      97           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
      98           0 :         if_attach(ifp);
      99           0 :         if_alloc_sadl(ifp);
     100             : #if NBPFILTER > 0
     101           0 :         bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
     102             : #endif
     103             : 
     104           0 :         mpeif->sc_ifa.ifa_ifp = ifp;
     105           0 :         mpeif->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl);
     106           0 :         mpeif->sc_smpls.smpls_len = sizeof(mpeif->sc_smpls);
     107           0 :         mpeif->sc_smpls.smpls_family = AF_MPLS;
     108             : 
     109           0 :         LIST_INSERT_HEAD(&mpeif_list, mpeif, sc_list);
     110             : 
     111           0 :         return (0);
     112             : }
     113             : 
     114             : int
     115           0 : mpe_clone_destroy(struct ifnet *ifp)
     116             : {
     117           0 :         struct mpe_softc        *mpeif = ifp->if_softc;
     118             : 
     119           0 :         LIST_REMOVE(mpeif, sc_list);
     120             : 
     121           0 :         if (mpeif->sc_smpls.smpls_label) {
     122           0 :                 rt_ifa_del(&mpeif->sc_ifa, RTF_MPLS,
     123           0 :                     smplstosa(&mpeif->sc_smpls));
     124           0 :         }
     125             : 
     126           0 :         if_detach(ifp);
     127           0 :         free(mpeif, M_DEVBUF, sizeof *mpeif);
     128           0 :         return (0);
     129             : }
     130             : 
     131             : struct sockaddr_storage  mpedst;
     132             : /*
     133             :  * Start output on the mpe interface.
     134             :  */
     135             : void
     136           0 : mpestart(struct ifnet *ifp0)
     137             : {
     138             :         struct mbuf             *m;
     139           0 :         struct sockaddr         *sa = sstosa(&mpedst);
     140             :         sa_family_t              af;
     141             :         struct rtentry          *rt;
     142             :         struct ifnet            *ifp;
     143             : 
     144           0 :         for (;;) {
     145           0 :                 IFQ_DEQUEUE(&ifp0->if_snd, m);
     146           0 :                 if (m == NULL)
     147             :                         return;
     148             : 
     149           0 :                 af = *mtod(m, sa_family_t *);
     150           0 :                 m_adj(m, sizeof(af));
     151           0 :                 switch (af) {
     152             :                 case AF_INET:
     153           0 :                         bzero(sa, sizeof(struct sockaddr_in));
     154           0 :                         satosin(sa)->sin_family = af;
     155           0 :                         satosin(sa)->sin_len = sizeof(struct sockaddr_in);
     156           0 :                         bcopy(mtod(m, caddr_t), &satosin(sa)->sin_addr,
     157             :                             sizeof(in_addr_t));
     158           0 :                         m_adj(m, sizeof(in_addr_t));
     159             :                         break;
     160             :                 default:
     161           0 :                         m_freem(m);
     162           0 :                         continue;
     163             :                 }
     164             : 
     165           0 :                 rt = rtalloc(sa, RT_RESOLVE, 0);
     166           0 :                 if (!rtisvalid(rt)) {
     167           0 :                         m_freem(m);
     168           0 :                         rtfree(rt);
     169           0 :                         continue;
     170             :                 }
     171             : 
     172           0 :                 ifp = if_get(rt->rt_ifidx);
     173           0 :                 if (ifp == NULL) {
     174           0 :                         m_freem(m);
     175           0 :                         rtfree(rt);
     176           0 :                         continue;
     177             :                 }
     178             : #if NBPFILTER > 0
     179           0 :                 if (ifp0->if_bpf) {
     180             :                         /* remove MPLS label before passing packet to bpf */
     181           0 :                         m->m_data += sizeof(struct shim_hdr);
     182           0 :                         m->m_len -= sizeof(struct shim_hdr);
     183           0 :                         m->m_pkthdr.len -= sizeof(struct shim_hdr);
     184           0 :                         bpf_mtap_af(ifp0->if_bpf, af, m, BPF_DIRECTION_OUT);
     185           0 :                         m->m_data -= sizeof(struct shim_hdr);
     186           0 :                         m->m_len += sizeof(struct shim_hdr);
     187           0 :                         m->m_pkthdr.len += sizeof(struct shim_hdr);
     188           0 :                 }
     189             : #endif
     190             :                 /* XXX lie, but mpls_output looks only at sa_family */
     191           0 :                 sa->sa_family = AF_MPLS;
     192             : 
     193           0 :                 mpls_output(ifp, m, sa, rt);
     194           0 :                 if_put(ifp);
     195           0 :                 rtfree(rt);
     196             :         }
     197           0 : }
     198             : 
     199             : int
     200           0 : mpeoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
     201             :         struct rtentry *rt)
     202             : {
     203           0 :         struct shim_hdr shim;
     204             :         int             error;
     205             :         int             off;
     206           0 :         in_addr_t       addr;
     207             :         u_int8_t        op = 0;
     208             : 
     209             : #ifdef DIAGNOSTIC
     210           0 :         if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) {
     211           0 :                 printf("%s: trying to send packet on wrong domain. "
     212           0 :                     "if %d vs. mbuf %d\n", ifp->if_xname,
     213           0 :                     ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid));
     214           0 :         }
     215             : #endif
     216           0 :         m->m_pkthdr.ph_ifidx = ifp->if_index;
     217             :         /* XXX assumes MPLS is always in rdomain 0 */
     218           0 :         m->m_pkthdr.ph_rtableid = 0;
     219             : 
     220             :         error = 0;
     221           0 :         switch (dst->sa_family) {
     222             :         case AF_INET:
     223           0 :                 if (!rt || !(rt->rt_flags & RTF_MPLS)) {
     224           0 :                         m_freem(m);
     225             :                         error = ENETUNREACH;
     226           0 :                         goto out;
     227             :                 }
     228           0 :                 shim.shim_label =
     229           0 :                     ((struct rt_mpls *)rt->rt_llinfo)->mpls_label;
     230           0 :                 shim.shim_label |= MPLS_BOS_MASK;
     231           0 :                 op =  ((struct rt_mpls *)rt->rt_llinfo)->mpls_operation;
     232           0 :                 if (op != MPLS_OP_PUSH) {
     233           0 :                         m_freem(m);
     234             :                         error = ENETUNREACH;
     235           0 :                         goto out;
     236             :                 }
     237           0 :                 if (mpls_mapttl_ip) {
     238             :                         struct ip       *ip;
     239           0 :                         ip = mtod(m, struct ip *);
     240           0 :                         shim.shim_label |= htonl(ip->ip_ttl) & MPLS_TTL_MASK;
     241           0 :                 } else
     242           0 :                         shim.shim_label |= htonl(mpls_defttl) & MPLS_TTL_MASK;
     243             :                 off = sizeof(sa_family_t) + sizeof(in_addr_t);
     244           0 :                 M_PREPEND(m, sizeof(shim) + off, M_DONTWAIT);
     245           0 :                 if (m == NULL) {
     246             :                         error = ENOBUFS;
     247           0 :                         goto out;
     248             :                 }
     249           0 :                 *mtod(m, sa_family_t *) = AF_INET;
     250           0 :                 addr = satosin(rt->rt_gateway)->sin_addr.s_addr;
     251           0 :                 m_copyback(m, sizeof(sa_family_t), sizeof(in_addr_t),
     252             :                     &addr, M_NOWAIT);
     253             :                 break;
     254             :         default:
     255           0 :                 m_freem(m);
     256             :                 error = EPFNOSUPPORT;
     257           0 :                 goto out;
     258             :         }
     259             : 
     260           0 :         m_copyback(m, off, sizeof(shim), (caddr_t)&shim, M_NOWAIT);
     261             : 
     262           0 :         error = if_enqueue(ifp, m);
     263             : out:
     264           0 :         if (error)
     265           0 :                 ifp->if_oerrors++;
     266           0 :         return (error);
     267           0 : }
     268             : 
     269             : int
     270           0 : mpeioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     271             : {
     272             :         struct mpe_softc        *ifm;
     273             :         struct ifreq            *ifr;
     274           0 :         struct shim_hdr          shim;
     275             :         int                      error = 0;
     276             : 
     277           0 :         ifr = (struct ifreq *)data;
     278           0 :         switch (cmd) {
     279             :         case SIOCSIFADDR:
     280           0 :                 if (!ISSET(ifp->if_flags, IFF_UP))
     281           0 :                         if_up(ifp);
     282             :                 break;
     283             :         case SIOCSIFFLAGS:
     284           0 :                 if (ifp->if_flags & IFF_UP)
     285           0 :                         ifp->if_flags |= IFF_RUNNING;
     286             :                 else
     287           0 :                         ifp->if_flags &= ~IFF_RUNNING;
     288             :                 break;
     289             :         case SIOCSIFMTU:
     290           0 :                 if (ifr->ifr_mtu < MPE_MTU_MIN ||
     291           0 :                     ifr->ifr_mtu > MPE_MTU_MAX)
     292           0 :                         error = EINVAL;
     293             :                 else
     294           0 :                         ifp->if_mtu = ifr->ifr_mtu;
     295             :                 break;
     296             :         case SIOCGETLABEL:
     297           0 :                 ifm = ifp->if_softc;
     298           0 :                 shim.shim_label =
     299           0 :                     ((ntohl(ifm->sc_smpls.smpls_label & MPLS_LABEL_MASK)) >>
     300             :                     MPLS_LABEL_OFFSET);
     301           0 :                 error = copyout(&shim, ifr->ifr_data, sizeof(shim));
     302           0 :                 break;
     303             :         case SIOCSETLABEL:
     304           0 :                 ifm = ifp->if_softc;
     305           0 :                 if ((error = copyin(ifr->ifr_data, &shim, sizeof(shim))))
     306             :                         break;
     307           0 :                 if (shim.shim_label > MPLS_LABEL_MAX ||
     308           0 :                     shim.shim_label <= MPLS_LABEL_RESERVED_MAX) {
     309             :                         error = EINVAL;
     310           0 :                         break;
     311             :                 }
     312           0 :                 shim.shim_label = htonl(shim.shim_label << MPLS_LABEL_OFFSET);
     313           0 :                 if (ifm->sc_smpls.smpls_label == shim.shim_label)
     314             :                         break;
     315           0 :                 LIST_FOREACH(ifm, &mpeif_list, sc_list) {
     316           0 :                         if (ifm != ifp->if_softc &&
     317           0 :                             ifm->sc_smpls.smpls_label == shim.shim_label) {
     318             :                                 error = EEXIST;
     319           0 :                                 break;
     320             :                         }
     321             :                 }
     322           0 :                 if (error)
     323             :                         break;
     324             :                 /*
     325             :                  * force interface up for now,
     326             :                  * linkstate of MPLS route is not tracked
     327             :                  */
     328           0 :                 if (!ISSET(ifp->if_flags, IFF_UP))
     329           0 :                         if_up(ifp);
     330           0 :                 ifm = ifp->if_softc;
     331           0 :                 if (ifm->sc_smpls.smpls_label) {
     332             :                         /* remove old MPLS route */
     333           0 :                         rt_ifa_del(&ifm->sc_ifa, RTF_MPLS,
     334           0 :                             smplstosa(&ifm->sc_smpls));
     335           0 :                 }
     336             :                 /* add new MPLS route */
     337           0 :                 ifm->sc_smpls.smpls_label = shim.shim_label;
     338           0 :                 error = rt_ifa_add(&ifm->sc_ifa, RTF_MPLS,
     339           0 :                     smplstosa(&ifm->sc_smpls));
     340           0 :                 if (error) {
     341           0 :                         ifm->sc_smpls.smpls_label = 0;
     342           0 :                         break;
     343             :                 }
     344             :                 break;
     345             :         case SIOCSIFRDOMAIN:
     346             :                 /* must readd the MPLS "route" for our label */
     347             :                 /* XXX does not make sense, the MPLS route is on rtable 0 */
     348           0 :                 ifm = ifp->if_softc;
     349           0 :                 if (ifr->ifr_rdomainid != ifp->if_rdomain) {
     350           0 :                         if (ifm->sc_smpls.smpls_label) {
     351           0 :                                 rt_ifa_add(&ifm->sc_ifa, RTF_MPLS,
     352           0 :                                     smplstosa(&ifm->sc_smpls));
     353           0 :                         }
     354             :                 }
     355             :                 /* return with ENOTTY so that the parent handler finishes */
     356           0 :                 return (ENOTTY);
     357             :         default:
     358           0 :                 return (ENOTTY);
     359             :         }
     360             : 
     361           0 :         return (error);
     362           0 : }
     363             : 
     364             : void
     365           0 : mpe_input(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls,
     366             :     u_int8_t ttl)
     367             : {
     368             :         struct ip       *ip;
     369             :         int              hlen;
     370             : 
     371             :         /* label -> AF lookup */
     372             : 
     373           0 :         if (mpls_mapttl_ip) {
     374           0 :                 if (m->m_len < sizeof (struct ip) &&
     375           0 :                     (m = m_pullup(m, sizeof(struct ip))) == NULL)
     376           0 :                         return;
     377           0 :                 ip = mtod(m, struct ip *);
     378           0 :                 hlen = ip->ip_hl << 2;
     379           0 :                 if (m->m_len < hlen) {
     380           0 :                         if ((m = m_pullup(m, hlen)) == NULL)
     381           0 :                                 return;
     382           0 :                         ip = mtod(m, struct ip *);
     383           0 :                 }
     384             : 
     385           0 :                 if (in_cksum(m, hlen) != 0) {
     386           0 :                         m_freem(m);
     387           0 :                         return;
     388             :                 }
     389             : 
     390             :                 /* set IP ttl from MPLS ttl */
     391           0 :                 ip->ip_ttl = ttl;
     392             : 
     393             :                 /* recalculate checksum */
     394           0 :                 ip->ip_sum = 0;
     395           0 :                 ip->ip_sum = in_cksum(m, hlen);
     396           0 :         }
     397             : 
     398             :         /* new receive if and move into correct rtable */
     399           0 :         m->m_pkthdr.ph_ifidx = ifp->if_index;
     400           0 :         m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
     401             : 
     402             : #if NBPFILTER > 0
     403           0 :         if (ifp->if_bpf)
     404           0 :                 bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_IN);
     405             : #endif
     406             : 
     407           0 :         ipv4_input(ifp, m);
     408           0 : }
     409             : 
     410             : #ifdef INET6
     411             : void
     412           0 : mpe_input6(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls,
     413             :     u_int8_t ttl)
     414             : {
     415             :         struct ip6_hdr *ip6hdr;
     416             : 
     417             :         /* label -> AF lookup */
     418             : 
     419           0 :         if (mpls_mapttl_ip6) {
     420           0 :                 if (m->m_len < sizeof (struct ip6_hdr) &&
     421           0 :                     (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
     422           0 :                         return;
     423             : 
     424           0 :                 ip6hdr = mtod(m, struct ip6_hdr *);
     425             : 
     426             :                 /* set IPv6 ttl from MPLS ttl */
     427           0 :                 ip6hdr->ip6_hlim = ttl;
     428           0 :         }
     429             : 
     430             :         /* new receive if and move into correct rtable */
     431           0 :         m->m_pkthdr.ph_ifidx = ifp->if_index;
     432           0 :         m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
     433             : 
     434             : #if NBPFILTER > 0
     435           0 :         if (ifp->if_bpf)
     436           0 :                 bpf_mtap_af(ifp->if_bpf, AF_INET6, m, BPF_DIRECTION_IN);
     437             : #endif
     438             : 
     439           0 :         ipv6_input(ifp, m);
     440           0 : }
     441             : #endif  /* INET6 */

Generated by: LCOV version 1.13