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
ath_hw_keyreset(struct ath_common * common,u16 entry)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
ath_hw_keysetmac(struct ath_common * common,u16 entry,const u8 * mac)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 */
107*4c2964efSRuan Jinjie if (is_multicast_ether_addr(mac))
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
ath_hw_set_keycache_entry(struct ath_common * common,u16 entry,const struct ath_keyval * k,const u8 * mac)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
ath_setkey_tkip(struct ath_common * common,u16 keyix,const u8 * key,struct ath_keyval * hk,const u8 * addr,bool authenticator)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
ath_reserve_key_cache_slot_tkip(struct ath_common * common)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
ath_reserve_key_cache_slot(struct ath_common * common,u32 cipher)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 */
ath_key_config(struct ath_common * common,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key)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)
506bfcc8ba4SKees 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 */
ath_key_delete(struct ath_common * common,u8 hw_key_idx)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