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