,,, /* * Copyright (c) 2009 Theo de Raadt * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Copyright (c) 2018, 2021 Henning Andersen Matyschok, DARPA/AFRL * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Virtual Ethernet interface, ported from OpenBSD. This interface * operates in conjunction with if_bridge(4). */ struct vether_softc { struct ifmedia sc_ifm; /* fake media information */ struct ifnet *sc_ifp; /* network interface. */ }; #define VETHER_IF_FLAGS (IFF_SIMPLEX|IFF_BROADCAST|IFF_MULTICAST) #define VETHER_IFCAP_FLAGS (IFCAP_VLAN_MTU|IFCAP_JUMBO_MTU) #define VETHER_IFM_FLAGS (IFM_ETHER|IFM_AUTO) /* * XXX * The set of protocol-numbers index-set * against maps-to set * over (enum), e. g.: * * typedef enum netisr_proto { * netisr_ip = NETISR_IP, * netisr_igmp = NETISR_IGMP, * netisr_route = NETISR_ROUTE, * netisr_arp = NETISR_ARP, * netisr_ether = NETISR_ETHER, * netisr_ipv6 = NETISR_IPV6, * netisr_epair = NETISR_EPAIR, * netisr_ip_direct = NETISR_IP_DIRECT, * netisr_ipv6_direct = NETISR_IPV6_DIRECT, * netisr_vether = NETISR_VETHER_FWD, * } netisr_proto_t; */ #define NETISR_VETHER_FWD 11 typedef enum vether_netisr_component { vether_netisr_fwd = NETISR_VETHER_FWD, } vether_netisr_component_t; static void vether_ifaddr_init(struct ifnet *, struct ether_addr *); static void vether_encap(struct mbuf *); static void vether_texeof(struct ifnet *); static void vether_init(void *); static void vether_stop(struct ifnet *); static void vether_start(struct ifnet *); static int vether_media_change(struct ifnet *); static void vether_media_status(struct ifnet *, struct ifmediareq *); static int vether_ioctl(struct ifnet *, u_long, caddr_t); static int vether_clone_create(struct if_clone *, int, caddr_t); static void vether_clone_destroy(struct ifnet *); static struct netisr_handler vether_nh_fwd = { .nh_name = "Softintr. for if_vether(4)", .nh_handler = vether_encap, .nh_proto = vether_netisr_fwd, .nh_policy = NETISR_POLICY_FLOW, }; static const char vether_name[] = "vether"; VNET_DEFINE(struct if_clone *, vether_cloner); #define V_vether_cloner VNET(vether_cloner) static int vether_clone_create(struct if_clone *ifc, int unit, caddr_t data) { struct vether_softc *sc; struct ifnet *ifp; struct ether_addr lla; int up_call; /* * For safety reason, there is a condition test applied - * independently, if M_WAITOK was enabled or not. */ if ((sc = malloc(sizeof(struct vether_softc), M_DEVBUF, M_WAITOK|M_ZERO)) != NULL) { if ((ifp = if_alloc(IFT_ETHER)) != NULL) { sc->sc_ifp = ifp; ifp->if_softc = sc; if_initname(ifp, vether_name, unit); ifp->if_init = vether_init; ifp->if_ioctl = vether_ioctl; ifp->if_start = vether_start; ifp->if_flags = VETHER_IF_FLAGS; ifp->if_capabilities = VETHER_IFCAP_FLAGS; ifp->if_capenable = VETHER_IFCAP_FLAGS; ifp->if_baudrate = 0; ifmedia_init(&sc->sc_ifm, 0, vether_media_change, vether_media_status); ifmedia_add(&sc->sc_ifm, VETHER_IFM_FLAGS, 0, NULL); ifmedia_set(&sc->sc_ifm, VETHER_IFM_FLAGS); vether_ifaddr_init(ifp, &lla); ether_ifattach(ifp, lla.octet); up_call = 0; } else { up_call = ENOSPC; free(sc, M_DEVBUF); } } else up_call = ENOBUFS; return (up_call); } static void vether_clone_destroy(struct ifnet *ifp) { struct vether_softc *sc; if (ifp != NULL) { ifp->if_flags &= ~IFF_UP; vether_stop(ifp); if ((sc = ifp->if_softc) != NULL) { free(sc, M_DEVBUF); ifp->if_softc = NULL; } ether_ifdetach(ifp); if_free(ifp); } } static void vnet_vether_init(const void *unused __unused) { V_vether_cloner = if_clone_simple(vether_name, vether_clone_create, vether_clone_destroy, 0); } VNET_SYSINIT(vnet_vether_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, vnet_vether_init, NULL); static void vnet_vether_uninit(const void *unused __unused) { if_clone_detach(V_vether_cloner); } VNET_SYSUNINIT(vnet_vether_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, vnet_vether_uninit, NULL); static int vether_mod_event(module_t mod, int event, void *data) { switch (event) { case MOD_LOAD: netisr_register(&vether_nh_fwd); return (0); case MOD_UNLOAD: netisr_unregister(&vether_nh_fwd); return (0); default: break; } return (EOPNOTSUPP); } static moduledata_t vether_mod = { "if_vether", vether_mod_event, 0, }; DECLARE_MODULE(if_vether, vether_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); /* * I/O. */ static void vether_txeof(struct ifnet *ifp) { struct mbuf *m; if (ifp != NULL) { IFQ_DEQUEUE(&ifp->if_snd, m); if (m != NULL) { BPF_MTAP(ifp, m); if ((m->m_flags & M_PKTHDR) != 0) { /* do some statistics */ if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); /* discard, if not member of if_bridge(4) */ if (ifp->if_bridge == NULL) m->m_pkthdr.rcvif = ifp; /* * Three cases are considered here: * * (a) Frame was tx'd by layer above. * * (b) Frame was rx'd by link-layer. * * (c) Data sink. */ if (m->m_pkthdr.rcvif == NULL) { m->m_pkthdr.rcvif = ifp; netisr_dispatch(vether_netisr_fwd, m); } else if (m->m_pkthdr.rcvif != ifp) { m->m_pkthdr.rcvif = ifp; /* demultiplex any other frame */ (*ifp->if_input)(ifp, m); } else { m_freem(m); m = NULL; } } else { if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); m_freem(m); m = NULL; } vether_txeof(ifp); } } } static void vether_start(struct ifnet *ifp) { if ((ifp->if_flags & IFF_UP) != 0) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; vether_txeof(ifp); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } } /* * Broadcast frame by if_bridge(4). */ static void vether_encap(struct mbuf *m) { struct mbuf *m; struct ifnet *ifp; int up_call; if (m != NULL) { if ((m->m_flags & M_PKTHDR) != 0) { if ((ifp = m->m_pkthdr.rcvif) != NULL) { if (ifp->if_mtu > m->m_pkthdr.len) m_freem(m); else { BRIDGE_OUTPUT(ifp, m, up_call); if (up_call != 0) m_freem(m); } } else m_freem(m); } else m_freem(m); } } /* * Initialize lla. */ static void vether_ifaddr_init(struct ifnet *ifp, struct ether_addr *lla) { caddr_t pfx, sfx; if (ifp != NULL) { if (lla != NULL) { pfx = lla->octet; pfx[0] = 0x02; sfx = (pfx + 1); arc4rand(sfx, 5, 0); } } } static int vether_media_change(struct ifnet *ifp) { int up_call; if (ifp != NULL) up_call = 0; else up_call = EADDRNOTAVAIL; return (up_call); } static void vether_media_status(struct ifnet *ifp, struct ifmediareq *ifm) { if (ifp != NULL) { if (ifm != NULL) { ifm->ifm_active = (IFM_ETHER|IFM_AUTO); ifm->ifm_status = (IFM_AVALID|IFM_ACTIVE); } } } static void vether_init(void *xsc) { struct vether_softc *sc; struct ifnet *ifp; if ((sc = (struct vether_softc *)xsc) != NULL) { if ((ifp = sc->sc_ifp) != NULL) { ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } } } static void vether_stop(struct ifnet *ifp) { if (ifp != NULL) ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE); } static int vether_ioctl(struct ifnet *ifp, u_long req, caddr_t argp) { struct vether_softc *sc; struct ifreq *ifr; int up_call; if (ifp != NULL) { if ((sc = ifp->if_softc) != NULL) { ifr = (struct ifreq *)argp; switch (req) { case SIOCSIFMTU: if (ifr->ifr_mtu < ETHER_MAX_LEN_JUMBO) { ifp->if_mtu = ifr->ifr_mtu; up_call = 0; } else up_call = EINVAL; break; case SIOCSIFMEDIA: /* Media types can't be changed. */ case SIOCGIFMEDIA: up_call = ifmedia_ioctl(ifp, ifr, &sc->sc_ifm, req); break; case SIOCSIFFLAGS: case SIOCADDMULTI: case SIOCDELMULTI: up_call = 0; break; case SIOCSIFPHYS: up_call = EOPNOTSUPP; break; default: up_call = ether_ioctl(ifp, req, argp); break; } } else up_call = ENXIO; } else up_call = ENOTTY; return (up_call); } ,,, Henning Andersen Matyschok, 120179M11214, USAF USAF Henning Andersen Matyschok Wasserlooser Weg 5 24944 Flensburg Germany