11a1e1d21SSam Leffler /*- 27535e66aSSam Leffler * Copyright (c) 2001 Atsushi Onoe 31a1e1d21SSam Leffler * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 41a1e1d21SSam Leffler * All rights reserved. 51a1e1d21SSam Leffler * 61a1e1d21SSam Leffler * Redistribution and use in source and binary forms, with or without 71a1e1d21SSam Leffler * modification, are permitted provided that the following conditions 81a1e1d21SSam Leffler * are met: 91a1e1d21SSam Leffler * 1. Redistributions of source code must retain the above copyright 107535e66aSSam Leffler * notice, this list of conditions and the following disclaimer. 117535e66aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 127535e66aSSam Leffler * notice, this list of conditions and the following disclaimer in the 137535e66aSSam Leffler * documentation and/or other materials provided with the distribution. 147535e66aSSam Leffler * 3. The name of the author may not be used to endorse or promote products 157535e66aSSam Leffler * derived from this software without specific prior written permission. 161a1e1d21SSam Leffler * 171a1e1d21SSam Leffler * Alternatively, this software may be distributed under the terms of the 181a1e1d21SSam Leffler * GNU General Public License ("GPL") version 2 as published by the Free 191a1e1d21SSam Leffler * Software Foundation. 201a1e1d21SSam Leffler * 217535e66aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 227535e66aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 237535e66aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 247535e66aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 257535e66aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 267535e66aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 277535e66aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 287535e66aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 297535e66aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 307535e66aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 311a1e1d21SSam Leffler */ 321a1e1d21SSam Leffler 331a1e1d21SSam Leffler #include <sys/cdefs.h> 341a1e1d21SSam Leffler __FBSDID("$FreeBSD$"); 351a1e1d21SSam Leffler 361a1e1d21SSam Leffler #include "opt_inet.h" 371a1e1d21SSam Leffler 381a1e1d21SSam Leffler #include <sys/param.h> 391a1e1d21SSam Leffler #include <sys/systm.h> 401a1e1d21SSam Leffler #include <sys/mbuf.h> 411a1e1d21SSam Leffler #include <sys/malloc.h> 421a1e1d21SSam Leffler #include <sys/kernel.h> 431a1e1d21SSam Leffler #include <sys/socket.h> 441a1e1d21SSam Leffler #include <sys/sockio.h> 451a1e1d21SSam Leffler #include <sys/endian.h> 461a1e1d21SSam Leffler #include <sys/errno.h> 471a1e1d21SSam Leffler #include <sys/bus.h> 481a1e1d21SSam Leffler #include <sys/proc.h> 491a1e1d21SSam Leffler #include <sys/sysctl.h> 501a1e1d21SSam Leffler 511a1e1d21SSam Leffler #include <machine/atomic.h> 521a1e1d21SSam Leffler 531a1e1d21SSam Leffler #include <net/if.h> 541a1e1d21SSam Leffler #include <net/if_dl.h> 551a1e1d21SSam Leffler #include <net/if_media.h> 561a1e1d21SSam Leffler #include <net/if_arp.h> 571a1e1d21SSam Leffler #include <net/ethernet.h> 581a1e1d21SSam Leffler #include <net/if_llc.h> 591a1e1d21SSam Leffler 601a1e1d21SSam Leffler #include <net80211/ieee80211_var.h> 611a1e1d21SSam Leffler 621a1e1d21SSam Leffler #include <net/bpf.h> 631a1e1d21SSam Leffler 641a1e1d21SSam Leffler #ifdef INET 651a1e1d21SSam Leffler #include <netinet/in.h> 661a1e1d21SSam Leffler #include <netinet/if_ether.h> 671a1e1d21SSam Leffler #endif 681a1e1d21SSam Leffler 691a1e1d21SSam Leffler #include <crypto/rc4/rc4.h> 701a1e1d21SSam Leffler #define arc4_ctxlen() sizeof (struct rc4_state) 711a1e1d21SSam Leffler #define arc4_setkey(_c,_k,_l) rc4_init(_c,_k,_l) 721a1e1d21SSam Leffler #define arc4_encrypt(_c,_d,_s,_l) rc4_crypt(_c,_s,_d,_l) 731a1e1d21SSam Leffler 741a1e1d21SSam Leffler static void ieee80211_crc_init(void); 751a1e1d21SSam Leffler static u_int32_t ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len); 761a1e1d21SSam Leffler 771a1e1d21SSam Leffler void 781a1e1d21SSam Leffler ieee80211_crypto_attach(struct ifnet *ifp) 791a1e1d21SSam Leffler { 801a1e1d21SSam Leffler struct ieee80211com *ic = (void *)ifp; 811a1e1d21SSam Leffler 821a1e1d21SSam Leffler /* 831a1e1d21SSam Leffler * Setup crypto support. 841a1e1d21SSam Leffler */ 851a1e1d21SSam Leffler ieee80211_crc_init(); 861a1e1d21SSam Leffler ic->ic_iv = arc4random(); 871a1e1d21SSam Leffler } 881a1e1d21SSam Leffler 891a1e1d21SSam Leffler void 901a1e1d21SSam Leffler ieee80211_crypto_detach(struct ifnet *ifp) 911a1e1d21SSam Leffler { 921a1e1d21SSam Leffler struct ieee80211com *ic = (void *)ifp; 931a1e1d21SSam Leffler 941a1e1d21SSam Leffler if (ic->ic_wep_ctx != NULL) { 951a1e1d21SSam Leffler free(ic->ic_wep_ctx, M_DEVBUF); 961a1e1d21SSam Leffler ic->ic_wep_ctx = NULL; 971a1e1d21SSam Leffler } 981a1e1d21SSam Leffler } 991a1e1d21SSam Leffler 1001a1e1d21SSam Leffler struct mbuf * 1011a1e1d21SSam Leffler ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag) 1021a1e1d21SSam Leffler { 1031a1e1d21SSam Leffler struct ieee80211com *ic = (void *)ifp; 1041a1e1d21SSam Leffler struct mbuf *m, *n, *n0; 1051a1e1d21SSam Leffler struct ieee80211_frame *wh; 1061a1e1d21SSam Leffler int i, left, len, moff, noff, kid; 1071a1e1d21SSam Leffler u_int32_t iv, crc; 1081a1e1d21SSam Leffler u_int8_t *ivp; 1091a1e1d21SSam Leffler void *ctx; 1101a1e1d21SSam Leffler u_int8_t keybuf[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE]; 1111a1e1d21SSam Leffler u_int8_t crcbuf[IEEE80211_WEP_CRCLEN]; 1121a1e1d21SSam Leffler 1131a1e1d21SSam Leffler n0 = NULL; 1141a1e1d21SSam Leffler if ((ctx = ic->ic_wep_ctx) == NULL) { 1151a1e1d21SSam Leffler ctx = malloc(arc4_ctxlen(), M_DEVBUF, M_NOWAIT); 1161a1e1d21SSam Leffler if (ctx == NULL) 1171a1e1d21SSam Leffler goto fail; 1181a1e1d21SSam Leffler ic->ic_wep_ctx = ctx; 1191a1e1d21SSam Leffler } 1201a1e1d21SSam Leffler m = m0; 1211a1e1d21SSam Leffler left = m->m_pkthdr.len; 1221a1e1d21SSam Leffler MGET(n, M_DONTWAIT, m->m_type); 1231a1e1d21SSam Leffler n0 = n; 1241a1e1d21SSam Leffler if (n == NULL) 1251a1e1d21SSam Leffler goto fail; 1261a1e1d21SSam Leffler M_MOVE_PKTHDR(n, m); 1271a1e1d21SSam Leffler len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; 1281a1e1d21SSam Leffler if (txflag) { 1291a1e1d21SSam Leffler n->m_pkthdr.len += len; 1301a1e1d21SSam Leffler } else { 1311a1e1d21SSam Leffler n->m_pkthdr.len -= len; 1321a1e1d21SSam Leffler left -= len; 1331a1e1d21SSam Leffler } 1341a1e1d21SSam Leffler n->m_len = MHLEN; 1351a1e1d21SSam Leffler if (n->m_pkthdr.len >= MINCLSIZE) { 1361a1e1d21SSam Leffler MCLGET(n, M_DONTWAIT); 1371a1e1d21SSam Leffler if (n->m_flags & M_EXT) 1381a1e1d21SSam Leffler n->m_len = n->m_ext.ext_size; 1391a1e1d21SSam Leffler } 1401a1e1d21SSam Leffler len = sizeof(struct ieee80211_frame); 1411a1e1d21SSam Leffler memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len); 1421a1e1d21SSam Leffler wh = mtod(n, struct ieee80211_frame *); 1431a1e1d21SSam Leffler left -= len; 1441a1e1d21SSam Leffler moff = len; 1451a1e1d21SSam Leffler noff = len; 1461a1e1d21SSam Leffler if (txflag) { 1471a1e1d21SSam Leffler kid = ic->ic_wep_txkey; 1481a1e1d21SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_WEP; 1491a1e1d21SSam Leffler iv = ic->ic_iv; 1501a1e1d21SSam Leffler /* 1511a1e1d21SSam Leffler * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: 1521a1e1d21SSam Leffler * (B, 255, N) with 3 <= B < 8 1531a1e1d21SSam Leffler */ 1541a1e1d21SSam Leffler if (iv >= 0x03ff00 && 1551a1e1d21SSam Leffler (iv & 0xf8ff00) == 0x00ff00) 1561a1e1d21SSam Leffler iv += 0x000100; 1571a1e1d21SSam Leffler ic->ic_iv = iv + 1; 1581a1e1d21SSam Leffler /* put iv in little endian to prepare 802.11i */ 1591a1e1d21SSam Leffler ivp = mtod(n, u_int8_t *) + noff; 1601a1e1d21SSam Leffler for (i = 0; i < IEEE80211_WEP_IVLEN; i++) { 1611a1e1d21SSam Leffler ivp[i] = iv & 0xff; 1621a1e1d21SSam Leffler iv >>= 8; 1631a1e1d21SSam Leffler } 1641a1e1d21SSam Leffler ivp[IEEE80211_WEP_IVLEN] = kid << 6; /* pad and keyid */ 1651a1e1d21SSam Leffler noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 1661a1e1d21SSam Leffler } else { 1671a1e1d21SSam Leffler wh->i_fc[1] &= ~IEEE80211_FC1_WEP; 1681a1e1d21SSam Leffler ivp = mtod(m, u_int8_t *) + moff; 1691a1e1d21SSam Leffler kid = ivp[IEEE80211_WEP_IVLEN] >> 6; 1701a1e1d21SSam Leffler moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 1711a1e1d21SSam Leffler } 1721a1e1d21SSam Leffler memcpy(keybuf, ivp, IEEE80211_WEP_IVLEN); 1731a1e1d21SSam Leffler memcpy(keybuf + IEEE80211_WEP_IVLEN, ic->ic_nw_keys[kid].wk_key, 1741a1e1d21SSam Leffler ic->ic_nw_keys[kid].wk_len); 1751a1e1d21SSam Leffler arc4_setkey(ctx, keybuf, 1761a1e1d21SSam Leffler IEEE80211_WEP_IVLEN + ic->ic_nw_keys[kid].wk_len); 1771a1e1d21SSam Leffler 1781a1e1d21SSam Leffler /* encrypt with calculating CRC */ 1791a1e1d21SSam Leffler crc = ~0; 1801a1e1d21SSam Leffler while (left > 0) { 1811a1e1d21SSam Leffler len = m->m_len - moff; 1821a1e1d21SSam Leffler if (len == 0) { 1831a1e1d21SSam Leffler m = m->m_next; 1841a1e1d21SSam Leffler moff = 0; 1851a1e1d21SSam Leffler continue; 1861a1e1d21SSam Leffler } 1871a1e1d21SSam Leffler if (len > n->m_len - noff) { 1881a1e1d21SSam Leffler len = n->m_len - noff; 1891a1e1d21SSam Leffler if (len == 0) { 1901a1e1d21SSam Leffler MGET(n->m_next, M_DONTWAIT, n->m_type); 1911a1e1d21SSam Leffler if (n->m_next == NULL) 1921a1e1d21SSam Leffler goto fail; 1931a1e1d21SSam Leffler n = n->m_next; 1941a1e1d21SSam Leffler n->m_len = MLEN; 1951a1e1d21SSam Leffler if (left >= MINCLSIZE) { 1961a1e1d21SSam Leffler MCLGET(n, M_DONTWAIT); 1971a1e1d21SSam Leffler if (n->m_flags & M_EXT) 1981a1e1d21SSam Leffler n->m_len = n->m_ext.ext_size; 1991a1e1d21SSam Leffler } 2001a1e1d21SSam Leffler noff = 0; 2011a1e1d21SSam Leffler continue; 2021a1e1d21SSam Leffler } 2031a1e1d21SSam Leffler } 2041a1e1d21SSam Leffler if (len > left) 2051a1e1d21SSam Leffler len = left; 2061a1e1d21SSam Leffler arc4_encrypt(ctx, mtod(n, caddr_t) + noff, 2071a1e1d21SSam Leffler mtod(m, caddr_t) + moff, len); 2081a1e1d21SSam Leffler if (txflag) 2091a1e1d21SSam Leffler crc = ieee80211_crc_update(crc, 2101a1e1d21SSam Leffler mtod(m, u_int8_t *) + moff, len); 2111a1e1d21SSam Leffler else 2121a1e1d21SSam Leffler crc = ieee80211_crc_update(crc, 2131a1e1d21SSam Leffler mtod(n, u_int8_t *) + noff, len); 2141a1e1d21SSam Leffler left -= len; 2151a1e1d21SSam Leffler moff += len; 2161a1e1d21SSam Leffler noff += len; 2171a1e1d21SSam Leffler } 2181a1e1d21SSam Leffler crc = ~crc; 2191a1e1d21SSam Leffler if (txflag) { 2201a1e1d21SSam Leffler *(u_int32_t *)crcbuf = htole32(crc); 2211a1e1d21SSam Leffler if (n->m_len >= noff + sizeof(crcbuf)) 2221a1e1d21SSam Leffler n->m_len = noff + sizeof(crcbuf); 2231a1e1d21SSam Leffler else { 2241a1e1d21SSam Leffler n->m_len = noff; 2251a1e1d21SSam Leffler MGET(n->m_next, M_DONTWAIT, n->m_type); 2261a1e1d21SSam Leffler if (n->m_next == NULL) 2271a1e1d21SSam Leffler goto fail; 2281a1e1d21SSam Leffler n = n->m_next; 2291a1e1d21SSam Leffler n->m_len = sizeof(crcbuf); 2301a1e1d21SSam Leffler noff = 0; 2311a1e1d21SSam Leffler } 2321a1e1d21SSam Leffler arc4_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf, 2331a1e1d21SSam Leffler sizeof(crcbuf)); 2341a1e1d21SSam Leffler } else { 2351a1e1d21SSam Leffler n->m_len = noff; 2361a1e1d21SSam Leffler for (noff = 0; noff < sizeof(crcbuf); noff += len) { 2371a1e1d21SSam Leffler len = sizeof(crcbuf) - noff; 2381a1e1d21SSam Leffler if (len > m->m_len - moff) 2391a1e1d21SSam Leffler len = m->m_len - moff; 2401a1e1d21SSam Leffler if (len > 0) 2411a1e1d21SSam Leffler arc4_encrypt(ctx, crcbuf + noff, 2421a1e1d21SSam Leffler mtod(m, caddr_t) + moff, len); 2431a1e1d21SSam Leffler m = m->m_next; 2441a1e1d21SSam Leffler moff = 0; 2451a1e1d21SSam Leffler } 2461a1e1d21SSam Leffler if (crc != le32toh(*(u_int32_t *)crcbuf)) { 2471a1e1d21SSam Leffler #ifdef IEEE80211_DEBUG 2481a1e1d21SSam Leffler if (ieee80211_debug) { 2491a1e1d21SSam Leffler if_printf(ifp, "decrypt CRC error\n"); 2501a1e1d21SSam Leffler if (ieee80211_debug > 1) 2511a1e1d21SSam Leffler ieee80211_dump_pkt(n0->m_data, 2521a1e1d21SSam Leffler n0->m_len, -1, -1); 2531a1e1d21SSam Leffler } 2541a1e1d21SSam Leffler #endif 2551a1e1d21SSam Leffler goto fail; 2561a1e1d21SSam Leffler } 2571a1e1d21SSam Leffler } 2581a1e1d21SSam Leffler m_freem(m0); 2591a1e1d21SSam Leffler return n0; 2601a1e1d21SSam Leffler 2611a1e1d21SSam Leffler fail: 2621a1e1d21SSam Leffler m_freem(m0); 2631a1e1d21SSam Leffler m_freem(n0); 2641a1e1d21SSam Leffler return NULL; 2651a1e1d21SSam Leffler } 2661a1e1d21SSam Leffler 2671a1e1d21SSam Leffler /* 2681a1e1d21SSam Leffler * CRC 32 -- routine from RFC 2083 2691a1e1d21SSam Leffler */ 2701a1e1d21SSam Leffler 2711a1e1d21SSam Leffler /* Table of CRCs of all 8-bit messages */ 2721a1e1d21SSam Leffler static u_int32_t ieee80211_crc_table[256]; 2731a1e1d21SSam Leffler 2741a1e1d21SSam Leffler /* Make the table for a fast CRC. */ 2751a1e1d21SSam Leffler static void 2761a1e1d21SSam Leffler ieee80211_crc_init(void) 2771a1e1d21SSam Leffler { 2781a1e1d21SSam Leffler u_int32_t c; 2791a1e1d21SSam Leffler int n, k; 2801a1e1d21SSam Leffler 2811a1e1d21SSam Leffler for (n = 0; n < 256; n++) { 2821a1e1d21SSam Leffler c = (u_int32_t)n; 2831a1e1d21SSam Leffler for (k = 0; k < 8; k++) { 2841a1e1d21SSam Leffler if (c & 1) 2851a1e1d21SSam Leffler c = 0xedb88320UL ^ (c >> 1); 2861a1e1d21SSam Leffler else 2871a1e1d21SSam Leffler c = c >> 1; 2881a1e1d21SSam Leffler } 2891a1e1d21SSam Leffler ieee80211_crc_table[n] = c; 2901a1e1d21SSam Leffler } 2911a1e1d21SSam Leffler } 2921a1e1d21SSam Leffler 2931a1e1d21SSam Leffler /* 2941a1e1d21SSam Leffler * Update a running CRC with the bytes buf[0..len-1]--the CRC 2951a1e1d21SSam Leffler * should be initialized to all 1's, and the transmitted value 2961a1e1d21SSam Leffler * is the 1's complement of the final running CRC 2971a1e1d21SSam Leffler */ 2981a1e1d21SSam Leffler 2991a1e1d21SSam Leffler static u_int32_t 3001a1e1d21SSam Leffler ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len) 3011a1e1d21SSam Leffler { 3021a1e1d21SSam Leffler u_int8_t *endbuf; 3031a1e1d21SSam Leffler 3041a1e1d21SSam Leffler for (endbuf = buf + len; buf < endbuf; buf++) 3051a1e1d21SSam Leffler crc = ieee80211_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); 3061a1e1d21SSam Leffler return crc; 3071a1e1d21SSam Leffler } 308