18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2009 Atheros Communications Inc. 38c2ecf20Sopenharmony_ci * Copyright (c) 2010 Bruno Randolf <br1@einfach.org> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 68c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 78c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 108c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 118c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 128c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 138c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 158c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/export.h> 198c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 208c2ecf20Sopenharmony_ci#include <net/mac80211.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "ath.h" 238c2ecf20Sopenharmony_ci#include "reg.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define REG_READ (common->ops->read) 268c2ecf20Sopenharmony_ci#define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) 278c2ecf20Sopenharmony_ci#define ENABLE_REGWRITE_BUFFER(_ah) \ 288c2ecf20Sopenharmony_ci if (common->ops->enable_write_buffer) \ 298c2ecf20Sopenharmony_ci common->ops->enable_write_buffer((_ah)); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define REGWRITE_BUFFER_FLUSH(_ah) \ 328c2ecf20Sopenharmony_ci if (common->ops->write_flush) \ 338c2ecf20Sopenharmony_ci common->ops->write_flush((_ah)); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define IEEE80211_WEP_NKID 4 /* number of key ids */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/************************/ 398c2ecf20Sopenharmony_ci/* Key Cache Management */ 408c2ecf20Sopenharmony_ci/************************/ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cibool ath_hw_keyreset(struct ath_common *common, u16 entry) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci u32 keyType; 458c2ecf20Sopenharmony_ci void *ah = common->ah; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (entry >= common->keymax) { 488c2ecf20Sopenharmony_ci ath_err(common, "keyreset: keycache entry %u out of range\n", 498c2ecf20Sopenharmony_ci entry); 508c2ecf20Sopenharmony_ci return false; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci ENABLE_REGWRITE_BUFFER(ah); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); 588c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); 598c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); 608c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); 618c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); 628c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); 638c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); 648c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (keyType == AR_KEYTABLE_TYPE_TKIP) { 678c2ecf20Sopenharmony_ci u16 micentry = entry + 64; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); 708c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); 718c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); 728c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); 738c2ecf20Sopenharmony_ci if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { 748c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); 758c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), 768c2ecf20Sopenharmony_ci AR_KEYTABLE_TYPE_CLR); 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci REGWRITE_BUFFER_FLUSH(ah); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return true; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_hw_keyreset); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cibool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci u32 macHi, macLo; 908c2ecf20Sopenharmony_ci u32 unicast_flag = AR_KEYTABLE_VALID; 918c2ecf20Sopenharmony_ci void *ah = common->ah; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (entry >= common->keymax) { 948c2ecf20Sopenharmony_ci ath_err(common, "keysetmac: keycache entry %u out of range\n", 958c2ecf20Sopenharmony_ci entry); 968c2ecf20Sopenharmony_ci return false; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (mac != NULL) { 1008c2ecf20Sopenharmony_ci /* 1018c2ecf20Sopenharmony_ci * AR_KEYTABLE_VALID indicates that the address is a unicast 1028c2ecf20Sopenharmony_ci * address, which must match the transmitter address for 1038c2ecf20Sopenharmony_ci * decrypting frames. 1048c2ecf20Sopenharmony_ci * Not setting this bit allows the hardware to use the key 1058c2ecf20Sopenharmony_ci * for multicast frame decryption. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci if (mac[0] & 0x01) 1088c2ecf20Sopenharmony_ci unicast_flag = 0; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci macLo = get_unaligned_le32(mac); 1118c2ecf20Sopenharmony_ci macHi = get_unaligned_le16(mac + 4); 1128c2ecf20Sopenharmony_ci macLo >>= 1; 1138c2ecf20Sopenharmony_ci macLo |= (macHi & 1) << 31; 1148c2ecf20Sopenharmony_ci macHi >>= 1; 1158c2ecf20Sopenharmony_ci } else { 1168c2ecf20Sopenharmony_ci macLo = macHi = 0; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci ENABLE_REGWRITE_BUFFER(ah); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); 1218c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci REGWRITE_BUFFER_FLUSH(ah); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return true; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_hw_keysetmac); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, 1308c2ecf20Sopenharmony_ci const struct ath_keyval *k, 1318c2ecf20Sopenharmony_ci const u8 *mac) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci void *ah = common->ah; 1348c2ecf20Sopenharmony_ci u32 key0, key1, key2, key3, key4; 1358c2ecf20Sopenharmony_ci u32 keyType; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (entry >= common->keymax) { 1388c2ecf20Sopenharmony_ci ath_err(common, "set-entry: keycache entry %u out of range\n", 1398c2ecf20Sopenharmony_ci entry); 1408c2ecf20Sopenharmony_ci return false; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci switch (k->kv_type) { 1448c2ecf20Sopenharmony_ci case ATH_CIPHER_AES_OCB: 1458c2ecf20Sopenharmony_ci keyType = AR_KEYTABLE_TYPE_AES; 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case ATH_CIPHER_AES_CCM: 1488c2ecf20Sopenharmony_ci if (!(common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)) { 1498c2ecf20Sopenharmony_ci ath_dbg(common, ANY, 1508c2ecf20Sopenharmony_ci "AES-CCM not supported by this mac rev\n"); 1518c2ecf20Sopenharmony_ci return false; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci keyType = AR_KEYTABLE_TYPE_CCM; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case ATH_CIPHER_TKIP: 1568c2ecf20Sopenharmony_ci keyType = AR_KEYTABLE_TYPE_TKIP; 1578c2ecf20Sopenharmony_ci if (entry + 64 >= common->keymax) { 1588c2ecf20Sopenharmony_ci ath_dbg(common, ANY, 1598c2ecf20Sopenharmony_ci "entry %u inappropriate for TKIP\n", entry); 1608c2ecf20Sopenharmony_ci return false; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci case ATH_CIPHER_WEP: 1648c2ecf20Sopenharmony_ci if (k->kv_len < WLAN_KEY_LEN_WEP40) { 1658c2ecf20Sopenharmony_ci ath_dbg(common, ANY, "WEP key length %u too small\n", 1668c2ecf20Sopenharmony_ci k->kv_len); 1678c2ecf20Sopenharmony_ci return false; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci if (k->kv_len <= WLAN_KEY_LEN_WEP40) 1708c2ecf20Sopenharmony_ci keyType = AR_KEYTABLE_TYPE_40; 1718c2ecf20Sopenharmony_ci else if (k->kv_len <= WLAN_KEY_LEN_WEP104) 1728c2ecf20Sopenharmony_ci keyType = AR_KEYTABLE_TYPE_104; 1738c2ecf20Sopenharmony_ci else 1748c2ecf20Sopenharmony_ci keyType = AR_KEYTABLE_TYPE_128; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci case ATH_CIPHER_CLR: 1778c2ecf20Sopenharmony_ci keyType = AR_KEYTABLE_TYPE_CLR; 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci default: 1808c2ecf20Sopenharmony_ci ath_err(common, "cipher %u not supported\n", k->kv_type); 1818c2ecf20Sopenharmony_ci return false; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci key0 = get_unaligned_le32(k->kv_val + 0); 1858c2ecf20Sopenharmony_ci key1 = get_unaligned_le16(k->kv_val + 4); 1868c2ecf20Sopenharmony_ci key2 = get_unaligned_le32(k->kv_val + 6); 1878c2ecf20Sopenharmony_ci key3 = get_unaligned_le16(k->kv_val + 10); 1888c2ecf20Sopenharmony_ci key4 = get_unaligned_le32(k->kv_val + 12); 1898c2ecf20Sopenharmony_ci if (k->kv_len <= WLAN_KEY_LEN_WEP104) 1908c2ecf20Sopenharmony_ci key4 &= 0xff; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* 1938c2ecf20Sopenharmony_ci * Note: Key cache registers access special memory area that requires 1948c2ecf20Sopenharmony_ci * two 32-bit writes to actually update the values in the internal 1958c2ecf20Sopenharmony_ci * memory. Consequently, the exact order and pairs used here must be 1968c2ecf20Sopenharmony_ci * maintained. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (keyType == AR_KEYTABLE_TYPE_TKIP) { 2008c2ecf20Sopenharmony_ci u16 micentry = entry + 64; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * Write inverted key[47:0] first to avoid Michael MIC errors 2048c2ecf20Sopenharmony_ci * on frames that could be sent or received at the same time. 2058c2ecf20Sopenharmony_ci * The correct key will be written in the end once everything 2068c2ecf20Sopenharmony_ci * else is ready. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); 2098c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* Write key[95:48] */ 2128c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); 2138c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Write key[127:96] and key type */ 2168c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); 2178c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Write MAC address for the entry */ 2208c2ecf20Sopenharmony_ci (void) ath_hw_keysetmac(common, entry, mac); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { 2238c2ecf20Sopenharmony_ci /* 2248c2ecf20Sopenharmony_ci * TKIP uses two key cache entries: 2258c2ecf20Sopenharmony_ci * Michael MIC TX/RX keys in the same key cache entry 2268c2ecf20Sopenharmony_ci * (idx = main index + 64): 2278c2ecf20Sopenharmony_ci * key0 [31:0] = RX key [31:0] 2288c2ecf20Sopenharmony_ci * key1 [15:0] = TX key [31:16] 2298c2ecf20Sopenharmony_ci * key1 [31:16] = reserved 2308c2ecf20Sopenharmony_ci * key2 [31:0] = RX key [63:32] 2318c2ecf20Sopenharmony_ci * key3 [15:0] = TX key [15:0] 2328c2ecf20Sopenharmony_ci * key3 [31:16] = reserved 2338c2ecf20Sopenharmony_ci * key4 [31:0] = TX key [63:32] 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci u32 mic0, mic1, mic2, mic3, mic4; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci mic0 = get_unaligned_le32(k->kv_mic + 0); 2388c2ecf20Sopenharmony_ci mic2 = get_unaligned_le32(k->kv_mic + 4); 2398c2ecf20Sopenharmony_ci mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; 2408c2ecf20Sopenharmony_ci mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; 2418c2ecf20Sopenharmony_ci mic4 = get_unaligned_le32(k->kv_txmic + 4); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci ENABLE_REGWRITE_BUFFER(ah); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Write RX[31:0] and TX[31:16] */ 2468c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); 2478c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* Write RX[63:32] and TX[15:0] */ 2508c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); 2518c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* Write TX[63:32] and keyType(reserved) */ 2548c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); 2558c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), 2568c2ecf20Sopenharmony_ci AR_KEYTABLE_TYPE_CLR); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci REGWRITE_BUFFER_FLUSH(ah); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci } else { 2618c2ecf20Sopenharmony_ci /* 2628c2ecf20Sopenharmony_ci * TKIP uses four key cache entries (two for group 2638c2ecf20Sopenharmony_ci * keys): 2648c2ecf20Sopenharmony_ci * Michael MIC TX/RX keys are in different key cache 2658c2ecf20Sopenharmony_ci * entries (idx = main index + 64 for TX and 2668c2ecf20Sopenharmony_ci * main index + 32 + 96 for RX): 2678c2ecf20Sopenharmony_ci * key0 [31:0] = TX/RX MIC key [31:0] 2688c2ecf20Sopenharmony_ci * key1 [31:0] = reserved 2698c2ecf20Sopenharmony_ci * key2 [31:0] = TX/RX MIC key [63:32] 2708c2ecf20Sopenharmony_ci * key3 [31:0] = reserved 2718c2ecf20Sopenharmony_ci * key4 [31:0] = reserved 2728c2ecf20Sopenharmony_ci * 2738c2ecf20Sopenharmony_ci * Upper layer code will call this function separately 2748c2ecf20Sopenharmony_ci * for TX and RX keys when these registers offsets are 2758c2ecf20Sopenharmony_ci * used. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci u32 mic0, mic2; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci mic0 = get_unaligned_le32(k->kv_mic + 0); 2808c2ecf20Sopenharmony_ci mic2 = get_unaligned_le32(k->kv_mic + 4); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci ENABLE_REGWRITE_BUFFER(ah); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Write MIC key[31:0] */ 2858c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); 2868c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Write MIC key[63:32] */ 2898c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); 2908c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Write TX[63:32] and keyType(reserved) */ 2938c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); 2948c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), 2958c2ecf20Sopenharmony_ci AR_KEYTABLE_TYPE_CLR); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci REGWRITE_BUFFER_FLUSH(ah); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ENABLE_REGWRITE_BUFFER(ah); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* MAC address registers are reserved for the MIC entry */ 3038c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); 3048c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * Write the correct (un-inverted) key[47:0] last to enable 3088c2ecf20Sopenharmony_ci * TKIP now that all other registers are set with correct 3098c2ecf20Sopenharmony_ci * values. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); 3128c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci REGWRITE_BUFFER_FLUSH(ah); 3158c2ecf20Sopenharmony_ci } else { 3168c2ecf20Sopenharmony_ci ENABLE_REGWRITE_BUFFER(ah); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* Write key[47:0] */ 3198c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); 3208c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* Write key[95:48] */ 3238c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); 3248c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Write key[127:96] and key type */ 3278c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); 3288c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci REGWRITE_BUFFER_FLUSH(ah); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Write MAC address for the entry */ 3338c2ecf20Sopenharmony_ci (void) ath_hw_keysetmac(common, entry, mac); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return true; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, 3408c2ecf20Sopenharmony_ci struct ath_keyval *hk, const u8 *addr, 3418c2ecf20Sopenharmony_ci bool authenticator) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci const u8 *key_rxmic; 3448c2ecf20Sopenharmony_ci const u8 *key_txmic; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; 3478c2ecf20Sopenharmony_ci key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (addr == NULL) { 3508c2ecf20Sopenharmony_ci /* 3518c2ecf20Sopenharmony_ci * Group key installation - only two key cache entries are used 3528c2ecf20Sopenharmony_ci * regardless of splitmic capability since group key is only 3538c2ecf20Sopenharmony_ci * used either for TX or RX. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci if (authenticator) { 3568c2ecf20Sopenharmony_ci memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); 3578c2ecf20Sopenharmony_ci memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); 3588c2ecf20Sopenharmony_ci } else { 3598c2ecf20Sopenharmony_ci memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); 3608c2ecf20Sopenharmony_ci memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci return ath_hw_set_keycache_entry(common, keyix, hk, addr); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { 3658c2ecf20Sopenharmony_ci /* TX and RX keys share the same key cache entry. */ 3668c2ecf20Sopenharmony_ci memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); 3678c2ecf20Sopenharmony_ci memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); 3688c2ecf20Sopenharmony_ci return ath_hw_set_keycache_entry(common, keyix, hk, addr); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* Separate key cache entries for TX and RX */ 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* TX key goes at first index, RX key at +32. */ 3748c2ecf20Sopenharmony_ci memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); 3758c2ecf20Sopenharmony_ci if (!ath_hw_set_keycache_entry(common, keyix, hk, NULL)) { 3768c2ecf20Sopenharmony_ci /* TX MIC entry failed. No need to proceed further */ 3778c2ecf20Sopenharmony_ci ath_err(common, "Setting TX MIC Key Failed\n"); 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); 3828c2ecf20Sopenharmony_ci /* XXX delete tx key on failure? */ 3838c2ecf20Sopenharmony_ci return ath_hw_set_keycache_entry(common, keyix + 32, hk, addr); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int ath_reserve_key_cache_slot_tkip(struct ath_common *common) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci int i; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { 3918c2ecf20Sopenharmony_ci if (test_bit(i, common->keymap) || 3928c2ecf20Sopenharmony_ci test_bit(i + 64, common->keymap)) 3938c2ecf20Sopenharmony_ci continue; /* At least one part of TKIP key allocated */ 3948c2ecf20Sopenharmony_ci if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) && 3958c2ecf20Sopenharmony_ci (test_bit(i + 32, common->keymap) || 3968c2ecf20Sopenharmony_ci test_bit(i + 64 + 32, common->keymap))) 3978c2ecf20Sopenharmony_ci continue; /* At least one part of TKIP key allocated */ 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Found a free slot for a TKIP key */ 4008c2ecf20Sopenharmony_ci return i; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci return -1; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int ath_reserve_key_cache_slot(struct ath_common *common, 4068c2ecf20Sopenharmony_ci u32 cipher) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci int i; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (cipher == WLAN_CIPHER_SUITE_TKIP) 4118c2ecf20Sopenharmony_ci return ath_reserve_key_cache_slot_tkip(common); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* First, try to find slots that would not be available for TKIP. */ 4148c2ecf20Sopenharmony_ci if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { 4158c2ecf20Sopenharmony_ci for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { 4168c2ecf20Sopenharmony_ci if (!test_bit(i, common->keymap) && 4178c2ecf20Sopenharmony_ci (test_bit(i + 32, common->keymap) || 4188c2ecf20Sopenharmony_ci test_bit(i + 64, common->keymap) || 4198c2ecf20Sopenharmony_ci test_bit(i + 64 + 32, common->keymap))) 4208c2ecf20Sopenharmony_ci return i; 4218c2ecf20Sopenharmony_ci if (!test_bit(i + 32, common->keymap) && 4228c2ecf20Sopenharmony_ci (test_bit(i, common->keymap) || 4238c2ecf20Sopenharmony_ci test_bit(i + 64, common->keymap) || 4248c2ecf20Sopenharmony_ci test_bit(i + 64 + 32, common->keymap))) 4258c2ecf20Sopenharmony_ci return i + 32; 4268c2ecf20Sopenharmony_ci if (!test_bit(i + 64, common->keymap) && 4278c2ecf20Sopenharmony_ci (test_bit(i , common->keymap) || 4288c2ecf20Sopenharmony_ci test_bit(i + 32, common->keymap) || 4298c2ecf20Sopenharmony_ci test_bit(i + 64 + 32, common->keymap))) 4308c2ecf20Sopenharmony_ci return i + 64; 4318c2ecf20Sopenharmony_ci if (!test_bit(i + 64 + 32, common->keymap) && 4328c2ecf20Sopenharmony_ci (test_bit(i, common->keymap) || 4338c2ecf20Sopenharmony_ci test_bit(i + 32, common->keymap) || 4348c2ecf20Sopenharmony_ci test_bit(i + 64, common->keymap))) 4358c2ecf20Sopenharmony_ci return i + 64 + 32; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci } else { 4388c2ecf20Sopenharmony_ci for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { 4398c2ecf20Sopenharmony_ci if (!test_bit(i, common->keymap) && 4408c2ecf20Sopenharmony_ci test_bit(i + 64, common->keymap)) 4418c2ecf20Sopenharmony_ci return i; 4428c2ecf20Sopenharmony_ci if (test_bit(i, common->keymap) && 4438c2ecf20Sopenharmony_ci !test_bit(i + 64, common->keymap)) 4448c2ecf20Sopenharmony_ci return i + 64; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* No partially used TKIP slots, pick any available slot */ 4498c2ecf20Sopenharmony_ci for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { 4508c2ecf20Sopenharmony_ci /* Do not allow slots that could be needed for TKIP group keys 4518c2ecf20Sopenharmony_ci * to be used. This limitation could be removed if we know that 4528c2ecf20Sopenharmony_ci * TKIP will not be used. */ 4538c2ecf20Sopenharmony_ci if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) 4548c2ecf20Sopenharmony_ci continue; 4558c2ecf20Sopenharmony_ci if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { 4568c2ecf20Sopenharmony_ci if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) 4578c2ecf20Sopenharmony_ci continue; 4588c2ecf20Sopenharmony_ci if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) 4598c2ecf20Sopenharmony_ci continue; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (!test_bit(i, common->keymap)) 4638c2ecf20Sopenharmony_ci return i; /* Found a free slot for a key */ 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* No free slot found */ 4678c2ecf20Sopenharmony_ci return -1; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci/* 4718c2ecf20Sopenharmony_ci * Configure encryption in the HW. 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ciint ath_key_config(struct ath_common *common, 4748c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 4758c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 4768c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct ath_keyval hk; 4798c2ecf20Sopenharmony_ci const u8 *mac = NULL; 4808c2ecf20Sopenharmony_ci u8 gmac[ETH_ALEN]; 4818c2ecf20Sopenharmony_ci int ret = 0; 4828c2ecf20Sopenharmony_ci int idx; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci memset(&hk, 0, sizeof(hk)); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci switch (key->cipher) { 4878c2ecf20Sopenharmony_ci case 0: 4888c2ecf20Sopenharmony_ci hk.kv_type = ATH_CIPHER_CLR; 4898c2ecf20Sopenharmony_ci break; 4908c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 4918c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 4928c2ecf20Sopenharmony_ci hk.kv_type = ATH_CIPHER_WEP; 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 4958c2ecf20Sopenharmony_ci hk.kv_type = ATH_CIPHER_TKIP; 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 4988c2ecf20Sopenharmony_ci hk.kv_type = ATH_CIPHER_AES_CCM; 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci default: 5018c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci hk.kv_len = key->keylen; 5058c2ecf20Sopenharmony_ci if (key->keylen) 5068c2ecf20Sopenharmony_ci memcpy(&hk.kv_values, key->key, key->keylen); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { 5098c2ecf20Sopenharmony_ci switch (vif->type) { 5108c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 5118c2ecf20Sopenharmony_ci memcpy(gmac, vif->addr, ETH_ALEN); 5128c2ecf20Sopenharmony_ci gmac[0] |= 0x01; 5138c2ecf20Sopenharmony_ci mac = gmac; 5148c2ecf20Sopenharmony_ci idx = ath_reserve_key_cache_slot(common, key->cipher); 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 5178c2ecf20Sopenharmony_ci if (!sta) { 5188c2ecf20Sopenharmony_ci idx = key->keyidx; 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci memcpy(gmac, sta->addr, ETH_ALEN); 5228c2ecf20Sopenharmony_ci gmac[0] |= 0x01; 5238c2ecf20Sopenharmony_ci mac = gmac; 5248c2ecf20Sopenharmony_ci idx = ath_reserve_key_cache_slot(common, key->cipher); 5258c2ecf20Sopenharmony_ci break; 5268c2ecf20Sopenharmony_ci default: 5278c2ecf20Sopenharmony_ci idx = key->keyidx; 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci } else if (key->keyidx) { 5318c2ecf20Sopenharmony_ci if (WARN_ON(!sta)) 5328c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5338c2ecf20Sopenharmony_ci mac = sta->addr; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP) { 5368c2ecf20Sopenharmony_ci /* Only keyidx 0 should be used with unicast key, but 5378c2ecf20Sopenharmony_ci * allow this for client mode for now. */ 5388c2ecf20Sopenharmony_ci idx = key->keyidx; 5398c2ecf20Sopenharmony_ci } else 5408c2ecf20Sopenharmony_ci return -EIO; 5418c2ecf20Sopenharmony_ci } else { 5428c2ecf20Sopenharmony_ci if (WARN_ON(!sta)) 5438c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5448c2ecf20Sopenharmony_ci mac = sta->addr; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci idx = ath_reserve_key_cache_slot(common, key->cipher); 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (idx < 0) 5508c2ecf20Sopenharmony_ci return -ENOSPC; /* no free key cache entries */ 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_TKIP) 5538c2ecf20Sopenharmony_ci ret = ath_setkey_tkip(common, idx, key->key, &hk, mac, 5548c2ecf20Sopenharmony_ci vif->type == NL80211_IFTYPE_AP); 5558c2ecf20Sopenharmony_ci else 5568c2ecf20Sopenharmony_ci ret = ath_hw_set_keycache_entry(common, idx, &hk, mac); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (!ret) 5598c2ecf20Sopenharmony_ci return -EIO; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci set_bit(idx, common->keymap); 5628c2ecf20Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_CCMP) 5638c2ecf20Sopenharmony_ci set_bit(idx, common->ccmp_keymap); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { 5668c2ecf20Sopenharmony_ci set_bit(idx + 64, common->keymap); 5678c2ecf20Sopenharmony_ci set_bit(idx, common->tkip_keymap); 5688c2ecf20Sopenharmony_ci set_bit(idx + 64, common->tkip_keymap); 5698c2ecf20Sopenharmony_ci if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { 5708c2ecf20Sopenharmony_ci set_bit(idx + 32, common->keymap); 5718c2ecf20Sopenharmony_ci set_bit(idx + 64 + 32, common->keymap); 5728c2ecf20Sopenharmony_ci set_bit(idx + 32, common->tkip_keymap); 5738c2ecf20Sopenharmony_ci set_bit(idx + 64 + 32, common->tkip_keymap); 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return idx; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_key_config); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci/* 5828c2ecf20Sopenharmony_ci * Delete Key. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_civoid ath_key_delete(struct ath_common *common, u8 hw_key_idx) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci /* Leave CCMP and TKIP (main key) configured to avoid disabling 5878c2ecf20Sopenharmony_ci * encryption for potentially pending frames already in a TXQ with the 5888c2ecf20Sopenharmony_ci * keyix pointing to this key entry. Instead, only clear the MAC address 5898c2ecf20Sopenharmony_ci * to prevent RX processing from using this key cache entry. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci if (test_bit(hw_key_idx, common->ccmp_keymap) || 5928c2ecf20Sopenharmony_ci test_bit(hw_key_idx, common->tkip_keymap)) 5938c2ecf20Sopenharmony_ci ath_hw_keysetmac(common, hw_key_idx, NULL); 5948c2ecf20Sopenharmony_ci else 5958c2ecf20Sopenharmony_ci ath_hw_keyreset(common, hw_key_idx); 5968c2ecf20Sopenharmony_ci if (hw_key_idx < IEEE80211_WEP_NKID) 5978c2ecf20Sopenharmony_ci return; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci clear_bit(hw_key_idx, common->keymap); 6008c2ecf20Sopenharmony_ci clear_bit(hw_key_idx, common->ccmp_keymap); 6018c2ecf20Sopenharmony_ci if (!test_bit(hw_key_idx, common->tkip_keymap)) 6028c2ecf20Sopenharmony_ci return; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci clear_bit(hw_key_idx + 64, common->keymap); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci clear_bit(hw_key_idx, common->tkip_keymap); 6078c2ecf20Sopenharmony_ci clear_bit(hw_key_idx + 64, common->tkip_keymap); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { 6108c2ecf20Sopenharmony_ci ath_hw_keyreset(common, hw_key_idx + 32); 6118c2ecf20Sopenharmony_ci clear_bit(hw_key_idx + 32, common->keymap); 6128c2ecf20Sopenharmony_ci clear_bit(hw_key_idx + 64 + 32, common->keymap); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci clear_bit(hw_key_idx + 32, common->tkip_keymap); 6158c2ecf20Sopenharmony_ci clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap); 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_key_delete); 619