1 /* $OpenBSD: if_vether.c,v 1.32 2020/07/10 13:26:42 patrick Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Theo de Raadt 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 <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/mbuf.h> 22 #include <sys/socket.h> 23 #include <sys/sockio.h> 24 #include <sys/ioctl.h> 25 26 #include <net/if.h> 27 #include <net/if_media.h> 28 29 #include <netinet/in.h> 30 #include <netinet/if_ether.h> 31 32 #include "bpfilter.h" 33 #if NBPFILTER > 0 34 #include <net/bpf.h> 35 #endif 36 37 void vetherattach(int); 38 int vetherioctl(struct ifnet *, u_long, caddr_t); 39 void vetherstart(struct ifnet *); 40 int vether_clone_create(struct if_clone *, int); 41 int vether_clone_destroy(struct ifnet *); 42 int vether_media_change(struct ifnet *); 43 void vether_media_status(struct ifnet *, struct ifmediareq *); 44 45 struct vether_softc { 46 struct arpcom sc_ac; 47 struct ifmedia sc_media; 48 }; 49 50 struct if_clone vether_cloner = 51 IF_CLONE_INITIALIZER("vether", vether_clone_create, vether_clone_destroy); 52 53 int 54 vether_media_change(struct ifnet *ifp) 55 { 56 return (0); 57 } 58 59 void 60 vether_media_status(struct ifnet *ifp, struct ifmediareq *imr) 61 { 62 imr->ifm_active = IFM_ETHER | IFM_AUTO; 63 imr->ifm_status = IFM_AVALID | IFM_ACTIVE; 64 } 65 66 void 67 vetherattach(int nvether) 68 { 69 if_clone_attach(&vether_cloner); 70 } 71 72 int 73 vether_clone_create(struct if_clone *ifc, int unit) 74 { 75 struct ifnet *ifp; 76 struct vether_softc *sc; 77 78 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 79 ifp = &sc->sc_ac.ac_if; 80 snprintf(ifp->if_xname, sizeof ifp->if_xname, "vether%d", unit); 81 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 82 ether_fakeaddr(ifp); 83 84 ifp->if_softc = sc; 85 ifp->if_ioctl = vetherioctl; 86 ifp->if_start = vetherstart; 87 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN); 88 89 ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN; 90 ifp->if_capabilities = IFCAP_VLAN_MTU; 91 92 ifmedia_init(&sc->sc_media, 0, vether_media_change, 93 vether_media_status); 94 ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 95 ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 96 97 if_attach(ifp); 98 ether_ifattach(ifp); 99 return (0); 100 } 101 102 int 103 vether_clone_destroy(struct ifnet *ifp) 104 { 105 struct vether_softc *sc = ifp->if_softc; 106 107 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); 108 ether_ifdetach(ifp); 109 if_detach(ifp); 110 free(sc, M_DEVBUF, sizeof(*sc)); 111 return (0); 112 } 113 114 /* 115 * The bridge has magically already done all the work for us, 116 * and we only need to discard the packets. 117 */ 118 void 119 vetherstart(struct ifnet *ifp) 120 { 121 struct mbuf *m; 122 123 for (;;) { 124 m = ifq_dequeue(&ifp->if_snd); 125 if (m == NULL) 126 return; 127 128 #if NBPFILTER > 0 129 if (ifp->if_bpf) 130 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 131 #endif /* NBPFILTER > 0 */ 132 133 m_freem(m); 134 } 135 } 136 137 int 138 vetherioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 139 { 140 struct vether_softc *sc = (struct vether_softc *)ifp->if_softc; 141 struct ifreq *ifr = (struct ifreq *)data; 142 int error = 0, link_state; 143 144 switch (cmd) { 145 case SIOCSIFADDR: 146 ifp->if_flags |= IFF_UP; 147 /* FALLTHROUGH */ 148 149 case SIOCSIFFLAGS: 150 if (ifp->if_flags & IFF_UP) { 151 ifp->if_flags |= IFF_RUNNING; 152 link_state = LINK_STATE_UP; 153 } else { 154 ifp->if_flags &= ~IFF_RUNNING; 155 link_state = LINK_STATE_DOWN; 156 } 157 if (ifp->if_link_state != link_state) { 158 ifp->if_link_state = link_state; 159 if_link_state_change(ifp); 160 } 161 break; 162 163 case SIOCADDMULTI: 164 case SIOCDELMULTI: 165 break; 166 167 case SIOCGIFMEDIA: 168 case SIOCSIFMEDIA: 169 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 170 break; 171 172 default: 173 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 174 } 175 return (error); 176 } 177