1 /* $OpenBSD: if_vether.c,v 1.17 2013/03/26 13:19:26 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/proc.h> 23 #include <sys/socket.h> 24 #include <sys/sockio.h> 25 #include <sys/ioctl.h> 26 27 #include <net/if.h> 28 #include <net/if_dl.h> 29 #include <net/if_media.h> 30 31 #ifdef INET 32 #include <netinet/in.h> 33 #include <netinet/if_ether.h> 34 #endif 35 36 void vetherattach(int); 37 int vetherioctl(struct ifnet *, u_long, caddr_t); 38 void vetherstart(struct ifnet *); 39 int vether_clone_create(struct if_clone *, int); 40 int vether_clone_destroy(struct ifnet *); 41 int vether_media_change(struct ifnet *); 42 void vether_media_status(struct ifnet *, struct ifmediareq *); 43 44 struct vether_softc { 45 struct arpcom sc_ac; 46 struct ifmedia sc_media; 47 }; 48 49 struct if_clone vether_cloner = 50 IF_CLONE_INITIALIZER("vether", vether_clone_create, vether_clone_destroy); 51 52 int 53 vether_media_change(struct ifnet *ifp) 54 { 55 return (0); 56 } 57 58 void 59 vether_media_status(struct ifnet *ifp, struct ifmediareq *imr) 60 { 61 imr->ifm_active = IFM_ETHER | IFM_AUTO; 62 imr->ifm_status = IFM_AVALID | IFM_ACTIVE; 63 } 64 65 void 66 vetherattach(int nvether) 67 { 68 if_clone_attach(&vether_cloner); 69 } 70 71 int 72 vether_clone_create(struct if_clone *ifc, int unit) 73 { 74 struct ifnet *ifp; 75 struct vether_softc *sc; 76 77 if ((sc = malloc(sizeof(*sc), 78 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 79 return (ENOMEM); 80 81 ifp = &sc->sc_ac.ac_if; 82 snprintf(ifp->if_xname, sizeof ifp->if_xname, "vether%d", unit); 83 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 84 ether_fakeaddr(ifp); 85 86 ifp->if_softc = sc; 87 ifp->if_ioctl = vetherioctl; 88 ifp->if_start = vetherstart; 89 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 90 IFQ_SET_READY(&ifp->if_snd); 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); 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 int s; 125 126 for (;;) { 127 s = splnet(); 128 IFQ_DEQUEUE(&ifp->if_snd, m); 129 splx(s); 130 131 if (m == NULL) 132 return; 133 ifp->if_opackets++; 134 m_freem(m); 135 } 136 } 137 138 /* ARGSUSED */ 139 int 140 vetherioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 141 { 142 struct vether_softc *sc = (struct vether_softc *)ifp->if_softc; 143 #ifdef INET 144 struct ifaddr *ifa = (struct ifaddr *)data; 145 #endif 146 struct ifreq *ifr = (struct ifreq *)data; 147 int error = 0, link_state; 148 149 switch (cmd) { 150 case SIOCSIFADDR: 151 ifp->if_flags |= IFF_UP; 152 #ifdef INET 153 if (ifa->ifa_addr->sa_family == AF_INET) 154 arp_ifinit(&sc->sc_ac, ifa); 155 #endif 156 /* FALLTHROUGH */ 157 158 case SIOCSIFFLAGS: 159 if (ifp->if_flags & IFF_UP) { 160 ifp->if_flags |= IFF_RUNNING; 161 link_state = LINK_STATE_UP; 162 } else { 163 ifp->if_flags &= ~IFF_RUNNING; 164 link_state = LINK_STATE_DOWN; 165 } 166 if (ifp->if_link_state != link_state) { 167 ifp->if_link_state = link_state; 168 if_link_state_change(ifp); 169 } 170 break; 171 172 case SIOCADDMULTI: 173 case SIOCDELMULTI: { 174 if (ifr == 0) { 175 error = EAFNOSUPPORT; /* XXX */ 176 break; 177 } 178 error = (cmd == SIOCADDMULTI) ? 179 ether_addmulti(ifr, &sc->sc_ac) : 180 ether_delmulti(ifr, &sc->sc_ac); 181 if (error == ENETRESET) { 182 /* 183 * Multicast list has changed; set the hardware 184 * filter accordingly. The good thing is we do 185 * not have a hardware filter (: 186 */ 187 error = 0; 188 } 189 break; 190 } 191 192 case SIOCGIFMEDIA: 193 case SIOCSIFMEDIA: 194 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 195 break; 196 197 default: 198 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 199 } 200 return (error); 201 } 202