LCOV - code coverage report
Current view: top level - net - if_pair.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 125 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_pair.c,v 1.11 2018/01/09 15:24:24 bluhm Exp $      */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
       5             :  * Copyright (c) 2009 Theo de Raadt <deraadt@openbsd.org>
       6             :  *
       7             :  * Permission to use, copy, modify, and distribute this software for any
       8             :  * purpose with or without fee is hereby granted, provided that the above
       9             :  * copyright notice and this permission notice appear in all copies.
      10             :  *
      11             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18             :  */
      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_media.h>
      29             : 
      30             : #include <netinet/in.h>
      31             : #include <netinet/if_ether.h>
      32             : 
      33             : #include "bpfilter.h"
      34             : #if NBPFILTER > 0
      35             : #include <net/bpf.h>
      36             : #endif
      37             : 
      38             : void    pairattach(int);
      39             : int     pairioctl(struct ifnet *, u_long, caddr_t);
      40             : void    pairstart(struct ifnet *);
      41             : int     pair_clone_create(struct if_clone *, int);
      42             : int     pair_clone_destroy(struct ifnet *);
      43             : int     pair_media_change(struct ifnet *);
      44             : void    pair_media_status(struct ifnet *, struct ifmediareq *);
      45             : void    pair_link_state(struct ifnet *);
      46             : 
      47             : struct pair_softc {
      48             :         struct arpcom           sc_ac;
      49             :         struct ifmedia          sc_media;
      50             :         unsigned int            sc_pairedif;
      51             : };
      52             : 
      53             : struct if_clone pair_cloner =
      54             :     IF_CLONE_INITIALIZER("pair", pair_clone_create, pair_clone_destroy);
      55             : 
      56             : int
      57           0 : pair_media_change(struct ifnet *ifp)
      58             : {
      59           0 :         return (0);
      60             : }
      61             : 
      62             : void
      63           0 : pair_media_status(struct ifnet *ifp, struct ifmediareq *imr)
      64             : {
      65           0 :         struct pair_softc       *sc = ifp->if_softc;
      66             :         struct ifnet            *pairedifp;
      67             : 
      68           0 :         imr->ifm_active = IFM_ETHER | IFM_AUTO;
      69             : 
      70           0 :         if ((pairedifp = if_get(sc->sc_pairedif)) == NULL) {
      71           0 :                 imr->ifm_status = 0;
      72           0 :                 return;
      73             :         }
      74           0 :         if_put(pairedifp);
      75             : 
      76           0 :         imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
      77           0 : }
      78             : 
      79             : void
      80           0 : pair_link_state(struct ifnet *ifp)
      81             : {
      82           0 :         struct pair_softc       *sc = ifp->if_softc;
      83             :         struct ifnet            *pairedifp;
      84             :         unsigned int             link_state;
      85             : 
      86             :         /* The pair state is determined by the paired interface */
      87           0 :         if ((pairedifp = if_get(sc->sc_pairedif)) != NULL) {
      88             :                 link_state = LINK_STATE_UP;
      89           0 :                 if_put(pairedifp);
      90           0 :         } else
      91             :                 link_state = LINK_STATE_DOWN;
      92             : 
      93           0 :         if (ifp->if_link_state != link_state) {
      94           0 :                 ifp->if_link_state = link_state;
      95           0 :                 if_link_state_change(ifp);
      96           0 :         }
      97           0 : }
      98             : 
      99             : void
     100           0 : pairattach(int npair)
     101             : {
     102           0 :         if_clone_attach(&pair_cloner);
     103           0 : }
     104             : 
     105             : int
     106           0 : pair_clone_create(struct if_clone *ifc, int unit)
     107             : {
     108             :         struct ifnet            *ifp;
     109             :         struct pair_softc       *sc;
     110             : 
     111           0 :         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
     112           0 :         ifp = &sc->sc_ac.ac_if;
     113           0 :         snprintf(ifp->if_xname, sizeof ifp->if_xname, "pair%d", unit);
     114           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     115           0 :         ether_fakeaddr(ifp);
     116             : 
     117           0 :         ifp->if_softc = sc;
     118           0 :         ifp->if_ioctl = pairioctl;
     119           0 :         ifp->if_start = pairstart;
     120           0 :         ifp->if_xflags = IFXF_CLONED;
     121           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
     122             : 
     123           0 :         ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN;
     124           0 :         ifp->if_capabilities = IFCAP_VLAN_MTU;
     125             : 
     126           0 :         ifmedia_init(&sc->sc_media, 0, pair_media_change,
     127             :             pair_media_status);
     128           0 :         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
     129           0 :         ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
     130             : 
     131           0 :         if_attach(ifp);
     132           0 :         ether_ifattach(ifp);
     133             : 
     134           0 :         pair_link_state(ifp);
     135             : 
     136           0 :         return (0);
     137             : }
     138             : 
     139             : int
     140           0 : pair_clone_destroy(struct ifnet *ifp)
     141             : {
     142           0 :         struct pair_softc       *sc = ifp->if_softc;
     143             :         struct ifnet            *pairedifp;
     144             :         struct pair_softc       *dstsc = ifp->if_softc;
     145             : 
     146           0 :         if ((pairedifp = if_get(sc->sc_pairedif)) != NULL) {
     147           0 :                 dstsc = pairedifp->if_softc;
     148           0 :                 dstsc->sc_pairedif = 0;
     149           0 :                 pair_link_state(pairedifp);
     150           0 :                 if_put(pairedifp);
     151           0 :         }
     152             : 
     153           0 :         ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
     154           0 :         ether_ifdetach(ifp);
     155           0 :         if_detach(ifp);
     156           0 :         free(sc, M_DEVBUF, sizeof(*sc));
     157             : 
     158           0 :         return (0);
     159             : }
     160             : 
     161             : void
     162           0 : pairstart(struct ifnet *ifp)
     163             : {
     164           0 :         struct pair_softc       *sc = (struct pair_softc *)ifp->if_softc;
     165           0 :         struct mbuf_list         ml = MBUF_LIST_INITIALIZER();
     166             :         struct ifnet            *pairedifp;
     167             :         struct mbuf             *m;
     168             : 
     169           0 :         pairedifp = if_get(sc->sc_pairedif);
     170             : 
     171           0 :         for (;;) {
     172           0 :                 IFQ_DEQUEUE(&ifp->if_snd, m);
     173           0 :                 if (m == NULL)
     174             :                         break;
     175             : 
     176             : #if NBPFILTER > 0
     177           0 :                 if (ifp->if_bpf)
     178           0 :                         bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
     179             : #endif /* NBPFILTER > 0 */
     180             : 
     181           0 :                 if (pairedifp != NULL) {
     182           0 :                         if (m->m_flags & M_PKTHDR)
     183           0 :                                 m_resethdr(m);
     184           0 :                         ml_enqueue(&ml, m);
     185           0 :                 } else
     186           0 :                         m_freem(m);
     187             :         }
     188             : 
     189           0 :         if (pairedifp != NULL) {
     190           0 :                 if_input(pairedifp, &ml);
     191           0 :                 if_put(pairedifp);
     192           0 :         }
     193           0 : }
     194             : 
     195             : int
     196           0 : pairioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     197             : {
     198           0 :         struct pair_softc       *sc = (struct pair_softc *)ifp->if_softc;
     199           0 :         struct ifreq            *ifr = (struct ifreq *)data;
     200             :         struct if_clone         *ifc;
     201             :         struct pair_softc       *pairedsc = ifp->if_softc;
     202             :         struct ifnet            *oldifp = NULL, *newifp = NULL;
     203           0 :         int                      error = 0, unit;
     204             : 
     205           0 :         switch (cmd) {
     206             :         case SIOCSIFADDR:
     207           0 :                 ifp->if_flags |= IFF_UP;
     208             :                 /* FALLTHROUGH */
     209             : 
     210             :         case SIOCSIFFLAGS:
     211           0 :                 if (ifp->if_flags & IFF_UP)
     212           0 :                         ifp->if_flags |= IFF_RUNNING;
     213             :                 else
     214           0 :                         ifp->if_flags &= ~IFF_RUNNING;
     215             :                 break;
     216             : 
     217             :         case SIOCADDMULTI:
     218             :         case SIOCDELMULTI:
     219             :                 break;
     220             : 
     221             :         case SIOCGIFMEDIA:
     222             :         case SIOCSIFMEDIA:
     223           0 :                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
     224           0 :                 break;
     225             : 
     226             :         case SIOCSIFPAIR:
     227           0 :                 if (sc->sc_pairedif == ifr->ifr_index)
     228             :                         break;
     229             : 
     230             :                 /* Cannot link to myself */
     231           0 :                 if (ifr->ifr_index == ifp->if_index) {
     232             :                         error = EINVAL;
     233           0 :                         break;
     234             :                 }
     235             : 
     236           0 :                 oldifp = if_get(sc->sc_pairedif);
     237           0 :                 newifp = if_get(ifr->ifr_index);
     238             : 
     239           0 :                 if (newifp != NULL) {
     240           0 :                         pairedsc = newifp->if_softc;
     241             : 
     242           0 :                         if (pairedsc->sc_pairedif != 0) {
     243             :                                 error = EBUSY;
     244           0 :                                 break;
     245             :                         }
     246             : 
     247             :                         /* Only allow pair(4) interfaces for the pair */
     248           0 :                         if ((ifc = if_clone_lookup(newifp->if_xname,
     249           0 :                             &unit)) == NULL || strcmp("pair",
     250           0 :                             ifc->ifc_name) != 0) {
     251             :                                 error = ENODEV;
     252           0 :                                 break;
     253             :                         }
     254             : 
     255           0 :                         pairedsc->sc_pairedif = ifp->if_index;
     256           0 :                         sc->sc_pairedif = ifr->ifr_index;
     257           0 :                 } else
     258           0 :                         sc->sc_pairedif = 0;
     259             : 
     260           0 :                 if (oldifp != NULL) {
     261           0 :                         pairedsc = oldifp->if_softc;
     262           0 :                         pairedsc->sc_pairedif = 0;
     263           0 :                 }
     264             :                 break;
     265             : 
     266             :         case SIOCGIFPAIR:
     267           0 :                 ifr->ifr_index = sc->sc_pairedif;
     268           0 :                 break;
     269             : 
     270             :         default:
     271           0 :                 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
     272           0 :         }
     273             : 
     274           0 :         if (newifp != NULL || oldifp != NULL)
     275           0 :                 pair_link_state(ifp);
     276           0 :         if (oldifp != NULL) {
     277           0 :                 pair_link_state(oldifp);
     278           0 :                 if_put(oldifp);
     279           0 :         }
     280           0 :         if (newifp != NULL) {
     281           0 :                 pair_link_state(newifp);
     282           0 :                 if_put(newifp);
     283           0 :         }
     284             : 
     285           0 :         return (error);
     286           0 : }

Generated by: LCOV version 1.13