1 /* $OpenBSD: if_vether.c,v 1.28 2016/11/29 10:09:57 reyk 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 if ((sc = malloc(sizeof(*sc), 79 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 80 return (ENOMEM); 81 82 ifp = &sc->sc_ac.ac_if; 83 snprintf(ifp->if_xname, sizeof ifp->if_xname, "vether%d", unit); 84 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 85 ether_fakeaddr(ifp); 86 87 ifp->if_softc = sc; 88 ifp->if_ioctl = vetherioctl; 89 ifp->if_start = vetherstart; 90 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 91 92 ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN; 93 ifp->if_capabilities = IFCAP_VLAN_MTU; 94 95 ifmedia_init(&sc->sc_media, 0, vether_media_change, 96 vether_media_status); 97 ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 98 ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 99 100 if_attach(ifp); 101 ether_ifattach(ifp); 102 return (0); 103 } 104 105 int 106 vether_clone_destroy(struct ifnet *ifp) 107 { 108 struct vether_softc *sc = ifp->if_softc; 109 110 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); 111 ether_ifdetach(ifp); 112 if_detach(ifp); 113 free(sc, M_DEVBUF, sizeof(*sc)); 114 return (0); 115 } 116 117 /* 118 * The bridge has magically already done all the work for us, 119 * and we only need to discard the packets. 120 */ 121 void 122 vetherstart(struct ifnet *ifp) 123 { 124 struct mbuf *m; 125 126 for (;;) { 127 IFQ_DEQUEUE(&ifp->if_snd, m); 128 if (m == NULL) 129 return; 130 131 #if NBPFILTER > 0 132 if (ifp->if_bpf) 133 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 134 #endif /* NBPFILTER > 0 */ 135 136 ifp->if_opackets++; 137 m_freem(m); 138 } 139 } 140 141 int 142 vetherioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 143 { 144 struct vether_softc *sc = (struct vether_softc *)ifp->if_softc; 145 struct ifreq *ifr = (struct ifreq *)data; 146 int error = 0, link_state; 147 148 switch (cmd) { 149 case SIOCSIFADDR: 150 ifp->if_flags |= IFF_UP; 151 /* FALLTHROUGH */ 152 153 case SIOCSIFFLAGS: 154 if (ifp->if_flags & IFF_UP) { 155 ifp->if_flags |= IFF_RUNNING; 156 link_state = LINK_STATE_UP; 157 } else { 158 ifp->if_flags &= ~IFF_RUNNING; 159 link_state = LINK_STATE_DOWN; 160 } 161 if (ifp->if_link_state != link_state) { 162 ifp->if_link_state = link_state; 163 if_link_state_change(ifp); 164 } 165 break; 166 167 case SIOCADDMULTI: 168 case SIOCDELMULTI: 169 break; 170 171 case SIOCGIFMEDIA: 172 case SIOCSIFMEDIA: 173 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 174 break; 175 176 default: 177 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 178 } 179 return (error); 180 } 181