Commit 672903b3 authored by Jouni Malinen's avatar Jouni Malinen Committed by John W. Linville

ath9k: Document keycache operations

There are number of small details about the keycache operations that
are very easy to miss (and forget), so better include detailed
comments in ath9k_hw_set_keycache_entry() to avoid having to figure
out this every time when having to touch this area.
Signed-off-by: default avatarJouni Malinen <jouni.malinen@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e65c2263
...@@ -2482,18 +2482,49 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, ...@@ -2482,18 +2482,49 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
if (k->kv_len <= LEN_WEP104) if (k->kv_len <= LEN_WEP104)
key4 &= 0xff; key4 &= 0xff;
/*
* Note: Key cache registers access special memory area that requires
* two 32-bit writes to actually update the values in the internal
* memory. Consequently, the exact order and pairs used here must be
* maintained.
*/
if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
u16 micentry = entry + 64; u16 micentry = entry + 64;
/*
* Write inverted key[47:0] first to avoid Michael MIC errors
* on frames that could be sent or received at the same time.
* The correct key will be written in the end once everything
* else is ready.
*/
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
/* Write key[95:48] */
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
/* Write key[127:96] and key type */
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
/* Write MAC address for the entry */
(void) ath9k_hw_keysetmac(ah, entry, mac); (void) ath9k_hw_keysetmac(ah, entry, mac);
if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) { if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) {
/*
* TKIP uses two key cache entries:
* Michael MIC TX/RX keys in the same key cache entry
* (idx = main index + 64):
* key0 [31:0] = RX key [31:0]
* key1 [15:0] = TX key [31:16]
* key1 [31:16] = reserved
* key2 [31:0] = RX key [63:32]
* key3 [15:0] = TX key [15:0]
* key3 [31:16] = reserved
* key4 [31:0] = TX key [63:32]
*/
u32 mic0, mic1, mic2, mic3, mic4; u32 mic0, mic1, mic2, mic3, mic4;
mic0 = get_unaligned_le32(k->kv_mic + 0); mic0 = get_unaligned_le32(k->kv_mic + 0);
...@@ -2501,45 +2532,84 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, ...@@ -2501,45 +2532,84 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
mic4 = get_unaligned_le32(k->kv_txmic + 4); mic4 = get_unaligned_le32(k->kv_txmic + 4);
/* Write RX[31:0] and TX[31:16] */
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
/* Write RX[63:32] and TX[15:0] */
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
/* Write TX[63:32] and keyType(reserved) */
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
AR_KEYTABLE_TYPE_CLR); AR_KEYTABLE_TYPE_CLR);
} else { } else {
/*
* TKIP uses four key cache entries (two for group
* keys):
* Michael MIC TX/RX keys are in different key cache
* entries (idx = main index + 64 for TX and
* main index + 32 + 96 for RX):
* key0 [31:0] = TX/RX MIC key [31:0]
* key1 [31:0] = reserved
* key2 [31:0] = TX/RX MIC key [63:32]
* key3 [31:0] = reserved
* key4 [31:0] = reserved
*
* Upper layer code will call this function separately
* for TX and RX keys when these registers offsets are
* used.
*/
u32 mic0, mic2; u32 mic0, mic2;
mic0 = get_unaligned_le32(k->kv_mic + 0); mic0 = get_unaligned_le32(k->kv_mic + 0);
mic2 = get_unaligned_le32(k->kv_mic + 4); mic2 = get_unaligned_le32(k->kv_mic + 4);
/* Write MIC key[31:0] */
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
/* Write MIC key[63:32] */
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
/* Write TX[63:32] and keyType(reserved) */
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
AR_KEYTABLE_TYPE_CLR); AR_KEYTABLE_TYPE_CLR);
} }
/* MAC address registers are reserved for the MIC entry */
REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
/*
* Write the correct (un-inverted) key[47:0] last to enable
* TKIP now that all other registers are set with correct
* values.
*/
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
} else { } else {
/* Write key[47:0] */
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
/* Write key[95:48] */
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
/* Write key[127:96] and key type */
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
/* Write MAC address for the entry */
(void) ath9k_hw_keysetmac(ah, entry, mac); (void) ath9k_hw_keysetmac(ah, entry, mac);
} }
if (ah->curchan == NULL)
return true;
return true; return true;
} }
......
...@@ -588,9 +588,11 @@ struct ath9k_keyval { ...@@ -588,9 +588,11 @@ struct ath9k_keyval {
u8 kv_type; u8 kv_type;
u8 kv_pad; u8 kv_pad;
u16 kv_len; u16 kv_len;
u8 kv_val[16]; u8 kv_val[16]; /* TK */
u8 kv_mic[8]; u8 kv_mic[8]; /* Michael MIC key */
u8 kv_txmic[8]; u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
* supports both MIC keys in the same key cache entry;
* in that case, kv_mic is the RX key) */
}; };
enum ath9k_key_type { enum ath9k_key_type {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment