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 ic->ic_stats.is_crypto_nomem++; 118 goto fail; 119 } 120 ic->ic_wep_ctx = ctx; 121 } 122 m = m0; 123 left = m->m_pkthdr.len; 124 MGET(n, M_DONTWAIT, m->m_type); 125 n0 = n; 126 if (n == NULL) { 127 if (txflag) 128 ic->ic_stats.is_tx_nombuf++; 129 else 130 ic->ic_stats.is_rx_nombuf++; 131 goto fail; 132 } 133 M_MOVE_PKTHDR(n, m); 134 len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; 135 if (txflag) { 136 n->m_pkthdr.len += len; 137 } else { 138 n->m_pkthdr.len -= len; 139 left -= len; 140 } 141 n->m_len = MHLEN; 142 if (n->m_pkthdr.len >= MINCLSIZE) { 143 MCLGET(n, M_DONTWAIT); 144 if (n->m_flags & M_EXT) 145 n->m_len = n->m_ext.ext_size; 146 } 147 len = sizeof(struct ieee80211_frame); 148 memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len); 149 wh = mtod(n, struct ieee80211_frame *); 150 left -= len; 151 moff = len; 152 noff = len; 153 if (txflag) { 154 kid = ic->ic_wep_txkey; 155 wh->i_fc[1] |= IEEE80211_FC1_WEP; 156 iv = ic->ic_iv; 157 /* 158 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: 159 * (B, 255, N) with 3 <= B < 8 160 */ 161 if (iv >= 0x03ff00 && 162 (iv & 0xf8ff00) == 0x00ff00) 163 iv += 0x000100; 164 ic->ic_iv = iv + 1; 165 /* put iv in little endian to prepare 802.11i */ 166 ivp = mtod(n, u_int8_t *) + noff; 167 for (i = 0; i < IEEE80211_WEP_IVLEN; i++) { 168 ivp[i] = iv & 0xff; 169 iv >>= 8; 170 } 171 ivp[IEEE80211_WEP_IVLEN] = kid << 6; /* pad and keyid */ 172 noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 173 } else { 174 wh->i_fc[1] &= ~IEEE80211_FC1_WEP; 175 ivp = mtod(m, u_int8_t *) + moff; 176 kid = ivp[IEEE80211_WEP_IVLEN] >> 6; 177 moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 178 } 179 memcpy(keybuf, ivp, IEEE80211_WEP_IVLEN); 180 memcpy(keybuf + IEEE80211_WEP_IVLEN, ic->ic_nw_keys[kid].wk_key, 181 ic->ic_nw_keys[kid].wk_len); 182 arc4_setkey(ctx, keybuf, 183 IEEE80211_WEP_IVLEN + ic->ic_nw_keys[kid].wk_len); 184 185 /* encrypt with calculating CRC */ 186 crc = ~0; 187 while (left > 0) { 188 len = m->m_len - moff; 189 if (len == 0) { 190 m = m->m_next; 191 moff = 0; 192 continue; 193 } 194 if (len > n->m_len - noff) { 195 len = n->m_len - noff; 196 if (len == 0) { 197 MGET(n->m_next, M_DONTWAIT, n->m_type); 198 if (n->m_next == NULL) { 199 if (txflag) 200 ic->ic_stats.is_tx_nombuf++; 201 else 202 ic->ic_stats.is_rx_nombuf++; 203 goto fail; 204 } 205 n = n->m_next; 206 n->m_len = MLEN; 207 if (left >= MINCLSIZE) { 208 MCLGET(n, M_DONTWAIT); 209 if (n->m_flags & M_EXT) 210 n->m_len = n->m_ext.ext_size; 211 } 212 noff = 0; 213 continue; 214 } 215 } 216 if (len > left) 217 len = left; 218 arc4_encrypt(ctx, mtod(n, caddr_t) + noff, 219 mtod(m, caddr_t) + moff, len); 220 if (txflag) 221 crc = ieee80211_crc_update(crc, 222 mtod(m, u_int8_t *) + moff, len); 223 else 224 crc = ieee80211_crc_update(crc, 225 mtod(n, u_int8_t *) + noff, len); 226 left -= len; 227 moff += len; 228 noff += len; 229 } 230 crc = ~crc; 231 if (txflag) { 232 *(u_int32_t *)crcbuf = htole32(crc); 233 if (n->m_len >= noff + sizeof(crcbuf)) 234 n->m_len = noff + sizeof(crcbuf); 235 else { 236 n->m_len = noff; 237 MGET(n->m_next, M_DONTWAIT, n->m_type); 238 if (n->m_next == NULL) { 239 ic->ic_stats.is_tx_nombuf++; 240 goto fail; 241 } 242 n = n->m_next; 243 n->m_len = sizeof(crcbuf); 244 noff = 0; 245 } 246 arc4_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf, 247 sizeof(crcbuf)); 248 } else { 249 n->m_len = noff; 250 for (noff = 0; noff < sizeof(crcbuf); noff += len) { 251 len = sizeof(crcbuf) - noff; 252 if (len > m->m_len - moff) 253 len = m->m_len - moff; 254 if (len > 0) 255 arc4_encrypt(ctx, crcbuf + noff, 256 mtod(m, caddr_t) + moff, len); 257 m = m->m_next; 258 moff = 0; 259 } 260 if (crc != le32toh(*(u_int32_t *)crcbuf)) { 261 #ifdef IEEE80211_DEBUG 262 if (ieee80211_debug) { 263 if_printf(ifp, "decrypt CRC error\n"); 264 if (ieee80211_debug > 1) 265 ieee80211_dump_pkt(n0->m_data, 266 n0->m_len, -1, -1); 267 } 268 #endif 269 ic->ic_stats.is_rx_decryptcrc++; 270 goto fail; 271 } 272 } 273 m_freem(m0); 274 return n0; 275 276 fail: 277 m_freem(m0); 278 m_freem(n0); 279 return NULL; 280 } 281 282 /* 283 * CRC 32 -- routine from RFC 2083 284 */ 285 286 /* Table of CRCs of all 8-bit messages */ 287 static u_int32_t ieee80211_crc_table[256]; 288 289 /* Make the table for a fast CRC. */ 290 static void 291 ieee80211_crc_init(void) 292 { 293 u_int32_t c; 294 int n, k; 295 296 for (n = 0; n < 256; n++) { 297 c = (u_int32_t)n; 298 for (k = 0; k < 8; k++) { 299 if (c & 1) 300 c = 0xedb88320UL ^ (c >> 1); 301 else 302 c = c >> 1; 303 } 304 ieee80211_crc_table[n] = c; 305 } 306 } 307 308 /* 309 * Update a running CRC with the bytes buf[0..len-1]--the CRC 310 * should be initialized to all 1's, and the transmitted value 311 * is the 1's complement of the final running CRC 312 */ 313 314 static u_int32_t 315 ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len) 316 { 317 u_int8_t *endbuf; 318 319 for (endbuf = buf + len; buf < endbuf; buf++) 320 crc = ieee80211_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); 321 return crc; 322 } 323