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