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