1 /* $OpenBSD: if_enc.c,v 1.52 2010/07/03 04:44:51 guenther 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/kernel.h> 25 #include <sys/malloc.h> 26 #include <sys/socket.h> 27 #include <sys/sockio.h> 28 #include <sys/mbuf.h> 29 30 #include <net/if.h> 31 #include <net/if_enc.h> 32 #include <net/if_types.h> 33 #include <net/route.h> 34 #if NBPFILTER > 0 35 #include <net/bpf.h> 36 #endif 37 38 struct ifnet **enc_ifps; /* rdomain-mapped enc ifs */ 39 u_int enc_max_id; 40 struct ifnet **enc_allifps; /* unit-mapped enc ifs */ 41 u_int enc_max_unit; 42 #define ENC_MAX_UNITS 4096 /* XXX n per rdomain */ 43 44 void encattach(int); 45 46 int enc_clone_create(struct if_clone *, int); 47 int enc_clone_destroy(struct ifnet *); 48 void enc_start(struct ifnet *); 49 int enc_output(struct ifnet *, struct mbuf *, struct sockaddr *, 50 struct rtentry *); 51 int enc_ioctl(struct ifnet *, u_long, caddr_t); 52 53 int enc_setif(struct ifnet *, u_int); 54 void enc_unsetif(struct ifnet *); 55 56 struct if_clone enc_cloner = 57 IF_CLONE_INITIALIZER("enc", enc_clone_create, enc_clone_destroy); 58 59 void 60 encattach(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 68 int 69 enc_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 76 if (unit > ENC_MAX_UNITS) 77 return (EINVAL); 78 79 if ((sc = malloc(sizeof(struct enc_softc), 80 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 81 return (ENOMEM); 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_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 if_alloc_sadl(ifp); 100 101 #if NBPFILTER > 0 102 bpfattach(&ifp->if_bpf, ifp, DLT_ENC, ENC_HDRLEN); 103 #endif 104 105 if (enc_setif(ifp, 0) != 0) { 106 if_detach(ifp); 107 free(sc, M_DEVBUF); 108 return (-1); 109 } 110 111 if (unit == 0 || unit > enc_max_unit) { 112 newlen = sizeof(struct ifnet *) * (unit + 1); 113 114 if ((new = malloc(newlen, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 115 return (-1); 116 if (enc_allifps != NULL) { 117 memcpy(new, enc_allifps, 118 sizeof(struct ifnet *) * (enc_max_unit + 1)); 119 free(enc_allifps, M_DEVBUF); 120 } 121 enc_allifps = new; 122 enc_max_unit = unit; 123 } 124 enc_allifps[unit] = ifp; 125 126 return (0); 127 } 128 129 int 130 enc_clone_destroy(struct ifnet *ifp) 131 { 132 struct enc_softc *sc = ifp->if_softc; 133 int s; 134 135 /* Protect users from removing enc0 */ 136 if (sc->sc_unit == 0) 137 return (EPERM); 138 139 s = splnet(); 140 enc_allifps[sc->sc_unit] = NULL; 141 enc_unsetif(ifp); 142 if_detach(ifp); 143 free(sc, M_DEVBUF); 144 splx(s); 145 146 return (0); 147 } 148 149 void 150 enc_start(struct ifnet *ifp) 151 { 152 struct mbuf *m; 153 154 for (;;) { 155 IF_DROP(&ifp->if_snd); 156 IF_DEQUEUE(&ifp->if_snd, m); 157 if (m == NULL) 158 break; 159 m_freem(m); 160 } 161 } 162 163 int 164 enc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, 165 struct rtentry *rt) 166 { 167 m_freem(m); /* drop packet */ 168 return (0); 169 } 170 171 int 172 enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 173 { 174 struct ifreq *ifr = (struct ifreq *)data; 175 int error = 0; 176 177 switch (cmd) { 178 case SIOCAIFADDR: 179 case SIOCSIFADDR: 180 case SIOCSIFDSTADDR: 181 case SIOCSIFFLAGS: 182 if (ifp->if_flags & IFF_UP) 183 ifp->if_flags |= IFF_RUNNING; 184 else 185 ifp->if_flags &= ~IFF_RUNNING; 186 break; 187 case SIOCSIFRDOMAIN: 188 if ((error = enc_setif(ifp, ifr->ifr_rdomainid)) != 0) 189 return (error); 190 /* FALLTHROUGH */ 191 default: 192 return (ENOTTY); 193 } 194 195 return (0); 196 } 197 198 struct ifnet * 199 enc_getif(u_int id, u_int unit) 200 { 201 struct ifnet *ifp; 202 203 /* Check if the caller wants to get a non-default enc interface */ 204 if (unit > 0) { 205 if (unit > enc_max_unit) 206 return (NULL); 207 ifp = enc_allifps[unit]; 208 if (ifp == NULL || ifp->if_rdomain != id) 209 return (NULL); 210 return (ifp); 211 } 212 213 /* Otherwise return the default enc interface for this rdomain */ 214 if (enc_ifps == NULL) 215 return (NULL); 216 else if (id > RT_TABLEID_MAX) 217 return (NULL); 218 else if (id > enc_max_id) 219 return (NULL); 220 return (enc_ifps[id]); 221 } 222 223 int 224 enc_setif(struct ifnet *ifp, u_int id) 225 { 226 struct ifnet **new; 227 size_t newlen; 228 229 enc_unsetif(ifp); 230 231 /* 232 * There can only be one default encif per rdomain - 233 * Don't overwrite the existing enc iface that is stored 234 * for this rdomain, so only the first enc interface that 235 * was added for this rdomain becomes the default. 236 */ 237 if (enc_getif(id, 0) != NULL) 238 return (0); 239 240 if (id > RT_TABLEID_MAX) 241 return (-1); 242 243 if (id == 0 || id > enc_max_id) { 244 newlen = sizeof(struct ifnet *) * (id + 1); 245 246 if ((new = malloc(newlen, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 247 return (-1); 248 if (enc_ifps != NULL) { 249 memcpy(new, enc_ifps, 250 sizeof(struct ifnet *) * (enc_max_id + 1)); 251 free(enc_ifps, M_DEVBUF); 252 } 253 enc_ifps = new; 254 enc_max_id = id; 255 } 256 257 enc_ifps[id] = ifp; 258 259 /* Indicate that this interface is the rdomain default */ 260 ifp->if_link_state = LINK_STATE_UP; 261 262 return (0); 263 } 264 265 void 266 enc_unsetif(struct ifnet *ifp) 267 { 268 u_int id = ifp->if_rdomain, i; 269 struct ifnet *oifp, *nifp; 270 271 if ((oifp = enc_getif(id, 0)) == NULL || oifp != ifp) 272 return; 273 274 /* Clear slot for this rdomain */ 275 enc_ifps[id] = NULL; 276 ifp->if_link_state = LINK_STATE_UNKNOWN; 277 278 /* 279 * Now find the next available encif to be the default interface 280 * for this rdomain. 281 */ 282 for (i = 0; i < (enc_max_unit + 1); i++) { 283 nifp = enc_allifps[i]; 284 285 if (nifp == NULL || nifp == ifp || nifp->if_rdomain != id) 286 continue; 287 288 enc_ifps[id] = nifp; 289 nifp->if_link_state = LINK_STATE_UP; 290 break; 291 } 292 } 293