1 /* $OpenBSD: if_enc.c,v 1.79 2022/08/29 07:51:45 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net> 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 "bpfilter.h" 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/malloc.h> 24 #include <sys/socket.h> 25 #include <sys/sockio.h> 26 #include <sys/mbuf.h> 27 28 #include <net/if.h> 29 #include <net/if_dl.h> 30 #include <net/if_var.h> 31 #include <net/if_enc.h> 32 #include <net/if_types.h> 33 #if NBPFILTER > 0 34 #include <net/bpf.h> 35 #endif 36 37 struct ifnet **enc_ifps; /* rdomain-mapped enc ifs */ 38 u_int enc_max_rdomain; 39 struct ifnet **enc_allifps; /* unit-mapped enc ifs */ 40 u_int enc_max_unit; 41 #define ENC_MAX_UNITS 4096 /* XXX n per rdomain */ 42 43 void encattach(int); 44 45 int enc_clone_create(struct if_clone *, int); 46 int enc_clone_destroy(struct ifnet *); 47 int enc_output(struct ifnet *, struct mbuf *, struct sockaddr *, 48 struct rtentry *); 49 int enc_ioctl(struct ifnet *, u_long, caddr_t); 50 51 int enc_setif(struct ifnet *, u_int); 52 void enc_unsetif(struct ifnet *); 53 54 struct if_clone enc_cloner = 55 IF_CLONE_INITIALIZER("enc", enc_clone_create, enc_clone_destroy); 56 57 void 58 encattach(int count) 59 { 60 /* Create enc0 by default */ 61 (void)enc_clone_create(&enc_cloner, 0); 62 63 if_clone_attach(&enc_cloner); 64 } 65 66 int 67 enc_clone_create(struct if_clone *ifc, int unit) 68 { 69 struct enc_softc *sc; 70 struct ifnet *ifp; 71 struct ifnet **new; 72 size_t oldlen; 73 int error; 74 75 if (unit > ENC_MAX_UNITS) 76 return (EINVAL); 77 78 if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 79 return (ENOBUFS); 80 81 sc->sc_unit = unit; 82 83 ifp = &sc->sc_if; 84 ifp->if_softc = sc; 85 ifp->if_type = IFT_ENC; 86 ifp->if_xflags = IFXF_CLONED; 87 ifp->if_output = enc_output; 88 ifp->if_ioctl = enc_ioctl; 89 ifp->if_hdrlen = ENC_HDRLEN; 90 91 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 92 ifc->ifc_name, unit); 93 94 if_attach(ifp); 95 if (unit == 0) 96 if_addgroup(ifp, ifc->ifc_name); 97 /* 98 * enc(4) does not have a link-layer address but rtrequest() 99 * wants an ifa for every route entry. So let's setup a fake 100 * and empty ifa of type AF_LINK for this purpose. 101 */ 102 if_alloc_sadl(ifp); 103 refcnt_init_trace(&sc->sc_ifa.ifa_refcnt, DT_REFCNT_IDX_IFADDR); 104 sc->sc_ifa.ifa_ifp = ifp; 105 sc->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl); 106 sc->sc_ifa.ifa_netmask = NULL; 107 108 #if NBPFILTER > 0 109 bpfattach(&ifp->if_bpf, ifp, DLT_ENC, ENC_HDRLEN); 110 #endif 111 NET_LOCK(); 112 error = enc_setif(ifp, 0); 113 if (error != 0) { 114 NET_UNLOCK(); 115 if_detach(ifp); 116 free(sc, M_DEVBUF, sizeof(*sc)); 117 return (error); 118 } 119 120 if (enc_allifps == NULL || unit > enc_max_unit) { 121 if ((new = mallocarray(unit + 1, sizeof(struct ifnet *), 122 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) { 123 NET_UNLOCK(); 124 return (ENOBUFS); 125 } 126 127 if (enc_allifps != NULL) { 128 oldlen = sizeof(struct ifnet *) * (enc_max_unit + 1); 129 memcpy(new, enc_allifps, oldlen); 130 free(enc_allifps, M_DEVBUF, oldlen); 131 } 132 enc_allifps = new; 133 enc_max_unit = unit; 134 } 135 enc_allifps[unit] = ifp; 136 NET_UNLOCK(); 137 138 return (0); 139 } 140 141 int 142 enc_clone_destroy(struct ifnet *ifp) 143 { 144 struct enc_softc *sc = ifp->if_softc; 145 146 /* Protect users from removing enc0 */ 147 if (sc->sc_unit == 0) 148 return (EPERM); 149 150 NET_LOCK(); 151 enc_allifps[sc->sc_unit] = NULL; 152 enc_unsetif(ifp); 153 NET_UNLOCK(); 154 155 if_detach(ifp); 156 if (refcnt_rele(&sc->sc_ifa.ifa_refcnt) == 0) { 157 panic("%s: ifa refcnt has %u refs", __func__, 158 sc->sc_ifa.ifa_refcnt.r_refs); 159 } 160 free(sc, M_DEVBUF, sizeof(*sc)); 161 162 return (0); 163 } 164 165 int 166 enc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, 167 struct rtentry *rt) 168 { 169 m_freem(m); /* drop packet */ 170 return (EAFNOSUPPORT); 171 } 172 173 int 174 enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 175 { 176 struct ifreq *ifr = (struct ifreq *)data; 177 int error; 178 179 switch (cmd) { 180 case SIOCSIFADDR: 181 case SIOCSIFDSTADDR: 182 case SIOCSIFFLAGS: 183 if (ifp->if_flags & IFF_UP) 184 ifp->if_flags |= IFF_RUNNING; 185 else 186 ifp->if_flags &= ~IFF_RUNNING; 187 break; 188 case SIOCSIFRDOMAIN: 189 if ((error = enc_setif(ifp, ifr->ifr_rdomainid)) != 0) 190 return (error); 191 /* FALLTHROUGH */ 192 default: 193 return (ENOTTY); 194 } 195 196 return (0); 197 } 198 199 struct ifnet * 200 enc_getif(u_int rdomain, u_int unit) 201 { 202 struct ifnet *ifp; 203 204 NET_ASSERT_LOCKED(); 205 206 /* Check if the caller wants to get a non-default enc interface */ 207 if (unit > 0) { 208 if (unit > enc_max_unit) 209 return (NULL); 210 ifp = enc_allifps[unit]; 211 if (ifp == NULL || ifp->if_rdomain != rdomain) 212 return (NULL); 213 return (ifp); 214 } 215 216 /* Otherwise return the default enc interface for this rdomain */ 217 if (enc_ifps == NULL) 218 return (NULL); 219 else if (rdomain > RT_TABLEID_MAX) 220 return (NULL); 221 else if (rdomain > enc_max_rdomain) 222 return (NULL); 223 return (enc_ifps[rdomain]); 224 } 225 226 struct ifaddr * 227 enc_getifa(u_int rdomain, u_int unit) 228 { 229 struct ifnet *ifp; 230 struct enc_softc *sc; 231 232 ifp = enc_getif(rdomain, unit); 233 if (ifp == NULL) 234 return (NULL); 235 236 sc = ifp->if_softc; 237 return (&sc->sc_ifa); 238 } 239 int 240 enc_setif(struct ifnet *ifp, u_int rdomain) 241 { 242 struct ifnet **new; 243 size_t oldlen; 244 245 NET_ASSERT_LOCKED(); 246 247 enc_unsetif(ifp); 248 249 /* 250 * There can only be one default encif per rdomain - 251 * Don't overwrite the existing enc iface that is stored 252 * for this rdomain, so only the first enc interface that 253 * was added for this rdomain becomes the default. 254 */ 255 if (enc_getif(rdomain, 0) != NULL) 256 return (0); 257 258 if (rdomain > RT_TABLEID_MAX) 259 return (EINVAL); 260 261 if (enc_ifps == NULL || rdomain > enc_max_rdomain) { 262 if ((new = mallocarray(rdomain + 1, sizeof(struct ifnet *), 263 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 264 return (ENOBUFS); 265 266 if (enc_ifps != NULL) { 267 oldlen = sizeof(struct ifnet *) * (enc_max_rdomain + 1); 268 memcpy(new, enc_ifps, oldlen); 269 free(enc_ifps, M_DEVBUF, oldlen); 270 } 271 enc_ifps = new; 272 enc_max_rdomain = rdomain; 273 } 274 275 enc_ifps[rdomain] = ifp; 276 277 /* Indicate that this interface is the rdomain default */ 278 ifp->if_link_state = LINK_STATE_UP; 279 280 return (0); 281 } 282 283 void 284 enc_unsetif(struct ifnet *ifp) 285 { 286 u_int rdomain = ifp->if_rdomain, i; 287 struct ifnet *oifp, *nifp; 288 289 if ((oifp = enc_getif(rdomain, 0)) == NULL || oifp != ifp) 290 return; 291 292 /* Clear slot for this rdomain */ 293 enc_ifps[rdomain] = NULL; 294 ifp->if_link_state = LINK_STATE_UNKNOWN; 295 296 /* 297 * Now find the next available encif to be the default interface 298 * for this rdomain. 299 */ 300 for (i = 0; i < (enc_max_unit + 1); i++) { 301 nifp = enc_allifps[i]; 302 303 if (nifp == NULL || nifp == ifp || nifp->if_rdomain != rdomain) 304 continue; 305 306 enc_ifps[rdomain] = nifp; 307 nifp->if_link_state = LINK_STATE_UP; 308 break; 309 } 310 } 311