11bba5b73SBruno Randolf /* 21bba5b73SBruno Randolf * Copyright (c) 2009 Atheros Communications Inc. 31bba5b73SBruno Randolf * Copyright (c) 2010 Bruno Randolf <br1@einfach.org> 41bba5b73SBruno Randolf * 51bba5b73SBruno Randolf * Permission to use, copy, modify, and/or distribute this software for any 61bba5b73SBruno Randolf * purpose with or without fee is hereby granted, provided that the above 71bba5b73SBruno Randolf * copyright notice and this permission notice appear in all copies. 81bba5b73SBruno Randolf * 91bba5b73SBruno Randolf * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 101bba5b73SBruno Randolf * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 111bba5b73SBruno Randolf * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 121bba5b73SBruno Randolf * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 131bba5b73SBruno Randolf * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 141bba5b73SBruno Randolf * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 151bba5b73SBruno Randolf * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 161bba5b73SBruno Randolf */ 171bba5b73SBruno Randolf 18ee40fa06SPaul Gortmaker #include <linux/export.h> 191bba5b73SBruno Randolf #include <asm/unaligned.h> 201bba5b73SBruno Randolf #include <net/mac80211.h> 211bba5b73SBruno Randolf 221bba5b73SBruno Randolf #include "ath.h" 231bba5b73SBruno Randolf #include "reg.h" 241bba5b73SBruno Randolf 251bba5b73SBruno Randolf #define REG_READ (common->ops->read) 261bba5b73SBruno Randolf #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) 27b0a9ede2SRajkumar Manoharan #define ENABLE_REGWRITE_BUFFER(_ah) \ 28b0a9ede2SRajkumar Manoharan if (common->ops->enable_write_buffer) \ 29b0a9ede2SRajkumar Manoharan common->ops->enable_write_buffer((_ah)); 30b0a9ede2SRajkumar Manoharan 31b0a9ede2SRajkumar Manoharan #define REGWRITE_BUFFER_FLUSH(_ah) \ 32b0a9ede2SRajkumar Manoharan if (common->ops->write_flush) \ 33b0a9ede2SRajkumar Manoharan common->ops->write_flush((_ah)); 34b0a9ede2SRajkumar Manoharan 351bba5b73SBruno Randolf 361bba5b73SBruno Randolf #define IEEE80211_WEP_NKID 4 /* number of key ids */ 371bba5b73SBruno Randolf 381bba5b73SBruno Randolf /************************/ 391bba5b73SBruno Randolf /* Key Cache Management */ 401bba5b73SBruno Randolf /************************/ 411bba5b73SBruno Randolf 421bba5b73SBruno Randolf bool ath_hw_keyreset(struct ath_common *common, u16 entry) 431bba5b73SBruno Randolf { 441bba5b73SBruno Randolf u32 keyType; 451bba5b73SBruno Randolf void *ah = common->ah; 461bba5b73SBruno Randolf 471bba5b73SBruno Randolf if (entry >= common->keymax) { 48fedf1d80SBen Greear ath_err(common, "keyreset: keycache entry %u out of range\n", 49fedf1d80SBen Greear entry); 501bba5b73SBruno Randolf return false; 511bba5b73SBruno Randolf } 521bba5b73SBruno Randolf 531bba5b73SBruno Randolf keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); 541bba5b73SBruno Randolf 55b0a9ede2SRajkumar Manoharan ENABLE_REGWRITE_BUFFER(ah); 56b0a9ede2SRajkumar Manoharan 571bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); 581bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); 591bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); 601bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); 611bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); 621bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); 631bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); 641bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); 651bba5b73SBruno Randolf 661bba5b73SBruno Randolf if (keyType == AR_KEYTABLE_TYPE_TKIP) { 671bba5b73SBruno Randolf u16 micentry = entry + 64; 681bba5b73SBruno Randolf 691bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); 701bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); 711bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); 721bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); 738e546104SJouni Malinen if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { 74998d516dSRajkumar Manoharan REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); 758e546104SJouni Malinen REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), 768e546104SJouni Malinen AR_KEYTABLE_TYPE_CLR); 778e546104SJouni Malinen } 781bba5b73SBruno Randolf 791bba5b73SBruno Randolf } 801bba5b73SBruno Randolf 81b0a9ede2SRajkumar Manoharan REGWRITE_BUFFER_FLUSH(ah); 82b0a9ede2SRajkumar Manoharan 831bba5b73SBruno Randolf return true; 841bba5b73SBruno Randolf } 851bba5b73SBruno Randolf EXPORT_SYMBOL(ath_hw_keyreset); 861bba5b73SBruno Randolf 87d2d3e364SJouni Malinen bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac) 881bba5b73SBruno Randolf { 891bba5b73SBruno Randolf u32 macHi, macLo; 901bba5b73SBruno Randolf u32 unicast_flag = AR_KEYTABLE_VALID; 911bba5b73SBruno Randolf void *ah = common->ah; 921bba5b73SBruno Randolf 931bba5b73SBruno Randolf if (entry >= common->keymax) { 94fedf1d80SBen Greear ath_err(common, "keysetmac: keycache entry %u out of range\n", 95fedf1d80SBen Greear entry); 961bba5b73SBruno Randolf return false; 971bba5b73SBruno Randolf } 981bba5b73SBruno Randolf 991bba5b73SBruno Randolf if (mac != NULL) { 1001bba5b73SBruno Randolf /* 1011bba5b73SBruno Randolf * AR_KEYTABLE_VALID indicates that the address is a unicast 1021bba5b73SBruno Randolf * address, which must match the transmitter address for 1031bba5b73SBruno Randolf * decrypting frames. 1041bba5b73SBruno Randolf * Not setting this bit allows the hardware to use the key 1051bba5b73SBruno Randolf * for multicast frame decryption. 1061bba5b73SBruno Randolf */ 1071bba5b73SBruno Randolf if (mac[0] & 0x01) 1081bba5b73SBruno Randolf unicast_flag = 0; 1091bba5b73SBruno Randolf 110d47d78dfSPavel Roskin macLo = get_unaligned_le32(mac); 111d47d78dfSPavel Roskin macHi = get_unaligned_le16(mac + 4); 1121bba5b73SBruno Randolf macLo >>= 1; 1131bba5b73SBruno Randolf macLo |= (macHi & 1) << 31; 1141bba5b73SBruno Randolf macHi >>= 1; 1151bba5b73SBruno Randolf } else { 1161bba5b73SBruno Randolf macLo = macHi = 0; 1171bba5b73SBruno Randolf } 118b0a9ede2SRajkumar Manoharan ENABLE_REGWRITE_BUFFER(ah); 119b0a9ede2SRajkumar Manoharan 1201bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); 1211bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag); 1221bba5b73SBruno Randolf 123b0a9ede2SRajkumar Manoharan REGWRITE_BUFFER_FLUSH(ah); 124b0a9ede2SRajkumar Manoharan 1251bba5b73SBruno Randolf return true; 1261bba5b73SBruno Randolf } 127d2d3e364SJouni Malinen EXPORT_SYMBOL(ath_hw_keysetmac); 1281bba5b73SBruno Randolf 129f8c2a087SLuis R. Rodriguez static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, 1301bba5b73SBruno Randolf const struct ath_keyval *k, 1311bba5b73SBruno Randolf const u8 *mac) 1321bba5b73SBruno Randolf { 1331bba5b73SBruno Randolf void *ah = common->ah; 1341bba5b73SBruno Randolf u32 key0, key1, key2, key3, key4; 1351bba5b73SBruno Randolf u32 keyType; 1361bba5b73SBruno Randolf 1371bba5b73SBruno Randolf if (entry >= common->keymax) { 138fedf1d80SBen Greear ath_err(common, "set-entry: keycache entry %u out of range\n", 139fedf1d80SBen Greear entry); 1401bba5b73SBruno Randolf return false; 1411bba5b73SBruno Randolf } 1421bba5b73SBruno Randolf 1431bba5b73SBruno Randolf switch (k->kv_type) { 1441bba5b73SBruno Randolf case ATH_CIPHER_AES_OCB: 1451bba5b73SBruno Randolf keyType = AR_KEYTABLE_TYPE_AES; 1461bba5b73SBruno Randolf break; 1471bba5b73SBruno Randolf case ATH_CIPHER_AES_CCM: 1481bba5b73SBruno Randolf if (!(common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)) { 149d2182b69SJoe Perches ath_dbg(common, ANY, 1501bba5b73SBruno Randolf "AES-CCM not supported by this mac rev\n"); 1511bba5b73SBruno Randolf return false; 1521bba5b73SBruno Randolf } 1531bba5b73SBruno Randolf keyType = AR_KEYTABLE_TYPE_CCM; 1541bba5b73SBruno Randolf break; 1551bba5b73SBruno Randolf case ATH_CIPHER_TKIP: 1561bba5b73SBruno Randolf keyType = AR_KEYTABLE_TYPE_TKIP; 1571bba5b73SBruno Randolf if (entry + 64 >= common->keymax) { 158d2182b69SJoe Perches ath_dbg(common, ANY, 1591bba5b73SBruno Randolf "entry %u inappropriate for TKIP\n", entry); 1601bba5b73SBruno Randolf return false; 1611bba5b73SBruno Randolf } 1621bba5b73SBruno Randolf break; 1631bba5b73SBruno Randolf case ATH_CIPHER_WEP: 1641bba5b73SBruno Randolf if (k->kv_len < WLAN_KEY_LEN_WEP40) { 165d2182b69SJoe Perches ath_dbg(common, ANY, "WEP key length %u too small\n", 166d2182b69SJoe Perches k->kv_len); 1671bba5b73SBruno Randolf return false; 1681bba5b73SBruno Randolf } 1691bba5b73SBruno Randolf if (k->kv_len <= WLAN_KEY_LEN_WEP40) 1701bba5b73SBruno Randolf keyType = AR_KEYTABLE_TYPE_40; 1711bba5b73SBruno Randolf else if (k->kv_len <= WLAN_KEY_LEN_WEP104) 1721bba5b73SBruno Randolf keyType = AR_KEYTABLE_TYPE_104; 1731bba5b73SBruno Randolf else 1741bba5b73SBruno Randolf keyType = AR_KEYTABLE_TYPE_128; 1751bba5b73SBruno Randolf break; 1761bba5b73SBruno Randolf case ATH_CIPHER_CLR: 1771bba5b73SBruno Randolf keyType = AR_KEYTABLE_TYPE_CLR; 1781bba5b73SBruno Randolf break; 1791bba5b73SBruno Randolf default: 1803800276aSJoe Perches ath_err(common, "cipher %u not supported\n", k->kv_type); 1811bba5b73SBruno Randolf return false; 1821bba5b73SBruno Randolf } 1831bba5b73SBruno Randolf 1841bba5b73SBruno Randolf key0 = get_unaligned_le32(k->kv_val + 0); 1851bba5b73SBruno Randolf key1 = get_unaligned_le16(k->kv_val + 4); 1861bba5b73SBruno Randolf key2 = get_unaligned_le32(k->kv_val + 6); 1871bba5b73SBruno Randolf key3 = get_unaligned_le16(k->kv_val + 10); 1881bba5b73SBruno Randolf key4 = get_unaligned_le32(k->kv_val + 12); 1891bba5b73SBruno Randolf if (k->kv_len <= WLAN_KEY_LEN_WEP104) 1901bba5b73SBruno Randolf key4 &= 0xff; 1911bba5b73SBruno Randolf 1921bba5b73SBruno Randolf /* 1931bba5b73SBruno Randolf * Note: Key cache registers access special memory area that requires 1941bba5b73SBruno Randolf * two 32-bit writes to actually update the values in the internal 1951bba5b73SBruno Randolf * memory. Consequently, the exact order and pairs used here must be 1961bba5b73SBruno Randolf * maintained. 1971bba5b73SBruno Randolf */ 1981bba5b73SBruno Randolf 1991bba5b73SBruno Randolf if (keyType == AR_KEYTABLE_TYPE_TKIP) { 2001bba5b73SBruno Randolf u16 micentry = entry + 64; 2011bba5b73SBruno Randolf 2021bba5b73SBruno Randolf /* 2031bba5b73SBruno Randolf * Write inverted key[47:0] first to avoid Michael MIC errors 2041bba5b73SBruno Randolf * on frames that could be sent or received at the same time. 2051bba5b73SBruno Randolf * The correct key will be written in the end once everything 2061bba5b73SBruno Randolf * else is ready. 2071bba5b73SBruno Randolf */ 2081bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); 2091bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); 2101bba5b73SBruno Randolf 2111bba5b73SBruno Randolf /* Write key[95:48] */ 2121bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); 2131bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); 2141bba5b73SBruno Randolf 2151bba5b73SBruno Randolf /* Write key[127:96] and key type */ 2161bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); 2171bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); 2181bba5b73SBruno Randolf 2191bba5b73SBruno Randolf /* Write MAC address for the entry */ 2201bba5b73SBruno Randolf (void) ath_hw_keysetmac(common, entry, mac); 2211bba5b73SBruno Randolf 222117675d0SBruno Randolf if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { 2231bba5b73SBruno Randolf /* 2241bba5b73SBruno Randolf * TKIP uses two key cache entries: 2251bba5b73SBruno Randolf * Michael MIC TX/RX keys in the same key cache entry 2261bba5b73SBruno Randolf * (idx = main index + 64): 2271bba5b73SBruno Randolf * key0 [31:0] = RX key [31:0] 2281bba5b73SBruno Randolf * key1 [15:0] = TX key [31:16] 2291bba5b73SBruno Randolf * key1 [31:16] = reserved 2301bba5b73SBruno Randolf * key2 [31:0] = RX key [63:32] 2311bba5b73SBruno Randolf * key3 [15:0] = TX key [15:0] 2321bba5b73SBruno Randolf * key3 [31:16] = reserved 2331bba5b73SBruno Randolf * key4 [31:0] = TX key [63:32] 2341bba5b73SBruno Randolf */ 2351bba5b73SBruno Randolf u32 mic0, mic1, mic2, mic3, mic4; 2361bba5b73SBruno Randolf 2371bba5b73SBruno Randolf mic0 = get_unaligned_le32(k->kv_mic + 0); 2381bba5b73SBruno Randolf mic2 = get_unaligned_le32(k->kv_mic + 4); 2391bba5b73SBruno Randolf mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; 2401bba5b73SBruno Randolf mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; 2411bba5b73SBruno Randolf mic4 = get_unaligned_le32(k->kv_txmic + 4); 2421bba5b73SBruno Randolf 243b0a9ede2SRajkumar Manoharan ENABLE_REGWRITE_BUFFER(ah); 244b0a9ede2SRajkumar Manoharan 2451bba5b73SBruno Randolf /* Write RX[31:0] and TX[31:16] */ 2461bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); 2471bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); 2481bba5b73SBruno Randolf 2491bba5b73SBruno Randolf /* Write RX[63:32] and TX[15:0] */ 2501bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); 2511bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); 2521bba5b73SBruno Randolf 2531bba5b73SBruno Randolf /* Write TX[63:32] and keyType(reserved) */ 2541bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); 2551bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), 2561bba5b73SBruno Randolf AR_KEYTABLE_TYPE_CLR); 2571bba5b73SBruno Randolf 258b0a9ede2SRajkumar Manoharan REGWRITE_BUFFER_FLUSH(ah); 259b0a9ede2SRajkumar Manoharan 2601bba5b73SBruno Randolf } else { 2611bba5b73SBruno Randolf /* 2621bba5b73SBruno Randolf * TKIP uses four key cache entries (two for group 2631bba5b73SBruno Randolf * keys): 2641bba5b73SBruno Randolf * Michael MIC TX/RX keys are in different key cache 2651bba5b73SBruno Randolf * entries (idx = main index + 64 for TX and 2661bba5b73SBruno Randolf * main index + 32 + 96 for RX): 2671bba5b73SBruno Randolf * key0 [31:0] = TX/RX MIC key [31:0] 2681bba5b73SBruno Randolf * key1 [31:0] = reserved 2691bba5b73SBruno Randolf * key2 [31:0] = TX/RX MIC key [63:32] 2701bba5b73SBruno Randolf * key3 [31:0] = reserved 2711bba5b73SBruno Randolf * key4 [31:0] = reserved 2721bba5b73SBruno Randolf * 2731bba5b73SBruno Randolf * Upper layer code will call this function separately 2741bba5b73SBruno Randolf * for TX and RX keys when these registers offsets are 2751bba5b73SBruno Randolf * used. 2761bba5b73SBruno Randolf */ 2771bba5b73SBruno Randolf u32 mic0, mic2; 2781bba5b73SBruno Randolf 2791bba5b73SBruno Randolf mic0 = get_unaligned_le32(k->kv_mic + 0); 2801bba5b73SBruno Randolf mic2 = get_unaligned_le32(k->kv_mic + 4); 2811bba5b73SBruno Randolf 282b0a9ede2SRajkumar Manoharan ENABLE_REGWRITE_BUFFER(ah); 283b0a9ede2SRajkumar Manoharan 2841bba5b73SBruno Randolf /* Write MIC key[31:0] */ 2851bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); 2861bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); 2871bba5b73SBruno Randolf 2881bba5b73SBruno Randolf /* Write MIC key[63:32] */ 2891bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); 2901bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); 2911bba5b73SBruno Randolf 2921bba5b73SBruno Randolf /* Write TX[63:32] and keyType(reserved) */ 2931bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); 2941bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), 2951bba5b73SBruno Randolf AR_KEYTABLE_TYPE_CLR); 296b0a9ede2SRajkumar Manoharan 297b0a9ede2SRajkumar Manoharan REGWRITE_BUFFER_FLUSH(ah); 2981bba5b73SBruno Randolf } 2991bba5b73SBruno Randolf 300b0a9ede2SRajkumar Manoharan ENABLE_REGWRITE_BUFFER(ah); 301b0a9ede2SRajkumar Manoharan 3021bba5b73SBruno Randolf /* MAC address registers are reserved for the MIC entry */ 3031bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); 3041bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); 3051bba5b73SBruno Randolf 3061bba5b73SBruno Randolf /* 3071bba5b73SBruno Randolf * Write the correct (un-inverted) key[47:0] last to enable 3081bba5b73SBruno Randolf * TKIP now that all other registers are set with correct 3091bba5b73SBruno Randolf * values. 3101bba5b73SBruno Randolf */ 3111bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); 3121bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); 313b0a9ede2SRajkumar Manoharan 314b0a9ede2SRajkumar Manoharan REGWRITE_BUFFER_FLUSH(ah); 3151bba5b73SBruno Randolf } else { 316b0a9ede2SRajkumar Manoharan ENABLE_REGWRITE_BUFFER(ah); 317b0a9ede2SRajkumar Manoharan 3181bba5b73SBruno Randolf /* Write key[47:0] */ 3191bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); 3201bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); 3211bba5b73SBruno Randolf 3221bba5b73SBruno Randolf /* Write key[95:48] */ 3231bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); 3241bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); 3251bba5b73SBruno Randolf 3261bba5b73SBruno Randolf /* Write key[127:96] and key type */ 3271bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); 3281bba5b73SBruno Randolf REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); 3291bba5b73SBruno Randolf 330b0a9ede2SRajkumar Manoharan REGWRITE_BUFFER_FLUSH(ah); 331b0a9ede2SRajkumar Manoharan 3321bba5b73SBruno Randolf /* Write MAC address for the entry */ 3331bba5b73SBruno Randolf (void) ath_hw_keysetmac(common, entry, mac); 3341bba5b73SBruno Randolf } 3351bba5b73SBruno Randolf 3361bba5b73SBruno Randolf return true; 3371bba5b73SBruno Randolf } 3381bba5b73SBruno Randolf 3391bba5b73SBruno Randolf static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, 3401bba5b73SBruno Randolf struct ath_keyval *hk, const u8 *addr, 3411bba5b73SBruno Randolf bool authenticator) 3421bba5b73SBruno Randolf { 3431bba5b73SBruno Randolf const u8 *key_rxmic; 3441bba5b73SBruno Randolf const u8 *key_txmic; 3451bba5b73SBruno Randolf 3461bba5b73SBruno Randolf key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; 3471bba5b73SBruno Randolf key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; 3481bba5b73SBruno Randolf 3491bba5b73SBruno Randolf if (addr == NULL) { 3501bba5b73SBruno Randolf /* 3511bba5b73SBruno Randolf * Group key installation - only two key cache entries are used 3521bba5b73SBruno Randolf * regardless of splitmic capability since group key is only 3531bba5b73SBruno Randolf * used either for TX or RX. 3541bba5b73SBruno Randolf */ 3551bba5b73SBruno Randolf if (authenticator) { 3561bba5b73SBruno Randolf memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); 3571bba5b73SBruno Randolf memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); 3581bba5b73SBruno Randolf } else { 3591bba5b73SBruno Randolf memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); 3601bba5b73SBruno Randolf memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); 3611bba5b73SBruno Randolf } 3621bba5b73SBruno Randolf return ath_hw_set_keycache_entry(common, keyix, hk, addr); 3631bba5b73SBruno Randolf } 364117675d0SBruno Randolf if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { 3651bba5b73SBruno Randolf /* TX and RX keys share the same key cache entry. */ 3661bba5b73SBruno Randolf memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); 3671bba5b73SBruno Randolf memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); 3681bba5b73SBruno Randolf return ath_hw_set_keycache_entry(common, keyix, hk, addr); 3691bba5b73SBruno Randolf } 3701bba5b73SBruno Randolf 3711bba5b73SBruno Randolf /* Separate key cache entries for TX and RX */ 3721bba5b73SBruno Randolf 3731bba5b73SBruno Randolf /* TX key goes at first index, RX key at +32. */ 3741bba5b73SBruno Randolf memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); 3751bba5b73SBruno Randolf if (!ath_hw_set_keycache_entry(common, keyix, hk, NULL)) { 3761bba5b73SBruno Randolf /* TX MIC entry failed. No need to proceed further */ 3773800276aSJoe Perches ath_err(common, "Setting TX MIC Key Failed\n"); 3781bba5b73SBruno Randolf return 0; 3791bba5b73SBruno Randolf } 3801bba5b73SBruno Randolf 3811bba5b73SBruno Randolf memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); 3821bba5b73SBruno Randolf /* XXX delete tx key on failure? */ 3831bba5b73SBruno Randolf return ath_hw_set_keycache_entry(common, keyix + 32, hk, addr); 3841bba5b73SBruno Randolf } 3851bba5b73SBruno Randolf 3861bba5b73SBruno Randolf static int ath_reserve_key_cache_slot_tkip(struct ath_common *common) 3871bba5b73SBruno Randolf { 3881bba5b73SBruno Randolf int i; 3891bba5b73SBruno Randolf 3901bba5b73SBruno Randolf for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { 3911bba5b73SBruno Randolf if (test_bit(i, common->keymap) || 3921bba5b73SBruno Randolf test_bit(i + 64, common->keymap)) 3931bba5b73SBruno Randolf continue; /* At least one part of TKIP key allocated */ 394117675d0SBruno Randolf if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) && 3951bba5b73SBruno Randolf (test_bit(i + 32, common->keymap) || 3961bba5b73SBruno Randolf test_bit(i + 64 + 32, common->keymap))) 3971bba5b73SBruno Randolf continue; /* At least one part of TKIP key allocated */ 3981bba5b73SBruno Randolf 3991bba5b73SBruno Randolf /* Found a free slot for a TKIP key */ 4001bba5b73SBruno Randolf return i; 4011bba5b73SBruno Randolf } 4021bba5b73SBruno Randolf return -1; 4031bba5b73SBruno Randolf } 4041bba5b73SBruno Randolf 4051bba5b73SBruno Randolf static int ath_reserve_key_cache_slot(struct ath_common *common, 4061bba5b73SBruno Randolf u32 cipher) 4071bba5b73SBruno Randolf { 4081bba5b73SBruno Randolf int i; 4091bba5b73SBruno Randolf 4101bba5b73SBruno Randolf if (cipher == WLAN_CIPHER_SUITE_TKIP) 4111bba5b73SBruno Randolf return ath_reserve_key_cache_slot_tkip(common); 4121bba5b73SBruno Randolf 4131bba5b73SBruno Randolf /* First, try to find slots that would not be available for TKIP. */ 414117675d0SBruno Randolf if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { 4151bba5b73SBruno Randolf for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { 4161bba5b73SBruno Randolf if (!test_bit(i, common->keymap) && 4171bba5b73SBruno Randolf (test_bit(i + 32, common->keymap) || 4181bba5b73SBruno Randolf test_bit(i + 64, common->keymap) || 4191bba5b73SBruno Randolf test_bit(i + 64 + 32, common->keymap))) 4201bba5b73SBruno Randolf return i; 4211bba5b73SBruno Randolf if (!test_bit(i + 32, common->keymap) && 4221bba5b73SBruno Randolf (test_bit(i, common->keymap) || 4231bba5b73SBruno Randolf test_bit(i + 64, common->keymap) || 4241bba5b73SBruno Randolf test_bit(i + 64 + 32, common->keymap))) 4251bba5b73SBruno Randolf return i + 32; 4261bba5b73SBruno Randolf if (!test_bit(i + 64, common->keymap) && 4271bba5b73SBruno Randolf (test_bit(i , common->keymap) || 4281bba5b73SBruno Randolf test_bit(i + 32, common->keymap) || 4291bba5b73SBruno Randolf test_bit(i + 64 + 32, common->keymap))) 4301bba5b73SBruno Randolf return i + 64; 4311bba5b73SBruno Randolf if (!test_bit(i + 64 + 32, common->keymap) && 4321bba5b73SBruno Randolf (test_bit(i, common->keymap) || 4331bba5b73SBruno Randolf test_bit(i + 32, common->keymap) || 4341bba5b73SBruno Randolf test_bit(i + 64, common->keymap))) 4351bba5b73SBruno Randolf return i + 64 + 32; 4361bba5b73SBruno Randolf } 4371bba5b73SBruno Randolf } else { 4381bba5b73SBruno Randolf for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { 4391bba5b73SBruno Randolf if (!test_bit(i, common->keymap) && 4401bba5b73SBruno Randolf test_bit(i + 64, common->keymap)) 4411bba5b73SBruno Randolf return i; 4421bba5b73SBruno Randolf if (test_bit(i, common->keymap) && 4431bba5b73SBruno Randolf !test_bit(i + 64, common->keymap)) 4441bba5b73SBruno Randolf return i + 64; 4451bba5b73SBruno Randolf } 4461bba5b73SBruno Randolf } 4471bba5b73SBruno Randolf 4481bba5b73SBruno Randolf /* No partially used TKIP slots, pick any available slot */ 4491bba5b73SBruno Randolf for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { 4501bba5b73SBruno Randolf /* Do not allow slots that could be needed for TKIP group keys 4511bba5b73SBruno Randolf * to be used. This limitation could be removed if we know that 4521bba5b73SBruno Randolf * TKIP will not be used. */ 4531bba5b73SBruno Randolf if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) 4541bba5b73SBruno Randolf continue; 455117675d0SBruno Randolf if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { 4561bba5b73SBruno Randolf if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) 4571bba5b73SBruno Randolf continue; 4581bba5b73SBruno Randolf if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) 4591bba5b73SBruno Randolf continue; 4601bba5b73SBruno Randolf } 4611bba5b73SBruno Randolf 4621bba5b73SBruno Randolf if (!test_bit(i, common->keymap)) 4631bba5b73SBruno Randolf return i; /* Found a free slot for a key */ 4641bba5b73SBruno Randolf } 4651bba5b73SBruno Randolf 4661bba5b73SBruno Randolf /* No free slot found */ 4671bba5b73SBruno Randolf return -1; 4681bba5b73SBruno Randolf } 4691bba5b73SBruno Randolf 4701bba5b73SBruno Randolf /* 4711bba5b73SBruno Randolf * Configure encryption in the HW. 4721bba5b73SBruno Randolf */ 4731bba5b73SBruno Randolf int ath_key_config(struct ath_common *common, 4741bba5b73SBruno Randolf struct ieee80211_vif *vif, 4751bba5b73SBruno Randolf struct ieee80211_sta *sta, 4761bba5b73SBruno Randolf struct ieee80211_key_conf *key) 4771bba5b73SBruno Randolf { 4781bba5b73SBruno Randolf struct ath_keyval hk; 4791bba5b73SBruno Randolf const u8 *mac = NULL; 4801bba5b73SBruno Randolf u8 gmac[ETH_ALEN]; 4811bba5b73SBruno Randolf int ret = 0; 4821bba5b73SBruno Randolf int idx; 4831bba5b73SBruno Randolf 4841bba5b73SBruno Randolf memset(&hk, 0, sizeof(hk)); 4851bba5b73SBruno Randolf 4861bba5b73SBruno Randolf switch (key->cipher) { 48793ae2dd2SFelix Fietkau case 0: 48893ae2dd2SFelix Fietkau hk.kv_type = ATH_CIPHER_CLR; 48993ae2dd2SFelix Fietkau break; 4901bba5b73SBruno Randolf case WLAN_CIPHER_SUITE_WEP40: 4911bba5b73SBruno Randolf case WLAN_CIPHER_SUITE_WEP104: 4921bba5b73SBruno Randolf hk.kv_type = ATH_CIPHER_WEP; 4931bba5b73SBruno Randolf break; 4941bba5b73SBruno Randolf case WLAN_CIPHER_SUITE_TKIP: 4951bba5b73SBruno Randolf hk.kv_type = ATH_CIPHER_TKIP; 4961bba5b73SBruno Randolf break; 4971bba5b73SBruno Randolf case WLAN_CIPHER_SUITE_CCMP: 4981bba5b73SBruno Randolf hk.kv_type = ATH_CIPHER_AES_CCM; 4991bba5b73SBruno Randolf break; 5001bba5b73SBruno Randolf default: 5011bba5b73SBruno Randolf return -EOPNOTSUPP; 5021bba5b73SBruno Randolf } 5031bba5b73SBruno Randolf 5041bba5b73SBruno Randolf hk.kv_len = key->keylen; 50593ae2dd2SFelix Fietkau if (key->keylen) 506*bfcc8ba4SKees Cook memcpy(&hk.kv_values, key->key, key->keylen); 5071bba5b73SBruno Randolf 5081bba5b73SBruno Randolf if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { 5091bba5b73SBruno Randolf switch (vif->type) { 5101bba5b73SBruno Randolf case NL80211_IFTYPE_AP: 5111bba5b73SBruno Randolf memcpy(gmac, vif->addr, ETH_ALEN); 5121bba5b73SBruno Randolf gmac[0] |= 0x01; 5131bba5b73SBruno Randolf mac = gmac; 5141bba5b73SBruno Randolf idx = ath_reserve_key_cache_slot(common, key->cipher); 5151bba5b73SBruno Randolf break; 5161bba5b73SBruno Randolf case NL80211_IFTYPE_ADHOC: 5171bba5b73SBruno Randolf if (!sta) { 5181bba5b73SBruno Randolf idx = key->keyidx; 5191bba5b73SBruno Randolf break; 5201bba5b73SBruno Randolf } 5211bba5b73SBruno Randolf memcpy(gmac, sta->addr, ETH_ALEN); 5221bba5b73SBruno Randolf gmac[0] |= 0x01; 5231bba5b73SBruno Randolf mac = gmac; 5241bba5b73SBruno Randolf idx = ath_reserve_key_cache_slot(common, key->cipher); 5251bba5b73SBruno Randolf break; 5261bba5b73SBruno Randolf default: 5271bba5b73SBruno Randolf idx = key->keyidx; 5281bba5b73SBruno Randolf break; 5291bba5b73SBruno Randolf } 5301bba5b73SBruno Randolf } else if (key->keyidx) { 5311bba5b73SBruno Randolf if (WARN_ON(!sta)) 5321bba5b73SBruno Randolf return -EOPNOTSUPP; 5331bba5b73SBruno Randolf mac = sta->addr; 5341bba5b73SBruno Randolf 5351bba5b73SBruno Randolf if (vif->type != NL80211_IFTYPE_AP) { 5361bba5b73SBruno Randolf /* Only keyidx 0 should be used with unicast key, but 5371bba5b73SBruno Randolf * allow this for client mode for now. */ 5381bba5b73SBruno Randolf idx = key->keyidx; 5391bba5b73SBruno Randolf } else 5401bba5b73SBruno Randolf return -EIO; 5411bba5b73SBruno Randolf } else { 5421bba5b73SBruno Randolf if (WARN_ON(!sta)) 5431bba5b73SBruno Randolf return -EOPNOTSUPP; 5441bba5b73SBruno Randolf mac = sta->addr; 5451bba5b73SBruno Randolf 5461bba5b73SBruno Randolf idx = ath_reserve_key_cache_slot(common, key->cipher); 5471bba5b73SBruno Randolf } 5481bba5b73SBruno Randolf 5491bba5b73SBruno Randolf if (idx < 0) 5501bba5b73SBruno Randolf return -ENOSPC; /* no free key cache entries */ 5511bba5b73SBruno Randolf 5521bba5b73SBruno Randolf if (key->cipher == WLAN_CIPHER_SUITE_TKIP) 5531bba5b73SBruno Randolf ret = ath_setkey_tkip(common, idx, key->key, &hk, mac, 5541bba5b73SBruno Randolf vif->type == NL80211_IFTYPE_AP); 5551bba5b73SBruno Randolf else 5561bba5b73SBruno Randolf ret = ath_hw_set_keycache_entry(common, idx, &hk, mac); 5571bba5b73SBruno Randolf 5581bba5b73SBruno Randolf if (!ret) 5591bba5b73SBruno Randolf return -EIO; 5601bba5b73SBruno Randolf 5611bba5b73SBruno Randolf set_bit(idx, common->keymap); 562bed3d9c0SFelix Fietkau if (key->cipher == WLAN_CIPHER_SUITE_CCMP) 563bed3d9c0SFelix Fietkau set_bit(idx, common->ccmp_keymap); 564bed3d9c0SFelix Fietkau 5651bba5b73SBruno Randolf if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { 5661bba5b73SBruno Randolf set_bit(idx + 64, common->keymap); 5671bba5b73SBruno Randolf set_bit(idx, common->tkip_keymap); 5681bba5b73SBruno Randolf set_bit(idx + 64, common->tkip_keymap); 569117675d0SBruno Randolf if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { 5701bba5b73SBruno Randolf set_bit(idx + 32, common->keymap); 5711bba5b73SBruno Randolf set_bit(idx + 64 + 32, common->keymap); 5721bba5b73SBruno Randolf set_bit(idx + 32, common->tkip_keymap); 5731bba5b73SBruno Randolf set_bit(idx + 64 + 32, common->tkip_keymap); 5741bba5b73SBruno Randolf } 5751bba5b73SBruno Randolf } 5761bba5b73SBruno Randolf 5771bba5b73SBruno Randolf return idx; 5781bba5b73SBruno Randolf } 5791bba5b73SBruno Randolf EXPORT_SYMBOL(ath_key_config); 5801bba5b73SBruno Randolf 5811bba5b73SBruno Randolf /* 5821bba5b73SBruno Randolf * Delete Key. 5831bba5b73SBruno Randolf */ 584144cd24dSJouni Malinen void ath_key_delete(struct ath_common *common, u8 hw_key_idx) 5851bba5b73SBruno Randolf { 58656c5485cSJouni Malinen /* Leave CCMP and TKIP (main key) configured to avoid disabling 58756c5485cSJouni Malinen * encryption for potentially pending frames already in a TXQ with the 58856c5485cSJouni Malinen * keyix pointing to this key entry. Instead, only clear the MAC address 58956c5485cSJouni Malinen * to prevent RX processing from using this key cache entry. 59056c5485cSJouni Malinen */ 591144cd24dSJouni Malinen if (test_bit(hw_key_idx, common->ccmp_keymap) || 592144cd24dSJouni Malinen test_bit(hw_key_idx, common->tkip_keymap)) 593144cd24dSJouni Malinen ath_hw_keysetmac(common, hw_key_idx, NULL); 59456c5485cSJouni Malinen else 595144cd24dSJouni Malinen ath_hw_keyreset(common, hw_key_idx); 596144cd24dSJouni Malinen if (hw_key_idx < IEEE80211_WEP_NKID) 5971bba5b73SBruno Randolf return; 5981bba5b73SBruno Randolf 599144cd24dSJouni Malinen clear_bit(hw_key_idx, common->keymap); 600144cd24dSJouni Malinen clear_bit(hw_key_idx, common->ccmp_keymap); 601144cd24dSJouni Malinen if (!test_bit(hw_key_idx, common->tkip_keymap)) 6021bba5b73SBruno Randolf return; 6031bba5b73SBruno Randolf 604144cd24dSJouni Malinen clear_bit(hw_key_idx + 64, common->keymap); 6051bba5b73SBruno Randolf 606144cd24dSJouni Malinen clear_bit(hw_key_idx, common->tkip_keymap); 607144cd24dSJouni Malinen clear_bit(hw_key_idx + 64, common->tkip_keymap); 6081bba5b73SBruno Randolf 609117675d0SBruno Randolf if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { 610144cd24dSJouni Malinen ath_hw_keyreset(common, hw_key_idx + 32); 611144cd24dSJouni Malinen clear_bit(hw_key_idx + 32, common->keymap); 612144cd24dSJouni Malinen clear_bit(hw_key_idx + 64 + 32, common->keymap); 6131bba5b73SBruno Randolf 614144cd24dSJouni Malinen clear_bit(hw_key_idx + 32, common->tkip_keymap); 615144cd24dSJouni Malinen clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap); 6161bba5b73SBruno Randolf } 6171bba5b73SBruno Randolf } 6181bba5b73SBruno Randolf EXPORT_SYMBOL(ath_key_delete); 619