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