LCOV - code coverage report
Current view: top level - net - if_mpw.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 201 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_mpw.c,v 1.24 2018/02/19 08:59:52 mpi Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2015 Rafael Zalamena <rzalamena@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 "bpfilter.h"
      20             : #include "vlan.h"
      21             : 
      22             : #include <sys/param.h>
      23             : #include <sys/systm.h>
      24             : #include <sys/mbuf.h>
      25             : #include <sys/socket.h>
      26             : #include <sys/ioctl.h>
      27             : #include <sys/errno.h>
      28             : 
      29             : #include <net/if.h>
      30             : #include <net/if_dl.h>
      31             : #include <net/if_types.h>
      32             : #include <net/route.h>
      33             : 
      34             : #include <netinet/in.h>
      35             : 
      36             : #include <netinet/if_ether.h>
      37             : #include <netmpls/mpls.h>
      38             : 
      39             : #if NBPFILTER > 0
      40             : #include <net/bpf.h>
      41             : #endif /* NBPFILTER */
      42             : 
      43             : #if NVLAN > 0
      44             : #include <net/if_vlan_var.h>
      45             : #endif
      46             : 
      47             : struct mpw_softc {
      48             :         struct          ifnet sc_if;
      49             : 
      50             :         struct          ifaddr sc_ifa;
      51             :         struct          sockaddr_mpls sc_smpls; /* Local label */
      52             : 
      53             :         uint32_t        sc_flags;
      54             :         uint32_t        sc_type;
      55             :         struct          shim_hdr sc_rshim;
      56             :         struct          sockaddr_storage sc_nexthop;
      57             : };
      58             : 
      59             : void    mpwattach(int);
      60             : int     mpw_clone_create(struct if_clone *, int);
      61             : int     mpw_clone_destroy(struct ifnet *);
      62             : int     mpw_ioctl(struct ifnet *, u_long, caddr_t);
      63             : int     mpw_output(struct ifnet *, struct mbuf *, struct sockaddr *,
      64             :     struct rtentry *);
      65             : void    mpw_start(struct ifnet *);
      66             : int     mpw_input(struct ifnet *, struct mbuf *, void *);
      67             : #if NVLAN > 0
      68             : struct  mbuf *mpw_vlan_handle(struct mbuf *, struct mpw_softc *);
      69             : #endif /* NVLAN */
      70             : 
      71             : struct if_clone mpw_cloner =
      72             :     IF_CLONE_INITIALIZER("mpw", mpw_clone_create, mpw_clone_destroy);
      73             : 
      74             : void
      75           0 : mpwattach(int n)
      76             : {
      77           0 :         if_clone_attach(&mpw_cloner);
      78           0 : }
      79             : 
      80             : int
      81           0 : mpw_clone_create(struct if_clone *ifc, int unit)
      82             : {
      83             :         struct mpw_softc *sc;
      84             :         struct ifnet *ifp;
      85             : 
      86           0 :         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
      87           0 :         ifp = &sc->sc_if;
      88           0 :         snprintf(ifp->if_xname, sizeof(ifp->if_xname), "mpw%d", unit);
      89           0 :         ifp->if_softc = sc;
      90           0 :         ifp->if_mtu = ETHERMTU;
      91           0 :         ifp->if_flags = IFF_POINTOPOINT;
      92           0 :         ifp->if_xflags = IFXF_CLONED;
      93           0 :         ifp->if_ioctl = mpw_ioctl;
      94           0 :         ifp->if_output = mpw_output;
      95           0 :         ifp->if_start = mpw_start;
      96           0 :         ifp->if_type = IFT_MPLSTUNNEL;
      97           0 :         ifp->if_hdrlen = ETHER_HDR_LEN;
      98           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
      99             : 
     100           0 :         if_attach(ifp);
     101           0 :         if_alloc_sadl(ifp);
     102             : 
     103           0 :         sc->sc_ifa.ifa_ifp = ifp;
     104           0 :         sc->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl);
     105           0 :         sc->sc_smpls.smpls_len = sizeof(sc->sc_smpls);
     106           0 :         sc->sc_smpls.smpls_family = AF_MPLS;
     107             : 
     108           0 :         if_ih_insert(ifp, mpw_input, NULL);
     109             : 
     110             : #if NBPFILTER > 0
     111           0 :         bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
     112             : #endif /* NBFILTER */
     113             : 
     114           0 :         return (0);
     115             : }
     116             : 
     117             : int
     118           0 : mpw_clone_destroy(struct ifnet *ifp)
     119             : {
     120           0 :         struct mpw_softc *sc = ifp->if_softc;
     121             : 
     122           0 :         ifp->if_flags &= ~IFF_RUNNING;
     123             : 
     124           0 :         if (sc->sc_smpls.smpls_label) {
     125           0 :                 rt_ifa_del(&sc->sc_ifa, RTF_MPLS,
     126           0 :                     smplstosa(&sc->sc_smpls));
     127           0 :         }
     128             : 
     129           0 :         if_ih_remove(ifp, mpw_input, NULL);
     130             : 
     131           0 :         if_detach(ifp);
     132           0 :         free(sc, M_DEVBUF, sizeof(*sc));
     133             : 
     134           0 :         return (0);
     135             : }
     136             : 
     137             : int
     138           0 : mpw_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
     139             : {
     140             :         /* Don't have local broadcast. */
     141           0 :         m_freem(m);
     142           0 :         return (1);
     143             : }
     144             : 
     145             : int
     146           0 : mpw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     147             : {
     148           0 :         struct ifreq *ifr = (struct ifreq *) data;
     149           0 :         struct mpw_softc *sc = ifp->if_softc;
     150             :         struct sockaddr_in *sin;
     151             :         struct sockaddr_in *sin_nexthop;
     152             :         int error = 0;
     153           0 :         struct ifmpwreq imr;
     154             : 
     155           0 :         switch (cmd) {
     156             :         case SIOCSIFMTU:
     157           0 :                 if (ifr->ifr_mtu < MPE_MTU_MIN ||
     158           0 :                     ifr->ifr_mtu > MPE_MTU_MAX)
     159           0 :                         error = EINVAL;
     160             :                 else
     161           0 :                         ifp->if_mtu = ifr->ifr_mtu;
     162             :                 break;
     163             : 
     164             :         case SIOCSIFFLAGS:
     165           0 :                 if ((ifp->if_flags & IFF_UP))
     166           0 :                         ifp->if_flags |= IFF_RUNNING;
     167             :                 else
     168           0 :                         ifp->if_flags &= ~IFF_RUNNING;
     169             :                 break;
     170             : 
     171             :         case SIOCSETMPWCFG:
     172           0 :                 error = suser(curproc);
     173           0 :                 if (error != 0)
     174             :                         break;
     175             : 
     176           0 :                 error = copyin(ifr->ifr_data, &imr, sizeof(imr));
     177           0 :                 if (error != 0)
     178             :                         break;
     179             : 
     180             :                 /* Teardown all configuration if got no nexthop */
     181           0 :                 sin = (struct sockaddr_in *) &imr.imr_nexthop;
     182           0 :                 if (sin->sin_addr.s_addr == 0) {
     183           0 :                         if (rt_ifa_del(&sc->sc_ifa, RTF_MPLS,
     184           0 :                             smplstosa(&sc->sc_smpls)) == 0)
     185           0 :                                 sc->sc_smpls.smpls_label = 0;
     186             : 
     187           0 :                         memset(&sc->sc_rshim, 0, sizeof(sc->sc_rshim));
     188           0 :                         memset(&sc->sc_nexthop, 0, sizeof(sc->sc_nexthop));
     189           0 :                         sc->sc_flags = 0;
     190           0 :                         sc->sc_type = 0;
     191           0 :                         break;
     192             :                 }
     193             : 
     194             :                 /* Validate input */
     195           0 :                 if (sin->sin_family != AF_INET ||
     196           0 :                     imr.imr_lshim.shim_label > MPLS_LABEL_MAX ||
     197           0 :                     imr.imr_lshim.shim_label <= MPLS_LABEL_RESERVED_MAX ||
     198           0 :                     imr.imr_rshim.shim_label > MPLS_LABEL_MAX ||
     199           0 :                     imr.imr_rshim.shim_label <= MPLS_LABEL_RESERVED_MAX) {
     200             :                         error = EINVAL;
     201           0 :                         break;
     202             :                 }
     203             : 
     204             :                 /* Setup labels and create inbound route */
     205           0 :                 imr.imr_lshim.shim_label =
     206           0 :                     htonl(imr.imr_lshim.shim_label << MPLS_LABEL_OFFSET);
     207           0 :                 imr.imr_rshim.shim_label =
     208           0 :                     htonl(imr.imr_rshim.shim_label << MPLS_LABEL_OFFSET);
     209             : 
     210           0 :                 if (sc->sc_smpls.smpls_label != imr.imr_lshim.shim_label) {
     211           0 :                         if (sc->sc_smpls.smpls_label)
     212           0 :                                 rt_ifa_del(&sc->sc_ifa, RTF_MPLS,
     213           0 :                                     smplstosa(&sc->sc_smpls));
     214             : 
     215           0 :                         sc->sc_smpls.smpls_label = imr.imr_lshim.shim_label;
     216           0 :                         error = rt_ifa_add(&sc->sc_ifa, RTF_MPLS,
     217           0 :                             smplstosa(&sc->sc_smpls));
     218           0 :                         if (error != 0) {
     219           0 :                                 sc->sc_smpls.smpls_label = 0;
     220           0 :                                 break;
     221             :                         }
     222             :                 }
     223             : 
     224             :                 /* Apply configuration */
     225           0 :                 sc->sc_flags = imr.imr_flags;
     226           0 :                 sc->sc_type = imr.imr_type;
     227           0 :                 sc->sc_rshim.shim_label = imr.imr_rshim.shim_label;
     228           0 :                 sc->sc_rshim.shim_label |= MPLS_BOS_MASK;
     229             : 
     230           0 :                 memset(&sc->sc_nexthop, 0, sizeof(sc->sc_nexthop));
     231           0 :                 sin_nexthop = (struct sockaddr_in *) &sc->sc_nexthop;
     232           0 :                 sin_nexthop->sin_family = sin->sin_family;
     233           0 :                 sin_nexthop->sin_len = sizeof(struct sockaddr_in);
     234           0 :                 sin_nexthop->sin_addr.s_addr = sin->sin_addr.s_addr;
     235           0 :                 break;
     236             : 
     237             :         case SIOCGETMPWCFG:
     238           0 :                 imr.imr_flags = sc->sc_flags;
     239           0 :                 imr.imr_type = sc->sc_type;
     240           0 :                 imr.imr_lshim.shim_label =
     241           0 :                     ((ntohl(sc->sc_smpls.smpls_label & MPLS_LABEL_MASK)) >>
     242             :                         MPLS_LABEL_OFFSET);
     243           0 :                 imr.imr_rshim.shim_label =
     244           0 :                     ((ntohl(sc->sc_rshim.shim_label & MPLS_LABEL_MASK)) >>
     245             :                         MPLS_LABEL_OFFSET);
     246           0 :                 memcpy(&imr.imr_nexthop, &sc->sc_nexthop,
     247             :                     sizeof(imr.imr_nexthop));
     248             : 
     249           0 :                 error = copyout(&imr, ifr->ifr_data, sizeof(imr));
     250           0 :                 break;
     251             : 
     252             :         default:
     253             :                 error = ENOTTY;
     254           0 :                 break;
     255             :         }
     256             : 
     257           0 :         return (error);
     258           0 : }
     259             : 
     260             : int
     261           0 : mpw_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
     262             :     struct rtentry *rt)
     263             : {
     264           0 :         struct mpw_softc *sc = ifp->if_softc;
     265           0 :         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
     266           0 :         struct ether_header *eh, ehc;
     267             :         struct shim_hdr *shim;
     268             : 
     269           0 :         if (sc->sc_type == IMR_TYPE_NONE) {
     270           0 :                 m_freem(m);
     271           0 :                 return (EHOSTUNREACH);
     272             :         }
     273             : 
     274           0 :         if (sc->sc_flags & IMR_FLAG_CONTROLWORD) {
     275           0 :                 shim = mtod(m, struct shim_hdr *);
     276           0 :                 m_adj(m, MPLS_HDRLEN);
     277             : 
     278             :                 /*
     279             :                  * The first 4 bits identifies that this packet is a
     280             :                  * control word. If the control word is configured and
     281             :                  * we received an IP datagram we shall drop it.
     282             :                  */
     283           0 :                 if (shim->shim_label & CW_ZERO_MASK) {
     284           0 :                         ifp->if_ierrors++;
     285           0 :                         m_freem(m);
     286           0 :                         return (EINVAL);
     287             :                 }
     288             : 
     289             :                 /* We don't support fragmentation just yet. */
     290           0 :                 if (shim->shim_label & CW_FRAG_MASK) {
     291           0 :                         ifp->if_ierrors++;
     292           0 :                         m_freem(m);
     293           0 :                         return (EINVAL);
     294             :                 }
     295             :         }
     296             : 
     297           0 :         if (sc->sc_type == IMR_TYPE_ETHERNET_TAGGED) {
     298           0 :                 m_copydata(m, 0, sizeof(ehc), (caddr_t) &ehc);
     299           0 :                 m_adj(m, ETHER_HDR_LEN);
     300             : 
     301             :                 /* Ethernet tagged expects at least 2 VLANs */
     302           0 :                 if (ntohs(ehc.ether_type) != ETHERTYPE_QINQ) {
     303           0 :                         ifp->if_ierrors++;
     304           0 :                         m_freem(m);
     305           0 :                         return (EINVAL);
     306             :                 }
     307             : 
     308             :                 /* Remove dummy VLAN and update ethertype */
     309           0 :                 if (EVL_VLANOFTAG(*mtod(m, uint16_t *)) == 0) {
     310           0 :                         m_adj(m, EVL_ENCAPLEN);
     311           0 :                         ehc.ether_type = htons(ETHERTYPE_VLAN);
     312           0 :                 }
     313             : 
     314           0 :                 M_PREPEND(m, sizeof(*eh), M_NOWAIT);
     315           0 :                 if (m == NULL)
     316           0 :                         return (ENOMEM);
     317             : 
     318           0 :                 eh = mtod(m, struct ether_header *);
     319           0 :                 memcpy(eh, &ehc, sizeof(*eh));
     320           0 :         }
     321             : 
     322           0 :         ml_enqueue(&ml, m);
     323           0 :         if_input(ifp, &ml);
     324             : 
     325           0 :         return (0);
     326           0 : }
     327             : 
     328             : #if NVLAN > 0
     329             : extern void vlan_start(struct ifqueue *);
     330             : 
     331             : /*
     332             :  * This routine handles VLAN tag reinsertion in packets flowing through
     333             :  * the pseudowire. Also it does the necessary modifications to the VLANs
     334             :  * to respect the RFC.
     335             :  */
     336             : struct mbuf *
     337           0 : mpw_vlan_handle(struct mbuf *m, struct mpw_softc *sc)
     338             : {
     339             :         struct ifnet *ifp;
     340             :         struct ifvlan *ifv;
     341             : 
     342             :         uint16_t type = ETHERTYPE_QINQ;
     343             :         uint16_t tag = 0;
     344             : 
     345           0 :         ifp = if_get(m->m_pkthdr.ph_ifidx);
     346           0 :         if (ifp != NULL && ifp->if_qstart == vlan_start &&
     347           0 :             ISSET(ifp->if_flags, IFF_RUNNING)) {
     348           0 :                 ifv = ifp->if_softc;
     349           0 :                 type = ifv->ifv_type;
     350           0 :                 tag = ifv->ifv_tag;
     351           0 :         }
     352           0 :         if_put(ifp);
     353             : 
     354           0 :         return (vlan_inject(m, type, tag));
     355             : }
     356             : #endif /* NVLAN */
     357             : 
     358             : void
     359           0 : mpw_start(struct ifnet *ifp)
     360             : {
     361           0 :         struct mpw_softc *sc = ifp->if_softc;
     362             :         struct rtentry *rt;
     363             :         struct ifnet *p;
     364             :         struct mbuf *m;
     365             :         struct shim_hdr *shim;
     366           0 :         struct sockaddr_storage ss;
     367             : 
     368           0 :         if (!ISSET(ifp->if_flags, IFF_RUNNING) ||
     369           0 :             sc->sc_rshim.shim_label == 0 ||
     370           0 :             sc->sc_type == IMR_TYPE_NONE) {
     371           0 :                 IFQ_PURGE(&ifp->if_snd);
     372           0 :                 return;
     373             :         }
     374             : 
     375           0 :         rt = rtalloc(sstosa(&sc->sc_nexthop), RT_RESOLVE, ifp->if_rdomain);
     376           0 :         if (!rtisvalid(rt)) {
     377           0 :                 IFQ_PURGE(&ifp->if_snd);
     378           0 :                 goto rtfree;
     379             :         }
     380             : 
     381           0 :         p = if_get(rt->rt_ifidx);
     382           0 :         if (p == NULL) {
     383           0 :                 IFQ_PURGE(&ifp->if_snd);
     384           0 :                 goto rtfree;
     385             :         }
     386             : 
     387             :         /*
     388             :          * XXX: lie about being MPLS, so mpls_output() get the TTL from
     389             :          * the right place.
     390             :          */
     391           0 :         memcpy(&ss, &sc->sc_nexthop, sizeof(sc->sc_nexthop));
     392           0 :         ss.ss_family = AF_MPLS;
     393             : 
     394           0 :         while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
     395             : #if NBPFILTER > 0
     396           0 :                 if (sc->sc_if.if_bpf)
     397           0 :                         bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT);
     398             : #endif /* NBPFILTER */
     399             : 
     400           0 :                 if (sc->sc_type == IMR_TYPE_ETHERNET_TAGGED) {
     401             :  #if NVLAN > 0
     402           0 :                         m = mpw_vlan_handle(m, sc);
     403           0 :                         if (m == NULL) {
     404           0 :                                 ifp->if_oerrors++;
     405           0 :                                 continue;
     406             :                         }
     407             :  #else
     408             :                         /* Ethernet tagged doesn't work without VLANs'*/
     409             :                         m_freem(m);
     410             :                         continue;
     411             :  #endif /* NVLAN */
     412             :                 }
     413             : 
     414           0 :                 if (sc->sc_flags & IMR_FLAG_CONTROLWORD) {
     415           0 :                         M_PREPEND(m, sizeof(*shim), M_NOWAIT);
     416           0 :                         if (m == NULL)
     417           0 :                                 continue;
     418             : 
     419           0 :                         shim = mtod(m, struct shim_hdr *);
     420           0 :                         memset(shim, 0, sizeof(*shim));
     421           0 :                 }
     422             : 
     423           0 :                 M_PREPEND(m, sizeof(*shim), M_NOWAIT);
     424           0 :                 if (m == NULL)
     425           0 :                         continue;
     426             : 
     427           0 :                 shim = mtod(m, struct shim_hdr *);
     428           0 :                 shim->shim_label = htonl(mpls_defttl) & MPLS_TTL_MASK;
     429           0 :                 shim->shim_label |= sc->sc_rshim.shim_label;
     430             : 
     431           0 :                 m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
     432             : 
     433           0 :                 mpls_output(p, m, sstosa(&ss), rt);
     434             :         }
     435             : 
     436           0 :         if_put(p);
     437             : rtfree:
     438           0 :         rtfree(rt);
     439           0 : }

Generated by: LCOV version 1.13