brintos

brintos / linux-shallow public Read only

0
0
Text · 17.3 KiB · 0ae436b Raw
619 lines · c
1/*2 * Copyright (c) 2009 Atheros Communications Inc.3 * Copyright (c) 2010 Bruno Randolf <br1@einfach.org>4 *5 * Permission to use, copy, modify, and/or distribute this software for any6 * purpose with or without fee is hereby granted, provided that the above7 * copyright notice and this permission notice appear in all copies.8 *9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.16 */17 18#include <linux/export.h>19#include <linux/unaligned.h>20#include <net/mac80211.h>21 22#include "ath.h"23#include "reg.h"24 25#define REG_READ			(common->ops->read)26#define REG_WRITE(_ah, _reg, _val)	(common->ops->write)(_ah, _val, _reg)27#define ENABLE_REGWRITE_BUFFER(_ah)			\28	if (common->ops->enable_write_buffer)		\29		common->ops->enable_write_buffer((_ah));30 31#define REGWRITE_BUFFER_FLUSH(_ah)			\32	if (common->ops->write_flush)			\33		common->ops->write_flush((_ah));34 35 36#define IEEE80211_WEP_NKID      4       /* number of key ids */37 38/************************/39/* Key Cache Management */40/************************/41 42bool ath_hw_keyreset(struct ath_common *common, u16 entry)43{44	u32 keyType;45	void *ah = common->ah;46 47	if (entry >= common->keymax) {48		ath_err(common, "keyreset: keycache entry %u out of range\n",49			entry);50		return false;51	}52 53	keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));54 55	ENABLE_REGWRITE_BUFFER(ah);56 57	REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);58	REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);59	REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);60	REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);61	REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);62	REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);63	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);64	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);65 66	if (keyType == AR_KEYTABLE_TYPE_TKIP) {67		u16 micentry = entry + 64;68 69		REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);70		REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);71		REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);72		REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);73		if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {74			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);75			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),76				  AR_KEYTABLE_TYPE_CLR);77		}78 79	}80 81	REGWRITE_BUFFER_FLUSH(ah);82 83	return true;84}85EXPORT_SYMBOL(ath_hw_keyreset);86 87bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)88{89	u32 macHi, macLo;90	u32 unicast_flag = AR_KEYTABLE_VALID;91	void *ah = common->ah;92 93	if (entry >= common->keymax) {94		ath_err(common, "keysetmac: keycache entry %u out of range\n",95			entry);96		return false;97	}98 99	if (mac != NULL) {100		/*101		 * AR_KEYTABLE_VALID indicates that the address is a unicast102		 * address, which must match the transmitter address for103		 * decrypting frames.104		 * Not setting this bit allows the hardware to use the key105		 * for multicast frame decryption.106		 */107		if (is_multicast_ether_addr(mac))108			unicast_flag = 0;109 110		macLo = get_unaligned_le32(mac);111		macHi = get_unaligned_le16(mac + 4);112		macLo >>= 1;113		macLo |= (macHi & 1) << 31;114		macHi >>= 1;115	} else {116		macLo = macHi = 0;117	}118	ENABLE_REGWRITE_BUFFER(ah);119 120	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);121	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);122 123	REGWRITE_BUFFER_FLUSH(ah);124 125	return true;126}127EXPORT_SYMBOL(ath_hw_keysetmac);128 129static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,130				      const struct ath_keyval *k,131				      const u8 *mac)132{133	void *ah = common->ah;134	u32 key0, key1, key2, key3, key4;135	u32 keyType;136 137	if (entry >= common->keymax) {138		ath_err(common, "set-entry: keycache entry %u out of range\n",139			entry);140		return false;141	}142 143	switch (k->kv_type) {144	case ATH_CIPHER_AES_OCB:145		keyType = AR_KEYTABLE_TYPE_AES;146		break;147	case ATH_CIPHER_AES_CCM:148		if (!(common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)) {149			ath_dbg(common, ANY,150				"AES-CCM not supported by this mac rev\n");151			return false;152		}153		keyType = AR_KEYTABLE_TYPE_CCM;154		break;155	case ATH_CIPHER_TKIP:156		keyType = AR_KEYTABLE_TYPE_TKIP;157		if (entry + 64 >= common->keymax) {158			ath_dbg(common, ANY,159				"entry %u inappropriate for TKIP\n", entry);160			return false;161		}162		break;163	case ATH_CIPHER_WEP:164		if (k->kv_len < WLAN_KEY_LEN_WEP40) {165			ath_dbg(common, ANY, "WEP key length %u too small\n",166				k->kv_len);167			return false;168		}169		if (k->kv_len <= WLAN_KEY_LEN_WEP40)170			keyType = AR_KEYTABLE_TYPE_40;171		else if (k->kv_len <= WLAN_KEY_LEN_WEP104)172			keyType = AR_KEYTABLE_TYPE_104;173		else174			keyType = AR_KEYTABLE_TYPE_128;175		break;176	case ATH_CIPHER_CLR:177		keyType = AR_KEYTABLE_TYPE_CLR;178		break;179	default:180		ath_err(common, "cipher %u not supported\n", k->kv_type);181		return false;182	}183 184	key0 = get_unaligned_le32(k->kv_val + 0);185	key1 = get_unaligned_le16(k->kv_val + 4);186	key2 = get_unaligned_le32(k->kv_val + 6);187	key3 = get_unaligned_le16(k->kv_val + 10);188	key4 = get_unaligned_le32(k->kv_val + 12);189	if (k->kv_len <= WLAN_KEY_LEN_WEP104)190		key4 &= 0xff;191 192	/*193	 * Note: Key cache registers access special memory area that requires194	 * two 32-bit writes to actually update the values in the internal195	 * memory. Consequently, the exact order and pairs used here must be196	 * maintained.197	 */198 199	if (keyType == AR_KEYTABLE_TYPE_TKIP) {200		u16 micentry = entry + 64;201 202		/*203		 * Write inverted key[47:0] first to avoid Michael MIC errors204		 * on frames that could be sent or received at the same time.205		 * The correct key will be written in the end once everything206		 * else is ready.207		 */208		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);209		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);210 211		/* Write key[95:48] */212		REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);213		REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);214 215		/* Write key[127:96] and key type */216		REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);217		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);218 219		/* Write MAC address for the entry */220		(void) ath_hw_keysetmac(common, entry, mac);221 222		if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {223			/*224			 * TKIP uses two key cache entries:225			 * Michael MIC TX/RX keys in the same key cache entry226			 * (idx = main index + 64):227			 * key0 [31:0] = RX key [31:0]228			 * key1 [15:0] = TX key [31:16]229			 * key1 [31:16] = reserved230			 * key2 [31:0] = RX key [63:32]231			 * key3 [15:0] = TX key [15:0]232			 * key3 [31:16] = reserved233			 * key4 [31:0] = TX key [63:32]234			 */235			u32 mic0, mic1, mic2, mic3, mic4;236 237			mic0 = get_unaligned_le32(k->kv_mic + 0);238			mic2 = get_unaligned_le32(k->kv_mic + 4);239			mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;240			mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;241			mic4 = get_unaligned_le32(k->kv_txmic + 4);242 243			ENABLE_REGWRITE_BUFFER(ah);244 245			/* Write RX[31:0] and TX[31:16] */246			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);247			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);248 249			/* Write RX[63:32] and TX[15:0] */250			REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);251			REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);252 253			/* Write TX[63:32] and keyType(reserved) */254			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);255			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),256				  AR_KEYTABLE_TYPE_CLR);257 258			REGWRITE_BUFFER_FLUSH(ah);259 260		} else {261			/*262			 * TKIP uses four key cache entries (two for group263			 * keys):264			 * Michael MIC TX/RX keys are in different key cache265			 * entries (idx = main index + 64 for TX and266			 * main index + 32 + 96 for RX):267			 * key0 [31:0] = TX/RX MIC key [31:0]268			 * key1 [31:0] = reserved269			 * key2 [31:0] = TX/RX MIC key [63:32]270			 * key3 [31:0] = reserved271			 * key4 [31:0] = reserved272			 *273			 * Upper layer code will call this function separately274			 * for TX and RX keys when these registers offsets are275			 * used.276			 */277			u32 mic0, mic2;278 279			mic0 = get_unaligned_le32(k->kv_mic + 0);280			mic2 = get_unaligned_le32(k->kv_mic + 4);281 282			ENABLE_REGWRITE_BUFFER(ah);283 284			/* Write MIC key[31:0] */285			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);286			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);287 288			/* Write MIC key[63:32] */289			REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);290			REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);291 292			/* Write TX[63:32] and keyType(reserved) */293			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);294			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),295				  AR_KEYTABLE_TYPE_CLR);296 297			REGWRITE_BUFFER_FLUSH(ah);298		}299 300		ENABLE_REGWRITE_BUFFER(ah);301 302		/* MAC address registers are reserved for the MIC entry */303		REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);304		REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);305 306		/*307		 * Write the correct (un-inverted) key[47:0] last to enable308		 * TKIP now that all other registers are set with correct309		 * values.310		 */311		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);312		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);313 314		REGWRITE_BUFFER_FLUSH(ah);315	} else {316		ENABLE_REGWRITE_BUFFER(ah);317 318		/* Write key[47:0] */319		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);320		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);321 322		/* Write key[95:48] */323		REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);324		REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);325 326		/* Write key[127:96] and key type */327		REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);328		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);329 330		REGWRITE_BUFFER_FLUSH(ah);331 332		/* Write MAC address for the entry */333		(void) ath_hw_keysetmac(common, entry, mac);334	}335 336	return true;337}338 339static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,340			   struct ath_keyval *hk, const u8 *addr,341			   bool authenticator)342{343	const u8 *key_rxmic;344	const u8 *key_txmic;345 346	key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;347	key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;348 349	if (addr == NULL) {350		/*351		 * Group key installation - only two key cache entries are used352		 * regardless of splitmic capability since group key is only353		 * used either for TX or RX.354		 */355		if (authenticator) {356			memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));357			memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));358		} else {359			memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));360			memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));361		}362		return ath_hw_set_keycache_entry(common, keyix, hk, addr);363	}364	if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {365		/* TX and RX keys share the same key cache entry. */366		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));367		memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));368		return ath_hw_set_keycache_entry(common, keyix, hk, addr);369	}370 371	/* Separate key cache entries for TX and RX */372 373	/* TX key goes at first index, RX key at +32. */374	memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));375	if (!ath_hw_set_keycache_entry(common, keyix, hk, NULL)) {376		/* TX MIC entry failed. No need to proceed further */377		ath_err(common, "Setting TX MIC Key Failed\n");378		return 0;379	}380 381	memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));382	/* XXX delete tx key on failure? */383	return ath_hw_set_keycache_entry(common, keyix + 32, hk, addr);384}385 386static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)387{388	int i;389 390	for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {391		if (test_bit(i, common->keymap) ||392		    test_bit(i + 64, common->keymap))393			continue; /* At least one part of TKIP key allocated */394		if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) &&395		    (test_bit(i + 32, common->keymap) ||396		     test_bit(i + 64 + 32, common->keymap)))397			continue; /* At least one part of TKIP key allocated */398 399		/* Found a free slot for a TKIP key */400		return i;401	}402	return -1;403}404 405static int ath_reserve_key_cache_slot(struct ath_common *common,406				      u32 cipher)407{408	int i;409 410	if (cipher == WLAN_CIPHER_SUITE_TKIP)411		return ath_reserve_key_cache_slot_tkip(common);412 413	/* First, try to find slots that would not be available for TKIP. */414	if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {415		for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {416			if (!test_bit(i, common->keymap) &&417			    (test_bit(i + 32, common->keymap) ||418			     test_bit(i + 64, common->keymap) ||419			     test_bit(i + 64 + 32, common->keymap)))420				return i;421			if (!test_bit(i + 32, common->keymap) &&422			    (test_bit(i, common->keymap) ||423			     test_bit(i + 64, common->keymap) ||424			     test_bit(i + 64 + 32, common->keymap)))425				return i + 32;426			if (!test_bit(i + 64, common->keymap) &&427			    (test_bit(i , common->keymap) ||428			     test_bit(i + 32, common->keymap) ||429			     test_bit(i + 64 + 32, common->keymap)))430				return i + 64;431			if (!test_bit(i + 64 + 32, common->keymap) &&432			    (test_bit(i, common->keymap) ||433			     test_bit(i + 32, common->keymap) ||434			     test_bit(i + 64, common->keymap)))435				return i + 64 + 32;436		}437	} else {438		for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {439			if (!test_bit(i, common->keymap) &&440			    test_bit(i + 64, common->keymap))441				return i;442			if (test_bit(i, common->keymap) &&443			    !test_bit(i + 64, common->keymap))444				return i + 64;445		}446	}447 448	/* No partially used TKIP slots, pick any available slot */449	for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {450		/* Do not allow slots that could be needed for TKIP group keys451		 * to be used. This limitation could be removed if we know that452		 * TKIP will not be used. */453		if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)454			continue;455		if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {456			if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)457				continue;458			if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)459				continue;460		}461 462		if (!test_bit(i, common->keymap))463			return i; /* Found a free slot for a key */464	}465 466	/* No free slot found */467	return -1;468}469 470/*471 * Configure encryption in the HW.472 */473int ath_key_config(struct ath_common *common,474			  struct ieee80211_vif *vif,475			  struct ieee80211_sta *sta,476			  struct ieee80211_key_conf *key)477{478	struct ath_keyval hk;479	const u8 *mac = NULL;480	u8 gmac[ETH_ALEN];481	int ret = 0;482	int idx;483 484	memset(&hk, 0, sizeof(hk));485 486	switch (key->cipher) {487	case 0:488		hk.kv_type = ATH_CIPHER_CLR;489		break;490	case WLAN_CIPHER_SUITE_WEP40:491	case WLAN_CIPHER_SUITE_WEP104:492		hk.kv_type = ATH_CIPHER_WEP;493		break;494	case WLAN_CIPHER_SUITE_TKIP:495		hk.kv_type = ATH_CIPHER_TKIP;496		break;497	case WLAN_CIPHER_SUITE_CCMP:498		hk.kv_type = ATH_CIPHER_AES_CCM;499		break;500	default:501		return -EOPNOTSUPP;502	}503 504	hk.kv_len = key->keylen;505	if (key->keylen)506		memcpy(&hk.kv_values, key->key, key->keylen);507 508	if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {509		switch (vif->type) {510		case NL80211_IFTYPE_AP:511			memcpy(gmac, vif->addr, ETH_ALEN);512			gmac[0] |= 0x01;513			mac = gmac;514			idx = ath_reserve_key_cache_slot(common, key->cipher);515			break;516		case NL80211_IFTYPE_ADHOC:517			if (!sta) {518				idx = key->keyidx;519				break;520			}521			memcpy(gmac, sta->addr, ETH_ALEN);522			gmac[0] |= 0x01;523			mac = gmac;524			idx = ath_reserve_key_cache_slot(common, key->cipher);525			break;526		default:527			idx = key->keyidx;528			break;529		}530	} else if (key->keyidx) {531		if (WARN_ON(!sta))532			return -EOPNOTSUPP;533		mac = sta->addr;534 535		if (vif->type != NL80211_IFTYPE_AP) {536			/* Only keyidx 0 should be used with unicast key, but537			 * allow this for client mode for now. */538			idx = key->keyidx;539		} else540			return -EIO;541	} else {542		if (WARN_ON(!sta))543			return -EOPNOTSUPP;544		mac = sta->addr;545 546		idx = ath_reserve_key_cache_slot(common, key->cipher);547	}548 549	if (idx < 0)550		return -ENOSPC; /* no free key cache entries */551 552	if (key->cipher == WLAN_CIPHER_SUITE_TKIP)553		ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,554				      vif->type == NL80211_IFTYPE_AP);555	else556		ret = ath_hw_set_keycache_entry(common, idx, &hk, mac);557 558	if (!ret)559		return -EIO;560 561	set_bit(idx, common->keymap);562	if (key->cipher == WLAN_CIPHER_SUITE_CCMP)563		set_bit(idx, common->ccmp_keymap);564 565	if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {566		set_bit(idx + 64, common->keymap);567		set_bit(idx, common->tkip_keymap);568		set_bit(idx + 64, common->tkip_keymap);569		if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {570			set_bit(idx + 32, common->keymap);571			set_bit(idx + 64 + 32, common->keymap);572			set_bit(idx + 32, common->tkip_keymap);573			set_bit(idx + 64 + 32, common->tkip_keymap);574		}575	}576 577	return idx;578}579EXPORT_SYMBOL(ath_key_config);580 581/*582 * Delete Key.583 */584void ath_key_delete(struct ath_common *common, u8 hw_key_idx)585{586	/* Leave CCMP and TKIP (main key) configured to avoid disabling587	 * encryption for potentially pending frames already in a TXQ with the588	 * keyix pointing to this key entry. Instead, only clear the MAC address589	 * to prevent RX processing from using this key cache entry.590	 */591	if (test_bit(hw_key_idx, common->ccmp_keymap) ||592	    test_bit(hw_key_idx, common->tkip_keymap))593		ath_hw_keysetmac(common, hw_key_idx, NULL);594	else595		ath_hw_keyreset(common, hw_key_idx);596	if (hw_key_idx < IEEE80211_WEP_NKID)597		return;598 599	clear_bit(hw_key_idx, common->keymap);600	clear_bit(hw_key_idx, common->ccmp_keymap);601	if (!test_bit(hw_key_idx, common->tkip_keymap))602		return;603 604	clear_bit(hw_key_idx + 64, common->keymap);605 606	clear_bit(hw_key_idx, common->tkip_keymap);607	clear_bit(hw_key_idx + 64, common->tkip_keymap);608 609	if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {610		ath_hw_keyreset(common, hw_key_idx + 32);611		clear_bit(hw_key_idx + 32, common->keymap);612		clear_bit(hw_key_idx + 64 + 32, common->keymap);613 614		clear_bit(hw_key_idx + 32, common->tkip_keymap);615		clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap);616	}617}618EXPORT_SYMBOL(ath_key_delete);619