1 /*- 2 * Copyright (c) 2001 Atsushi Onoe 3 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * Alternatively, this software may be distributed under the terms of the 18 * GNU General Public License ("GPL") version 2 as published by the Free 19 * Software Foundation. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include "opt_inet.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/mbuf.h> 41 #include <sys/malloc.h> 42 #include <sys/kernel.h> 43 #include <sys/socket.h> 44 #include <sys/sockio.h> 45 #include <sys/endian.h> 46 #include <sys/errno.h> 47 #include <sys/bus.h> 48 #include <sys/proc.h> 49 #include <sys/sysctl.h> 50 51 #include <machine/atomic.h> 52 53 #include <net/if.h> 54 #include <net/if_dl.h> 55 #include <net/if_media.h> 56 #include <net/if_arp.h> 57 #include <net/ethernet.h> 58 #include <net/if_llc.h> 59 60 #include <net80211/ieee80211_var.h> 61 62 #include <net/bpf.h> 63 64 #ifdef INET 65 #include <netinet/in.h> 66 #include <netinet/if_ether.h> 67 #endif 68 69 #include <crypto/rc4/rc4.h> 70 #define arc4_ctxlen() sizeof (struct rc4_state) 71 #define arc4_setkey(_c,_k,_l) rc4_init(_c,_k,_l) 72 #define arc4_encrypt(_c,_d,_s,_l) rc4_crypt(_c,_s,_d,_l) 73 74 static void ieee80211_crc_init(void); 75 static u_int32_t ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len); 76 77 void 78 ieee80211_crypto_attach(struct ifnet *ifp) 79 { 80 struct ieee80211com *ic = (void *)ifp; 81 82 /* 83 * Setup crypto support. 84 */ 85 ieee80211_crc_init(); 86 ic->ic_iv = arc4random(); 87 } 88 89 void 90 ieee80211_crypto_detach(struct ifnet *ifp) 91 { 92 struct ieee80211com *ic = (void *)ifp; 93 94 if (ic->ic_wep_ctx != NULL) { 95 free(ic->ic_wep_ctx, M_DEVBUF); 96 ic->ic_wep_ctx = NULL; 97 } 98 } 99 100 struct mbuf * 101 ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag) 102 { 103 struct ieee80211com *ic = (void *)ifp; 104 struct mbuf *m, *n, *n0; 105 struct ieee80211_frame *wh; 106 int i, left, len, moff, noff, kid; 107 u_int32_t iv, crc; 108 u_int8_t *ivp; 109 void *ctx; 110 u_int8_t keybuf[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE]; 111 u_int8_t crcbuf[IEEE80211_WEP_CRCLEN]; 112 113 n0 = NULL; 114 if ((ctx = ic->ic_wep_ctx) == NULL) { 115 ctx = malloc(arc4_ctxlen(), M_DEVBUF, M_NOWAIT); 116 if (ctx == NULL) 117 goto fail; 118 ic->ic_wep_ctx = ctx; 119 } 120 m = m0; 121 left = m->m_pkthdr.len; 122 MGET(n, M_DONTWAIT, m->m_type); 123 n0 = n; 124 if (n == NULL) 125 goto fail; 126 M_MOVE_PKTHDR(n, m); 127 len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; 128 if (txflag) { 129 n->m_pkthdr.len += len; 130 } else { 131 n->m_pkthdr.len -= len; 132 left -= len; 133 } 134 n->m_len = MHLEN; 135 if (n->m_pkthdr.len >= MINCLSIZE) { 136 MCLGET(n, M_DONTWAIT); 137 if (n->m_flags & M_EXT) 138 n->m_len = n->m_ext.ext_size; 139 } 140 len = sizeof(struct ieee80211_frame); 141 memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len); 142 wh = mtod(n, struct ieee80211_frame *); 143 left -= len; 144 moff = len; 145 noff = len; 146 if (txflag) { 147 kid = ic->ic_wep_txkey; 148 wh->i_fc[1] |= IEEE80211_FC1_WEP; 149 iv = ic->ic_iv; 150 /* 151 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: 152 * (B, 255, N) with 3 <= B < 8 153 */ 154 if (iv >= 0x03ff00 && 155 (iv & 0xf8ff00) == 0x00ff00) 156 iv += 0x000100; 157 ic->ic_iv = iv + 1; 158 /* put iv in little endian to prepare 802.11i */ 159 ivp = mtod(n, u_int8_t *) + noff; 160 for (i = 0; i < IEEE80211_WEP_IVLEN; i++) { 161 ivp[i] = iv & 0xff; 162 iv >>= 8; 163 } 164 ivp[IEEE80211_WEP_IVLEN] = kid << 6; /* pad and keyid */ 165 noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 166 } else { 167 wh->i_fc[1] &= ~IEEE80211_FC1_WEP; 168 ivp = mtod(m, u_int8_t *) + moff; 169 kid = ivp[IEEE80211_WEP_IVLEN] >> 6; 170 moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 171 } 172 memcpy(keybuf, ivp, IEEE80211_WEP_IVLEN); 173 memcpy(keybuf + IEEE80211_WEP_IVLEN, ic->ic_nw_keys[kid].wk_key, 174 ic->ic_nw_keys[kid].wk_len); 175 arc4_setkey(ctx, keybuf, 176 IEEE80211_WEP_IVLEN + ic->ic_nw_keys[kid].wk_len); 177 178 /* encrypt with calculating CRC */ 179 crc = ~0; 180 while (left > 0) { 181 len = m->m_len - moff; 182 if (len == 0) { 183 m = m->m_next; 184 moff = 0; 185 continue; 186 } 187 if (len > n->m_len - noff) { 188 len = n->m_len - noff; 189 if (len == 0) { 190 MGET(n->m_next, M_DONTWAIT, n->m_type); 191 if (n->m_next == NULL) 192 goto fail; 193 n = n->m_next; 194 n->m_len = MLEN; 195 if (left >= MINCLSIZE) { 196 MCLGET(n, M_DONTWAIT); 197 if (n->m_flags & M_EXT) 198 n->m_len = n->m_ext.ext_size; 199 } 200 noff = 0; 201 continue; 202 } 203 } 204 if (len > left) 205 len = left; 206 arc4_encrypt(ctx, mtod(n, caddr_t) + noff, 207 mtod(m, caddr_t) + moff, len); 208 if (txflag) 209 crc = ieee80211_crc_update(crc, 210 mtod(m, u_int8_t *) + moff, len); 211 else 212 crc = ieee80211_crc_update(crc, 213 mtod(n, u_int8_t *) + noff, len); 214 left -= len; 215 moff += len; 216 noff += len; 217 } 218 crc = ~crc; 219 if (txflag) { 220 *(u_int32_t *)crcbuf = htole32(crc); 221 if (n->m_len >= noff + sizeof(crcbuf)) 222 n->m_len = noff + sizeof(crcbuf); 223 else { 224 n->m_len = noff; 225 MGET(n->m_next, M_DONTWAIT, n->m_type); 226 if (n->m_next == NULL) 227 goto fail; 228 n = n->m_next; 229 n->m_len = sizeof(crcbuf); 230 noff = 0; 231 } 232 arc4_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf, 233 sizeof(crcbuf)); 234 } else { 235 n->m_len = noff; 236 for (noff = 0; noff < sizeof(crcbuf); noff += len) { 237 len = sizeof(crcbuf) - noff; 238 if (len > m->m_len - moff) 239 len = m->m_len - moff; 240 if (len > 0) 241 arc4_encrypt(ctx, crcbuf + noff, 242 mtod(m, caddr_t) + moff, len); 243 m = m->m_next; 244 moff = 0; 245 } 246 if (crc != le32toh(*(u_int32_t *)crcbuf)) { 247 #ifdef IEEE80211_DEBUG 248 if (ieee80211_debug) { 249 if_printf(ifp, "decrypt CRC error\n"); 250 if (ieee80211_debug > 1) 251 ieee80211_dump_pkt(n0->m_data, 252 n0->m_len, -1, -1); 253 } 254 #endif 255 goto fail; 256 } 257 } 258 m_freem(m0); 259 return n0; 260 261 fail: 262 m_freem(m0); 263 m_freem(n0); 264 return NULL; 265 } 266 267 /* 268 * CRC 32 -- routine from RFC 2083 269 */ 270 271 /* Table of CRCs of all 8-bit messages */ 272 static u_int32_t ieee80211_crc_table[256]; 273 274 /* Make the table for a fast CRC. */ 275 static void 276 ieee80211_crc_init(void) 277 { 278 u_int32_t c; 279 int n, k; 280 281 for (n = 0; n < 256; n++) { 282 c = (u_int32_t)n; 283 for (k = 0; k < 8; k++) { 284 if (c & 1) 285 c = 0xedb88320UL ^ (c >> 1); 286 else 287 c = c >> 1; 288 } 289 ieee80211_crc_table[n] = c; 290 } 291 } 292 293 /* 294 * Update a running CRC with the bytes buf[0..len-1]--the CRC 295 * should be initialized to all 1's, and the transmitted value 296 * is the 1's complement of the final running CRC 297 */ 298 299 static u_int32_t 300 ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len) 301 { 302 u_int8_t *endbuf; 303 304 for (endbuf = buf + len; buf < endbuf; buf++) 305 crc = ieee80211_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); 306 return crc; 307 } 308