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

          Line data    Source code
       1             : /*      $OpenBSD: if_etherip.c,v 1.37 2018/02/19 00:29:29 dlg Exp $     */
       2             : /*
       3             :  * Copyright (c) 2015 Kazuya GODA <goda@openbsd.org>
       4             :  *
       5             :  * Permission to use, copy, modify, and distribute this software for any
       6             :  * purpose with or without fee is hereby granted, provided that the above
       7             :  * copyright notice and this permission notice appear in all copies.
       8             :  *
       9             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      10             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      11             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      12             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      13             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      14             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      15             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      16             :  */
      17             : 
      18             : #include "bpfilter.h"
      19             : #include "pf.h"
      20             : 
      21             : #include <sys/param.h>
      22             : #include <sys/systm.h>
      23             : #include <sys/mbuf.h>
      24             : #include <sys/socket.h>
      25             : #include <sys/ioctl.h>
      26             : #include <sys/device.h>
      27             : #include <sys/sysctl.h>
      28             : #include <sys/tree.h>
      29             : 
      30             : #include <net/if.h>
      31             : #include <net/if_var.h>
      32             : #include <net/if_dl.h>
      33             : #include <net/if_media.h>
      34             : #include <net/rtable.h>
      35             : 
      36             : #include <netinet/in.h>
      37             : #include <netinet/ip.h>
      38             : #include <netinet/ip_var.h>
      39             : #include <netinet/if_ether.h>
      40             : #include <netinet/ip_ether.h>
      41             : 
      42             : #ifdef INET6
      43             : #include <netinet/ip6.h>
      44             : #include <netinet6/ip6_var.h>
      45             : #endif
      46             : 
      47             : #if NBPFILTER > 0
      48             : #include <net/bpf.h>
      49             : #endif
      50             : 
      51             : #if NPF > 0
      52             : #include <net/pfvar.h>
      53             : #endif
      54             : 
      55             : #include <net/if_etherip.h>
      56             : 
      57             : union etherip_addr {
      58             :         struct in_addr  in4;
      59             :         struct in6_addr in6;
      60             : };
      61             : 
      62             : struct etherip_tunnel {
      63             :         union etherip_addr
      64             :                         _t_src;
      65             : #define t_src4  _t_src.in4
      66             : #define t_src6  _t_src.in6
      67             :         union etherip_addr
      68             :                         _t_dst;
      69             : #define t_dst4  _t_dst.in4
      70             : #define t_dst6  _t_dst.in6
      71             : 
      72             :         unsigned int    t_rtableid;
      73             :         sa_family_t     t_af;
      74             : 
      75             :         TAILQ_ENTRY(etherip_tunnel)
      76             :                         t_entry;
      77             : };
      78             : 
      79             : TAILQ_HEAD(etherip_list, etherip_tunnel);
      80             : 
      81             : static inline int etherip_cmp(const struct etherip_tunnel *,
      82             :     const struct etherip_tunnel *);
      83             : 
      84             : struct etherip_softc {
      85             :         struct etherip_tunnel   sc_tunnel; /* must be first */
      86             :         struct arpcom           sc_ac;
      87             :         struct ifmedia          sc_media;
      88             :         uint16_t                sc_df;
      89             :         uint8_t                 sc_ttl;
      90             : };
      91             : 
      92             : /*
      93             :  * We can control the acceptance of EtherIP packets by altering the sysctl
      94             :  * net.inet.etherip.allow value. Zero means drop them, all else is acceptance.
      95             :  */
      96             : int etherip_allow = 0;
      97             : 
      98             : struct cpumem *etheripcounters;
      99             : 
     100             : void etheripattach(int);
     101             : int etherip_clone_create(struct if_clone *, int);
     102             : int etherip_clone_destroy(struct ifnet *);
     103             : int etherip_ioctl(struct ifnet *, u_long, caddr_t);
     104             : void etherip_start(struct ifnet *);
     105             : int etherip_media_change(struct ifnet *);
     106             : void etherip_media_status(struct ifnet *, struct ifmediareq *);
     107             : int etherip_set_tunnel(struct etherip_softc *, struct if_laddrreq *);
     108             : int etherip_get_tunnel(struct etherip_softc *, struct if_laddrreq *);
     109             : int etherip_del_tunnel(struct etherip_softc *);
     110             : int etherip_up(struct etherip_softc *);
     111             : int etherip_down(struct etherip_softc *);
     112             : struct etherip_softc *etherip_find(const struct etherip_tunnel *);
     113             : int etherip_input(struct etherip_tunnel *, struct mbuf *, int);
     114             : 
     115             : struct if_clone etherip_cloner = IF_CLONE_INITIALIZER("etherip",
     116             :     etherip_clone_create, etherip_clone_destroy);
     117             : 
     118             : struct etherip_list etherip_list = TAILQ_HEAD_INITIALIZER(etherip_list);
     119             : 
     120             : void
     121           0 : etheripattach(int count)
     122             : {
     123           0 :         if_clone_attach(&etherip_cloner);
     124           0 :         etheripcounters = counters_alloc(etherips_ncounters);
     125           0 : }
     126             : 
     127             : int
     128           0 : etherip_clone_create(struct if_clone *ifc, int unit)
     129             : {
     130             :         struct ifnet *ifp;
     131             :         struct etherip_softc *sc;
     132             : 
     133           0 :         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
     134           0 :         ifp = &sc->sc_ac.ac_if;
     135             : 
     136           0 :         snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
     137           0 :             ifc->ifc_name, unit);
     138             : 
     139           0 :         sc->sc_ttl = ip_defttl;
     140           0 :         sc->sc_df = htons(0);
     141             : 
     142           0 :         ifp->if_softc = sc;
     143           0 :         ifp->if_ioctl = etherip_ioctl;
     144           0 :         ifp->if_start = etherip_start;
     145           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     146           0 :         ifp->if_xflags = IFXF_CLONED;
     147           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
     148           0 :         ifp->if_capabilities = IFCAP_VLAN_MTU;
     149           0 :         ether_fakeaddr(ifp);
     150             : 
     151           0 :         ifmedia_init(&sc->sc_media, 0, etherip_media_change,
     152             :             etherip_media_status);
     153           0 :         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
     154           0 :         ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
     155             : 
     156           0 :         if_attach(ifp);
     157           0 :         ether_ifattach(ifp);
     158             : 
     159           0 :         NET_LOCK();
     160           0 :         TAILQ_INSERT_TAIL(&etherip_list, &sc->sc_tunnel, t_entry);
     161           0 :         NET_UNLOCK();
     162             : 
     163           0 :         return (0);
     164             : }
     165             : 
     166             : int
     167           0 : etherip_clone_destroy(struct ifnet *ifp)
     168             : {
     169           0 :         struct etherip_softc *sc = ifp->if_softc;
     170             : 
     171           0 :         NET_LOCK();
     172           0 :         if (ISSET(ifp->if_flags, IFF_RUNNING))
     173           0 :                 etherip_down(sc);
     174             : 
     175           0 :         TAILQ_REMOVE(&etherip_list, &sc->sc_tunnel, t_entry);
     176           0 :         NET_UNLOCK();
     177             : 
     178           0 :         ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
     179           0 :         ether_ifdetach(ifp);
     180           0 :         if_detach(ifp);
     181             : 
     182           0 :         free(sc, M_DEVBUF, sizeof(*sc));
     183             : 
     184           0 :         return (0);
     185             : }
     186             : 
     187             : int
     188           0 : etherip_media_change(struct ifnet *ifp)
     189             : {
     190           0 :         return 0;
     191             : }
     192             : 
     193             : void
     194           0 : etherip_media_status(struct ifnet *ifp, struct ifmediareq *imr)
     195             : {
     196           0 :         imr->ifm_active = IFM_ETHER | IFM_AUTO;
     197           0 :         imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
     198           0 : }
     199             : 
     200             : void
     201           0 : etherip_start(struct ifnet *ifp)
     202             : {
     203           0 :         struct etherip_softc *sc = ifp->if_softc;
     204             :         struct mbuf *m;
     205             :         int error;
     206             : #if NBPFILTER > 0
     207             :         caddr_t if_bpf;
     208             : #endif
     209             : 
     210           0 :         while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
     211             : #if NBPFILTER > 0
     212           0 :                 if_bpf = ifp->if_bpf;
     213           0 :                 if (if_bpf)
     214           0 :                         bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT);
     215             : #endif
     216             : 
     217           0 :                 switch (sc->sc_tunnel.t_af) {
     218             :                 case AF_INET:
     219           0 :                         error = ip_etherip_output(ifp, m);
     220           0 :                         break;
     221             : #ifdef INET6
     222             :                 case AF_INET6:
     223           0 :                         error = ip6_etherip_output(ifp, m);
     224           0 :                         break;
     225             : #endif
     226             :                 default:
     227             :                         /* unhandled_af(sc->sc_tunnel.t_af); */
     228           0 :                         m_freem(m);
     229           0 :                         continue;
     230             :                 }
     231             : 
     232           0 :                 if (error)
     233           0 :                         ifp->if_oerrors++;
     234             :         }
     235           0 : }
     236             : 
     237             : int
     238           0 : etherip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     239             : {
     240           0 :         struct etherip_softc *sc = ifp->if_softc;
     241           0 :         struct ifreq *ifr = (struct ifreq *)data;
     242             :         int error = 0;
     243             : 
     244           0 :         switch (cmd) {
     245             :         case SIOCSIFADDR:
     246           0 :                 ifp->if_flags |= IFF_UP;
     247             :                 /* FALLTHROUGH */
     248             : 
     249             :         case SIOCSIFFLAGS:
     250           0 :                 if (ISSET(ifp->if_flags, IFF_UP)) {
     251           0 :                         if (!ISSET(ifp->if_flags, IFF_RUNNING))
     252           0 :                                 error = etherip_up(sc);
     253             :                         else
     254             :                                 error = 0;
     255             :                 } else {
     256           0 :                         if (ISSET(ifp->if_flags, IFF_RUNNING))
     257           0 :                                 error = etherip_down(sc);
     258             :                 }
     259             :                 break;
     260             : 
     261             :         case SIOCSLIFPHYRTABLE:
     262           0 :                 if (ifr->ifr_rdomainid < 0 ||
     263           0 :                     ifr->ifr_rdomainid > RT_TABLEID_MAX ||
     264           0 :                     !rtable_exists(ifr->ifr_rdomainid)) {
     265             :                         error = EINVAL;
     266           0 :                         break;
     267             :                 }
     268           0 :                 sc->sc_tunnel.t_rtableid = ifr->ifr_rdomainid;
     269           0 :                 break;
     270             : 
     271             :         case SIOCGLIFPHYRTABLE:
     272           0 :                 ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid;
     273           0 :                 break;
     274             : 
     275             :         case SIOCSLIFPHYADDR:
     276           0 :                 error = etherip_set_tunnel(sc, (struct if_laddrreq *)data);
     277           0 :                 break;
     278             :         case SIOCGLIFPHYADDR:
     279           0 :                 error = etherip_get_tunnel(sc, (struct if_laddrreq *)data);
     280           0 :                 break;
     281             :         case SIOCDIFPHYADDR:
     282           0 :                 error = etherip_del_tunnel(sc);
     283           0 :                 break;
     284             : 
     285             :         case SIOCSLIFPHYTTL:
     286           0 :                 if (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff) {
     287             :                         error = EINVAL;
     288           0 :                         break;
     289             :                 }
     290             : 
     291             :                 /* commit */
     292           0 :                 sc->sc_ttl = (uint8_t)ifr->ifr_ttl;
     293           0 :                 break;
     294             :         case SIOCGLIFPHYTTL:
     295           0 :                 ifr->ifr_ttl = (int)sc->sc_ttl;
     296           0 :                 break;
     297             : 
     298             :         case SIOCSLIFPHYDF:
     299             :                 /* commit */
     300           0 :                 sc->sc_df = ifr->ifr_df ? htons(IP_DF) : htons(0);
     301           0 :                 break;
     302             :         case SIOCGLIFPHYDF:
     303           0 :                 ifr->ifr_df = sc->sc_df ? 1 : 0;
     304           0 :                 break;
     305             : 
     306             :         case SIOCSIFMEDIA:
     307             :         case SIOCGIFMEDIA:
     308           0 :                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
     309           0 :                 break;
     310             : 
     311             :         default:
     312           0 :                 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
     313           0 :                 break;
     314             :         }
     315             : 
     316           0 :         return (error);
     317             : }
     318             : 
     319             : int
     320           0 : etherip_set_tunnel(struct etherip_softc *sc, struct if_laddrreq *req)
     321             : {
     322           0 :         struct sockaddr *src = (struct sockaddr *)&req->addr;
     323           0 :         struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
     324             :         struct sockaddr_in *src4, *dst4;
     325             : #ifdef INET6
     326             :         struct sockaddr_in6 *src6, *dst6;
     327             :         int error;
     328             : #endif
     329             : 
     330             :         /* sa_family and sa_len must be equal */
     331           0 :         if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len)
     332           0 :                 return (EINVAL);
     333             : 
     334             :         /* validate */
     335           0 :         switch (dst->sa_family) {
     336             :         case AF_INET:
     337           0 :                 if (dst->sa_len != sizeof(*dst4))
     338           0 :                         return (EINVAL);
     339             : 
     340           0 :                 src4 = (struct sockaddr_in *)src;
     341           0 :                 if (in_nullhost(src4->sin_addr) ||
     342           0 :                     IN_MULTICAST(src4->sin_addr.s_addr))
     343           0 :                         return (EINVAL);
     344             : 
     345           0 :                 dst4 = (struct sockaddr_in *)dst;
     346           0 :                 if (in_nullhost(dst4->sin_addr) ||
     347           0 :                     IN_MULTICAST(dst4->sin_addr.s_addr))
     348           0 :                         return (EINVAL);
     349             : 
     350           0 :                 sc->sc_tunnel.t_src4 = src4->sin_addr;
     351           0 :                 sc->sc_tunnel.t_dst4 = dst4->sin_addr;
     352           0 :                 break;
     353             : #ifdef INET6
     354             :         case AF_INET6:
     355           0 :                 if (dst->sa_len != sizeof(*dst6))
     356           0 :                         return (EINVAL);
     357             : 
     358           0 :                 src6 = (struct sockaddr_in6 *)src;
     359           0 :                 if (IN6_IS_ADDR_UNSPECIFIED(&src6->sin6_addr) ||
     360           0 :                     IN6_IS_ADDR_MULTICAST(&src6->sin6_addr))
     361           0 :                         return (EINVAL);
     362             : 
     363           0 :                 dst6 = (struct sockaddr_in6 *)dst;
     364           0 :                 if (IN6_IS_ADDR_UNSPECIFIED(&dst6->sin6_addr) ||
     365           0 :                     IN6_IS_ADDR_MULTICAST(&dst6->sin6_addr))
     366           0 :                         return (EINVAL);
     367             : 
     368           0 :                 error = in6_embedscope(&sc->sc_tunnel.t_src6, src6, NULL);
     369           0 :                 if (error != 0)
     370           0 :                         return (error);
     371             : 
     372           0 :                 error = in6_embedscope(&sc->sc_tunnel.t_dst6, dst6, NULL);
     373           0 :                 if (error != 0)
     374           0 :                         return (error);
     375             : 
     376             :                 break;
     377             : #endif
     378             :         default:
     379           0 :                 return (EAFNOSUPPORT);
     380             :         }
     381             : 
     382             :         /* commit */
     383           0 :         sc->sc_tunnel.t_af = dst->sa_family;
     384             : 
     385           0 :         return (0);
     386           0 : }
     387             : 
     388             : int
     389           0 : etherip_get_tunnel(struct etherip_softc *sc, struct if_laddrreq *req)
     390             : {
     391           0 :         struct sockaddr *src = (struct sockaddr *)&req->addr;
     392           0 :         struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
     393             :         struct sockaddr_in *sin;
     394             : #ifdef INET6 /* ifconfig already embeds the scopeid */
     395             :         struct sockaddr_in6 *sin6;
     396             : #endif
     397             : 
     398           0 :         switch (sc->sc_tunnel.t_af) {
     399             :         case AF_UNSPEC:
     400           0 :                 return (EADDRNOTAVAIL);
     401             :         case AF_INET:
     402           0 :                 sin = (struct sockaddr_in *)src;
     403           0 :                 memset(sin, 0, sizeof(*sin));
     404           0 :                 sin->sin_family = AF_INET;
     405           0 :                 sin->sin_len = sizeof(*sin);
     406           0 :                 sin->sin_addr = sc->sc_tunnel.t_src4;
     407             : 
     408           0 :                 sin = (struct sockaddr_in *)dst;
     409           0 :                 memset(sin, 0, sizeof(*sin));
     410           0 :                 sin->sin_family = AF_INET;
     411           0 :                 sin->sin_len = sizeof(*sin);
     412           0 :                 sin->sin_addr = sc->sc_tunnel.t_dst4;
     413             : 
     414           0 :                 break;
     415             : #ifdef INET6
     416             :         case AF_INET6:
     417           0 :                 sin6 = (struct sockaddr_in6 *)src;
     418           0 :                 memset(sin6, 0, sizeof(*sin6));
     419           0 :                 sin6->sin6_family = AF_INET6;
     420           0 :                 sin6->sin6_len = sizeof(*sin6);
     421           0 :                 in6_recoverscope(sin6, &sc->sc_tunnel.t_src6);
     422             : 
     423           0 :                 sin6 = (struct sockaddr_in6 *)dst;
     424           0 :                 memset(sin6, 0, sizeof(*sin6));
     425           0 :                 sin6->sin6_family = AF_INET6;
     426           0 :                 sin6->sin6_len = sizeof(*sin6);
     427           0 :                 in6_recoverscope(sin6, &sc->sc_tunnel.t_dst6);
     428             : 
     429           0 :                 break;
     430             : #endif
     431             :         default:
     432           0 :                 return (EAFNOSUPPORT);
     433             :         }
     434             : 
     435           0 :         return (0);
     436           0 : }
     437             : 
     438             : int
     439           0 : etherip_del_tunnel(struct etherip_softc *sc)
     440             : {
     441             :         /* commit */
     442           0 :         sc->sc_tunnel.t_af = AF_UNSPEC;
     443             : 
     444           0 :         return (0);
     445             : }
     446             : 
     447             : int
     448           0 : etherip_up(struct etherip_softc *sc)
     449             : {
     450           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
     451             : 
     452           0 :         NET_ASSERT_LOCKED();
     453             : 
     454           0 :         SET(ifp->if_flags, IFF_RUNNING);
     455             : 
     456           0 :         return (0);
     457             : }
     458             : 
     459             : int
     460           0 : etherip_down(struct etherip_softc *sc)
     461             : {
     462           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
     463             : 
     464           0 :         NET_ASSERT_LOCKED();
     465             : 
     466           0 :         CLR(ifp->if_flags, IFF_RUNNING);
     467             : 
     468           0 :         return (0);
     469             : }
     470             : 
     471             : int
     472           0 : ip_etherip_output(struct ifnet *ifp, struct mbuf *m)
     473             : {
     474           0 :         struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc;
     475             :         struct etherip_header *eip;
     476             :         struct ip *ip;
     477             : 
     478           0 :         M_PREPEND(m, sizeof(*ip) + sizeof(*eip), M_DONTWAIT);
     479           0 :         if (m == NULL) {
     480           0 :                 etheripstat_inc(etherips_adrops);
     481           0 :                 return ENOBUFS;
     482             :         }
     483             : 
     484           0 :         ip = mtod(m, struct ip *);
     485           0 :         memset(ip, 0, sizeof(struct ip));
     486             : 
     487           0 :         ip->ip_v = IPVERSION;
     488           0 :         ip->ip_hl = sizeof(*ip) >> 2;
     489           0 :         ip->ip_tos = IPTOS_LOWDELAY;
     490           0 :         ip->ip_len = htons(m->m_pkthdr.len);
     491           0 :         ip->ip_id = htons(ip_randomid());
     492           0 :         ip->ip_off = sc->sc_df;
     493           0 :         ip->ip_ttl = sc->sc_ttl;
     494           0 :         ip->ip_p = IPPROTO_ETHERIP;
     495           0 :         ip->ip_src = sc->sc_tunnel.t_src4;
     496           0 :         ip->ip_dst = sc->sc_tunnel.t_dst4;
     497             : 
     498           0 :         eip = (struct etherip_header *)(ip + 1);
     499           0 :         eip->eip_ver = ETHERIP_VERSION;
     500           0 :         eip->eip_res = 0;
     501           0 :         eip->eip_pad = 0;
     502             : 
     503           0 :         m->m_flags &= ~(M_BCAST|M_MCAST);
     504           0 :         m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid;
     505             : 
     506             : #if NPF > 0
     507           0 :         pf_pkt_addr_changed(m);
     508             : #endif
     509           0 :         etheripstat_pkt(etherips_opackets, etherips_obytes, m->m_pkthdr.len -
     510             :             (sizeof(struct ip) + sizeof(struct etherip_header)));
     511             : 
     512           0 :         ip_send(m);
     513             : 
     514           0 :         return (0);
     515           0 : }
     516             : 
     517             : int
     518           0 : ip_etherip_input(struct mbuf **mp, int *offp, int type, int af)
     519             : {
     520           0 :         struct mbuf *m = *mp;
     521           0 :         struct etherip_tunnel key;
     522             :         struct ip *ip;
     523             : 
     524           0 :         ip = mtod(m, struct ip *);
     525             : 
     526           0 :         key.t_af = AF_INET;
     527           0 :         key.t_src4 = ip->ip_dst;
     528           0 :         key.t_dst4 = ip->ip_src;
     529             : 
     530           0 :         return (etherip_input(&key, m, *offp));
     531           0 : }
     532             : 
     533             : struct etherip_softc *
     534           0 : etherip_find(const struct etherip_tunnel *key)
     535             : {
     536             :         struct etherip_tunnel *t;
     537             :         struct etherip_softc *sc;
     538             : 
     539           0 :         TAILQ_FOREACH(t, &etherip_list, t_entry) {
     540           0 :                 if (etherip_cmp(key, t) != 0)
     541             :                         continue;
     542             : 
     543           0 :                 sc = (struct etherip_softc *)t;
     544           0 :                 if (!ISSET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING))
     545             :                         continue;
     546             : 
     547           0 :                 return (sc);
     548             :         }
     549             : 
     550           0 :         return (NULL);
     551           0 : }
     552             : 
     553             : int
     554           0 : etherip_input(struct etherip_tunnel *key, struct mbuf *m, int hlen)
     555             : {
     556           0 :         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
     557             :         struct etherip_softc *sc;
     558             :         struct ifnet *ifp;
     559             :         struct etherip_header *eip;
     560             : 
     561           0 :         if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) {
     562           0 :                 etheripstat_inc(etherips_pdrops);
     563           0 :                 goto drop;
     564             :         }
     565             : 
     566           0 :         key->t_rtableid = m->m_pkthdr.ph_rtableid;
     567             : 
     568           0 :         NET_ASSERT_LOCKED();
     569           0 :         sc = etherip_find(key);
     570           0 :         if (sc == NULL) {
     571           0 :                 etheripstat_inc(etherips_noifdrops);
     572           0 :                 goto drop;
     573             :         }
     574             : 
     575           0 :         m_adj(m, hlen);
     576           0 :         m = m_pullup(m, sizeof(*eip));
     577           0 :         if (m == NULL) {
     578           0 :                 etheripstat_inc(etherips_adrops);
     579           0 :                 return IPPROTO_DONE;
     580             :         }
     581             : 
     582           0 :         eip = mtod(m, struct etherip_header *);
     583           0 :         if (eip->eip_ver != ETHERIP_VERSION || eip->eip_pad) {
     584           0 :                 etheripstat_inc(etherips_adrops);
     585           0 :                 goto drop;
     586             :         }
     587             : 
     588           0 :         m_adj(m, sizeof(struct etherip_header));
     589             : 
     590           0 :         etheripstat_pkt(etherips_ipackets, etherips_ibytes, m->m_pkthdr.len);
     591             : 
     592           0 :         m = m_pullup(m, sizeof(struct ether_header));
     593           0 :         if (m == NULL) {
     594           0 :                 etheripstat_inc(etherips_adrops);
     595           0 :                 return IPPROTO_DONE;
     596             :         }
     597             : 
     598           0 :         ifp = &sc->sc_ac.ac_if;
     599             : 
     600           0 :         m->m_flags &= ~(M_BCAST|M_MCAST);
     601           0 :         m->m_pkthdr.ph_ifidx = ifp->if_index;
     602           0 :         m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
     603             : 
     604             : #if NPF > 0
     605           0 :         pf_pkt_addr_changed(m);
     606             : #endif
     607             : 
     608           0 :         ml_enqueue(&ml, m);
     609           0 :         if_input(ifp, &ml);
     610           0 :         return IPPROTO_DONE;
     611             : 
     612             : drop:
     613           0 :         m_freem(m);
     614           0 :         return (IPPROTO_DONE);
     615           0 : }
     616             : 
     617             : #ifdef INET6
     618             : int
     619           0 : ip6_etherip_output(struct ifnet *ifp, struct mbuf *m)
     620             : {
     621           0 :         struct etherip_softc *sc = ifp->if_softc;
     622             :         struct ip6_hdr *ip6;
     623             :         struct etherip_header *eip;
     624             :         uint16_t len;
     625             : 
     626           0 :         if (IN6_IS_ADDR_UNSPECIFIED(&sc->sc_tunnel.t_dst6)) {
     627           0 :                 m_freem(m);
     628           0 :                 return (ENETUNREACH);
     629             :         }
     630             : 
     631           0 :         len = m->m_pkthdr.len;
     632             : 
     633           0 :         M_PREPEND(m, sizeof(*ip6) + sizeof(*eip), M_DONTWAIT);
     634           0 :         if (m == NULL) {
     635           0 :                 etheripstat_inc(etherips_adrops);
     636           0 :                 return ENOBUFS;
     637             :         }
     638             : 
     639           0 :         ip6 = mtod(m, struct ip6_hdr *);
     640           0 :         ip6->ip6_flow = 0;
     641           0 :         ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
     642           0 :         ip6->ip6_vfc |= IPV6_VERSION;
     643           0 :         ip6->ip6_nxt  = IPPROTO_ETHERIP;
     644           0 :         ip6->ip6_hlim = ip6_defhlim;
     645           0 :         ip6->ip6_plen = htons(len);
     646           0 :         memcpy(&ip6->ip6_src, &sc->sc_tunnel.t_src6, sizeof(ip6->ip6_src));
     647           0 :         memcpy(&ip6->ip6_dst, &sc->sc_tunnel.t_dst6, sizeof(ip6->ip6_dst));
     648             : 
     649           0 :         eip = (struct etherip_header *)(ip6 + 1);
     650           0 :         eip->eip_ver = ETHERIP_VERSION;
     651           0 :         eip->eip_res = 0;
     652           0 :         eip->eip_pad = 0;
     653             : 
     654           0 :         if (sc->sc_df)
     655           0 :                 SET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT);
     656             : 
     657           0 :         m->m_flags &= ~(M_BCAST|M_MCAST);
     658           0 :         m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid;
     659             : 
     660             : #if NPF > 0
     661           0 :         pf_pkt_addr_changed(m);
     662             : #endif
     663             : 
     664           0 :         etheripstat_pkt(etherips_opackets, etherips_obytes, len);
     665             : 
     666           0 :         ip6_send(m);
     667           0 :         return (0);
     668           0 : }
     669             : 
     670             : int
     671           0 : ip6_etherip_input(struct mbuf **mp, int *offp, int proto, int af)
     672             : {
     673           0 :         struct mbuf *m = *mp;
     674           0 :         struct etherip_tunnel key;
     675             :         const struct ip6_hdr *ip6;
     676             : 
     677           0 :         ip6 = mtod(m, const struct ip6_hdr *);
     678             : 
     679           0 :         key.t_af = AF_INET6;
     680           0 :         key.t_src6 = ip6->ip6_dst;
     681           0 :         key.t_dst6 = ip6->ip6_src;
     682             : 
     683           0 :         return (etherip_input(&key, m, *offp));
     684           0 : }
     685             : #endif /* INET6 */
     686             : 
     687             : int
     688           0 : etherip_sysctl_etheripstat(void *oldp, size_t *oldlenp, void *newp)
     689             : {
     690           0 :         struct etheripstat etheripstat;
     691             : 
     692             :         CTASSERT(sizeof(etheripstat) == (etherips_ncounters *
     693             :             sizeof(uint64_t)));
     694           0 :         memset(&etheripstat, 0, sizeof etheripstat);
     695           0 :         counters_read(etheripcounters, (uint64_t *)&etheripstat,
     696             :             etherips_ncounters);
     697           0 :         return (sysctl_rdstruct(oldp, oldlenp, newp, &etheripstat,
     698             :             sizeof(etheripstat)));
     699           0 : }
     700             : 
     701             : int
     702           0 : etherip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
     703             :     void *newp, size_t newlen)
     704             : {
     705             :         int error;
     706             : 
     707             :         /* All sysctl names at this level are terminal. */
     708           0 :         if (namelen != 1)
     709           0 :                 return ENOTDIR;
     710             : 
     711           0 :         switch (name[0]) {
     712             :         case ETHERIPCTL_ALLOW:
     713           0 :                 NET_LOCK();
     714           0 :                 error = sysctl_int(oldp, oldlenp, newp, newlen, &etherip_allow);
     715           0 :                 NET_UNLOCK();
     716           0 :                 return (error);
     717             :         case ETHERIPCTL_STATS:
     718           0 :                 return (etherip_sysctl_etheripstat(oldp, oldlenp, newp));
     719             :         default:
     720             :                 break;
     721             :         }
     722             : 
     723           0 :         return ENOPROTOOPT;
     724           0 : }
     725             : 
     726             : static inline int
     727           0 : etherip_ip_cmp(int af, const union etherip_addr *a, const union etherip_addr *b)
     728             : {
     729           0 :         switch (af) {
     730             : #ifdef INET6
     731             :         case AF_INET6:
     732           0 :                 return (memcmp(&a->in6, &b->in6, sizeof(a->in6)));
     733             :                 /* FALLTHROUGH */
     734             : #endif /* INET6 */
     735             :         case AF_INET:
     736           0 :                 return (memcmp(&a->in4, &b->in4, sizeof(a->in4)));
     737             :                 break;
     738             :         default:
     739           0 :                 panic("%s: unsupported af %d\n", __func__, af);
     740             :         }
     741             : 
     742             :         return (0);
     743           0 : }
     744             : 
     745             : static inline int
     746           0 : etherip_cmp(const struct etherip_tunnel *a, const struct etherip_tunnel *b)
     747             : {
     748             :         int rv;
     749             : 
     750           0 :         if (a->t_rtableid > b->t_rtableid)
     751           0 :                 return (1);
     752           0 :         if (a->t_rtableid < b->t_rtableid)
     753           0 :                 return (-1);
     754             : 
     755             :         /* sort by address */
     756           0 :         if (a->t_af > b->t_af)
     757           0 :                 return (1);
     758           0 :         if (a->t_af < b->t_af)
     759           0 :                 return (-1);
     760             : 
     761           0 :         rv = etherip_ip_cmp(a->t_af, &a->_t_dst, &b->_t_dst);
     762           0 :         if (rv != 0)
     763           0 :                 return (rv);
     764             : 
     765           0 :         rv = etherip_ip_cmp(a->t_af, &a->_t_src, &b->_t_src);
     766           0 :         if (rv != 0)
     767           0 :                 return (rv);
     768             : 
     769           0 :         return (0);
     770           0 : }

Generated by: LCOV version 1.13