if_enc.c revision 1.49
1/* $OpenBSD: if_enc.c,v 1.49 2010/06/29 21:28:37 reyk 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 38TAILQ_HEAD(__enchead, enc_softc) enc_list; /* all enc interfaces */ 39struct ifnet **enc_ifps; /* rdomain-mapped enc ifs */ 40u_int enc_max_id; 41 42void encattach(int); 43 44int enc_clone_create(struct if_clone *, int); 45int enc_clone_destroy(struct ifnet *); 46void enc_start(struct ifnet *); 47int enc_output(struct ifnet *, struct mbuf *, struct sockaddr *, 48 struct rtentry *); 49int enc_ioctl(struct ifnet *, u_long, caddr_t); 50 51int enc_setif(struct ifnet *, u_int); 52void enc_unsetif(struct ifnet *); 53 54struct if_clone enc_cloner = 55 IF_CLONE_INITIALIZER("enc", enc_clone_create, enc_clone_destroy); 56 57void 58encattach(int count) 59{ 60 TAILQ_INIT(&enc_list); 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 74 if ((sc = malloc(sizeof(struct enc_softc), 75 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 76 return (ENOMEM); 77 78 sc->sc_unit = unit; 79 80 ifp = &sc->sc_if; 81 ifp->if_softc = sc; 82 ifp->if_type = IFT_ENC; 83 ifp->if_start = enc_start; 84 ifp->if_output = enc_output; 85 ifp->if_ioctl = enc_ioctl; 86 ifp->if_hdrlen = ENC_HDRLEN; 87 88 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 89 ifc->ifc_name, unit); 90 91 if_attach(ifp); 92 if_alloc_sadl(ifp); 93 94#if NBPFILTER > 0 95 bpfattach(&ifp->if_bpf, ifp, DLT_ENC, ENC_HDRLEN); 96#endif 97 98 if (enc_setif(ifp, 0) != 0) { 99 if_detach(ifp); 100 free(sc, M_DEVBUF); 101 return (-1); 102 } 103 104 TAILQ_INSERT_TAIL(&enc_list, sc, sc_entry); 105 return (0); 106} 107 108int 109enc_clone_destroy(struct ifnet *ifp) 110{ 111 struct enc_softc *sc = ifp->if_softc; 112 int s; 113 114 /* Protect users from removing enc0 */ 115 if (sc->sc_unit == 0) 116 return (EPERM); 117 118 s = splnet(); 119 TAILQ_REMOVE(&enc_list, sc, sc_entry); 120 enc_unsetif(ifp); 121 if_detach(ifp); 122 free(sc, M_DEVBUF); 123 splx(s); 124 125 return (0); 126} 127 128void 129enc_start(struct ifnet *ifp) 130{ 131 struct mbuf *m; 132 133 for (;;) { 134 IF_DROP(&ifp->if_snd); 135 IF_DEQUEUE(&ifp->if_snd, m); 136 if (m == NULL) 137 break; 138 m_freem(m); 139 } 140} 141 142int 143enc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, 144 struct rtentry *rt) 145{ 146 m_freem(m); /* drop packet */ 147 return (0); 148} 149 150int 151enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 152{ 153 struct ifreq *ifr = (struct ifreq *)data; 154 int error = 0; 155 156 switch (cmd) { 157 case SIOCAIFADDR: 158 case SIOCSIFADDR: 159 case SIOCSIFDSTADDR: 160 case SIOCSIFFLAGS: 161 if (ifp->if_flags & IFF_UP) 162 ifp->if_flags |= IFF_RUNNING; 163 else 164 ifp->if_flags &= ~IFF_RUNNING; 165 break; 166 case SIOCSIFRTABLEID: 167 if ((error = enc_setif(ifp, ifr->ifr_rdomainid)) != 0) 168 return (error); 169 /* FALLTHROUGH */ 170 default: 171 return (ENOTTY); 172 } 173 174 return (0); 175} 176 177struct ifnet * 178enc_getif(u_int id) 179{ 180 if (enc_ifps == NULL) 181 return (NULL); 182 else if (id > RT_TABLEID_MAX) 183 return (NULL); 184 else if (id > enc_max_id) 185 return (NULL); 186 return (enc_ifps[id]); 187} 188 189int 190enc_setif(struct ifnet *ifp, u_int id) 191{ 192 struct ifnet **new; 193 size_t newlen; 194 195 enc_unsetif(ifp); 196 197 /* 198 * There can only be one default encif per rdomain - 199 * Don't overwrite the existing enc iface that is stored 200 * for this rdomain, so only the first enc interface that 201 * was added for this rdomain becomes the default. 202 */ 203 if (enc_getif(id) != NULL) 204 return (0); 205 206 if (id > RT_TABLEID_MAX) 207 return (-1); 208 209 if (id == 0 || id > enc_max_id) { 210 newlen = sizeof(struct ifnet *) * (id + 1); 211 212 if ((new = malloc(newlen, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 213 return (-1); 214 if (enc_ifps != NULL) { 215 memcpy(new, enc_ifps, 216 sizeof(struct ifnet *) * (enc_max_id + 1)); 217 free(enc_ifps, M_DEVBUF); 218 } 219 enc_ifps = new; 220 enc_max_id = id; 221 } 222 223 enc_ifps[id] = ifp; 224 225 /* Indicate that this interface is the rdomain default */ 226 ifp->if_link_state = LINK_STATE_UP; 227 228 return (0); 229} 230 231void 232enc_unsetif(struct ifnet *ifp) 233{ 234 u_int id = ifp->if_rdomain; 235 struct ifnet *oifp; 236 struct enc_softc *sc; 237 238 if ((oifp = enc_getif(id)) == NULL || oifp != ifp) 239 return; 240 241 /* Clear slot for this rdomain */ 242 enc_ifps[id] = NULL; 243 ifp->if_link_state = LINK_STATE_UNKNOWN; 244 245 /* 246 * Now find the next available encif to be the default interface 247 * for this rdomain. 248 */ 249 TAILQ_FOREACH(sc, &enc_list, sc_entry) { 250 if (&sc->sc_if == ifp || sc->sc_if.if_rdomain != id) 251 continue; 252 253 enc_ifps[id] = &sc->sc_if; 254 sc->sc_if.if_link_state = LINK_STATE_UP; 255 break; 256 } 257} 258