1 /* $NetBSD: if_vether.c,v 1.4 2024/09/26 09:59:55 roy Exp $ */ 2 /* $OpenBSD: if_vether.c,v 1.27 2016/04/13 11:41:15 mpi Exp $ */ 3 4 /* 5 * Copyright (c) 2009 Theo de Raadt 6 * Copyright (c) 2020 Roy Marples 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/cdefs.h> 22 __KERNEL_RCSID(0, "$NetBSD: if_vether.c,v 1.4 2024/09/26 09:59:55 roy Exp $"); 23 24 #include <sys/cprng.h> 25 #include <sys/kmem.h> 26 #include <sys/mbuf.h> 27 28 #include <net/if.h> 29 #include <net/if_ether.h> 30 #include <net/if_media.h> 31 #include <net/bpf.h> 32 33 void vetherattach(int); 34 static int vether_ioctl(struct ifnet *, u_long, void *); 35 static int vether_mediachange(struct ifnet *); 36 static void vether_mediastatus(struct ifnet *, struct ifmediareq *); 37 static void vether_start(struct ifnet *); 38 static int vether_clone_create(struct if_clone *, int); 39 static int vether_clone_destroy(struct ifnet *); 40 41 static void vether_stop(struct ifnet *, int); 42 static int vether_init(struct ifnet *); 43 44 struct vether_softc { 45 struct ethercom sc_ec; 46 struct ifmedia sc_im; 47 }; 48 49 struct if_clone vether_cloner = 50 IF_CLONE_INITIALIZER("vether", vether_clone_create, vether_clone_destroy); 51 52 void 53 vetherattach(int nvether) 54 { 55 56 if_clone_attach(&vether_cloner); 57 } 58 59 static int 60 vether_clone_create(struct if_clone *ifc, int unit) 61 { 62 struct ifnet *ifp; 63 struct vether_softc *sc; 64 uint8_t enaddr[ETHER_ADDR_LEN] = 65 { 0xf2, 0x0b, 0xa4, 0xff, 0xff, 0xff }; 66 67 sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); 68 69 sc->sc_ec.ec_ifmedia = &sc->sc_im; 70 ifmedia_init(&sc->sc_im, 0, vether_mediachange, vether_mediastatus); 71 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_AUTO, 0, NULL); 72 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_NONE, 0, NULL); 73 ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_AUTO); 74 75 ifp = &sc->sc_ec.ec_if; 76 if_initname(ifp, ifc->ifc_name, unit); 77 ifp->if_softc = sc; 78 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 79 #ifdef NET_MPSAFE 80 ifp->if_extflags = IFEF_MPSAFE; 81 #endif 82 ifp->if_ioctl = vether_ioctl; 83 ifp->if_start = vether_start; 84 ifp->if_stop = vether_stop; 85 ifp->if_init = vether_init; 86 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 87 IFQ_SET_READY(&ifp->if_snd); 88 89 sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; 90 91 /* 92 * In order to obtain unique initial Ethernet address on a host, 93 * do some randomisation. It's not meant for anything but avoiding 94 * hard-coding an address. 95 */ 96 cprng_fast(&enaddr[3], 3); 97 98 /* Those steps are mandatory for an Ethernet driver. */ 99 if_initialize(ifp); 100 ether_ifattach(ifp, enaddr); 101 if_register(ifp); 102 103 /* Notify our link state */ 104 vether_mediachange(ifp); 105 106 return 0; 107 } 108 109 static int 110 vether_clone_destroy(struct ifnet *ifp) 111 { 112 struct vether_softc *sc = ifp->if_softc; 113 114 ether_ifdetach(ifp); 115 if_detach(ifp); 116 kmem_free(sc, sizeof(*sc)); 117 return 0; 118 } 119 120 static int 121 vether_init(struct ifnet *ifp) 122 { 123 124 ifp->if_flags |= IFF_RUNNING; 125 vether_start(ifp); 126 return 0; 127 } 128 129 static int 130 vether_mediachange(struct ifnet *ifp) 131 { 132 struct vether_softc *sc = ifp->if_softc; 133 int link_state; 134 135 if (IFM_SUBTYPE(sc->sc_im.ifm_cur->ifm_media) == IFM_NONE) 136 link_state = LINK_STATE_DOWN; 137 else 138 link_state = LINK_STATE_UP; 139 140 if_link_state_change(ifp, link_state); 141 return 0; 142 } 143 144 static void 145 vether_mediastatus(struct ifnet *ifp, struct ifmediareq *imr) 146 { 147 struct vether_softc *sc = ifp->if_softc; 148 149 imr->ifm_active = sc->sc_im.ifm_cur->ifm_media; 150 151 imr->ifm_status = IFM_AVALID; 152 if (IFM_SUBTYPE(imr->ifm_active) != IFM_NONE) 153 imr->ifm_status |= IFM_ACTIVE; 154 } 155 156 /* 157 * The bridge has magically already done all the work for us, 158 * and we only need to discard the packets. 159 */ 160 static void 161 vether_start(struct ifnet *ifp) 162 { 163 struct mbuf *m; 164 165 for (;;) { 166 IFQ_DEQUEUE(&ifp->if_snd, m); 167 if (m == NULL) 168 break; 169 bpf_mtap(ifp, m, BPF_D_OUT); 170 m_freem(m); 171 if_statinc(ifp, if_opackets); 172 } 173 } 174 175 static void 176 vether_stop(struct ifnet *ifp, __unused int disable) 177 { 178 179 ifp->if_flags &= ~IFF_RUNNING; 180 } 181 182 static int 183 vether_ioctl(struct ifnet *ifp, unsigned long cmd, void *data) 184 { 185 int error = 0; 186 187 switch (cmd) { 188 case SIOCADDMULTI: 189 case SIOCDELMULTI: 190 break; 191 192 default: 193 error = ether_ioctl(ifp, cmd, data); 194 } 195 return error; 196 } 197