1 /* $OpenBSD: if_vether.c,v 1.21 2014/11/23 07:39:02 deraadt 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_dl.h> 28 #include <net/if_media.h> 29 30 #ifdef INET 31 #include <netinet/in.h> 32 #include <netinet/if_ether.h> 33 #endif 34 35 void vetherattach(int); 36 int vetherioctl(struct ifnet *, u_long, caddr_t); 37 void vetherstart(struct ifnet *); 38 int vether_clone_create(struct if_clone *, int); 39 int vether_clone_destroy(struct ifnet *); 40 int vether_media_change(struct ifnet *); 41 void vether_media_status(struct ifnet *, struct ifmediareq *); 42 43 struct vether_softc { 44 struct arpcom sc_ac; 45 struct ifmedia sc_media; 46 }; 47 48 struct if_clone vether_cloner = 49 IF_CLONE_INITIALIZER("vether", vether_clone_create, vether_clone_destroy); 50 51 int 52 vether_media_change(struct ifnet *ifp) 53 { 54 return (0); 55 } 56 57 void 58 vether_media_status(struct ifnet *ifp, struct ifmediareq *imr) 59 { 60 imr->ifm_active = IFM_ETHER | IFM_AUTO; 61 imr->ifm_status = IFM_AVALID | IFM_ACTIVE; 62 } 63 64 void 65 vetherattach(int nvether) 66 { 67 if_clone_attach(&vether_cloner); 68 } 69 70 int 71 vether_clone_create(struct if_clone *ifc, int unit) 72 { 73 struct ifnet *ifp; 74 struct vether_softc *sc; 75 76 if ((sc = malloc(sizeof(*sc), 77 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 78 return (ENOMEM); 79 80 ifp = &sc->sc_ac.ac_if; 81 snprintf(ifp->if_xname, sizeof ifp->if_xname, "vether%d", unit); 82 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 83 ether_fakeaddr(ifp); 84 85 ifp->if_softc = sc; 86 ifp->if_ioctl = vetherioctl; 87 ifp->if_start = vetherstart; 88 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 89 IFQ_SET_READY(&ifp->if_snd); 90 91 ifp->if_capabilities = IFCAP_VLAN_MTU; 92 93 ifmedia_init(&sc->sc_media, 0, vether_media_change, 94 vether_media_status); 95 ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 96 ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 97 98 if_attach(ifp); 99 ether_ifattach(ifp); 100 return (0); 101 } 102 103 int 104 vether_clone_destroy(struct ifnet *ifp) 105 { 106 struct vether_softc *sc = ifp->if_softc; 107 108 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); 109 ether_ifdetach(ifp); 110 if_detach(ifp); 111 free(sc, M_DEVBUF, sizeof(*sc)); 112 return (0); 113 } 114 115 /* 116 * The bridge has magically already done all the work for us, 117 * and we only need to discard the packets. 118 */ 119 void 120 vetherstart(struct ifnet *ifp) 121 { 122 struct mbuf *m; 123 int s; 124 125 for (;;) { 126 s = splnet(); 127 IFQ_DEQUEUE(&ifp->if_snd, m); 128 splx(s); 129 130 if (m == NULL) 131 return; 132 ifp->if_opackets++; 133 m_freem(m); 134 } 135 } 136 137 /* ARGSUSED */ 138 int 139 vetherioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 140 { 141 struct vether_softc *sc = (struct vether_softc *)ifp->if_softc; 142 #ifdef INET 143 struct ifaddr *ifa = (struct ifaddr *)data; 144 #endif 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 #ifdef INET 152 if (ifa->ifa_addr->sa_family == AF_INET) 153 arp_ifinit(&sc->sc_ac, ifa); 154 #endif 155 /* FALLTHROUGH */ 156 157 case SIOCSIFFLAGS: 158 if (ifp->if_flags & IFF_UP) { 159 ifp->if_flags |= IFF_RUNNING; 160 link_state = LINK_STATE_UP; 161 } else { 162 ifp->if_flags &= ~IFF_RUNNING; 163 link_state = LINK_STATE_DOWN; 164 } 165 if (ifp->if_link_state != link_state) { 166 ifp->if_link_state = link_state; 167 if_link_state_change(ifp); 168 } 169 break; 170 171 case SIOCADDMULTI: 172 case SIOCDELMULTI: 173 break; 174 175 case SIOCGIFMEDIA: 176 case SIOCSIFMEDIA: 177 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 178 break; 179 180 default: 181 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 182 } 183 return (error); 184 } 185