xref: /openbmc/linux/drivers/net/wireless/ath/key.c (revision bfcc8ba4)
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