diff options
author | Bob Copeland <me@bobcopeland.com> | 2008-10-29 23:19:14 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-11-10 15:17:33 -0500 |
commit | 3f64b435ab76e79bfb3b4d36f043e6f892093b71 (patch) | |
tree | 44d68068b59f54e54288d1ccab30783b7c661ffb /drivers | |
parent | 9ad9a26e7b7b6671a9aefbb1edb2e8a9ed50ee8d (diff) |
ath5k: update keycache to support TKIP handling
Newer parts have slots at entry+64 for michael mic and can do WPA-TKIP
in hardware. The open-sourced Atheros HAL has code for accessing this
portion so now we know how where to put the key material.
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Acked-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/pcu.c | 64 |
2 files changed, 62 insertions, 7 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 4bf3678529b8..c7ffcbb9062d 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -2983,8 +2983,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
2983 | 2983 | ||
2984 | switch (key->alg) { | 2984 | switch (key->alg) { |
2985 | case ALG_WEP: | 2985 | case ALG_WEP: |
2986 | break; | ||
2987 | case ALG_TKIP: | 2986 | case ALG_TKIP: |
2987 | break; | ||
2988 | case ALG_CCMP: | 2988 | case ALG_CCMP: |
2989 | return -EOPNOTSUPP; | 2989 | return -EOPNOTSUPP; |
2990 | default: | 2990 | default: |
@@ -3003,7 +3003,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3003 | } | 3003 | } |
3004 | __set_bit(key->keyidx, sc->keymap); | 3004 | __set_bit(key->keyidx, sc->keymap); |
3005 | key->hw_key_idx = key->keyidx; | 3005 | key->hw_key_idx = key->keyidx; |
3006 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 3006 | key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | |
3007 | IEEE80211_KEY_FLAG_GENERATE_MMIC); | ||
3007 | break; | 3008 | break; |
3008 | case DISABLE_KEY: | 3009 | case DISABLE_KEY: |
3009 | ath5k_hw_reset_key(sc->ah, key->keyidx); | 3010 | ath5k_hw_reset_key(sc->ah, key->keyidx); |
diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index 9c6698520edc..d7f0c1017bda 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c | |||
@@ -1021,17 +1021,29 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, | |||
1021 | const struct ieee80211_key_conf *key, const u8 *mac) | 1021 | const struct ieee80211_key_conf *key, const u8 *mac) |
1022 | { | 1022 | { |
1023 | unsigned int i; | 1023 | unsigned int i; |
1024 | int keylen; | ||
1024 | __le32 key_v[5] = {}; | 1025 | __le32 key_v[5] = {}; |
1026 | __le32 key0 = 0, key1 = 0; | ||
1027 | __le32 *rxmic, *txmic; | ||
1025 | u32 keytype; | 1028 | u32 keytype; |
1029 | u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; | ||
1030 | bool is_tkip; | ||
1026 | 1031 | ||
1027 | ATH5K_TRACE(ah->ah_sc); | 1032 | ATH5K_TRACE(ah->ah_sc); |
1028 | 1033 | ||
1029 | /* key->keylen comes in from mac80211 in bytes */ | 1034 | is_tkip = (key->alg == ALG_TKIP); |
1035 | |||
1036 | /* | ||
1037 | * key->keylen comes in from mac80211 in bytes. | ||
1038 | * TKIP is 128 bit + 128 bit mic | ||
1039 | */ | ||
1040 | keylen = (is_tkip) ? (128 / 8) : key->keylen; | ||
1030 | 1041 | ||
1031 | if (key->keylen > AR5K_KEYTABLE_SIZE / 8) | 1042 | if (entry > AR5K_KEYTABLE_SIZE || |
1043 | (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) | ||
1032 | return -EOPNOTSUPP; | 1044 | return -EOPNOTSUPP; |
1033 | 1045 | ||
1034 | switch (key->keylen) { | 1046 | switch (keylen) { |
1035 | /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ | 1047 | /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ |
1036 | case 40 / 8: | 1048 | case 40 / 8: |
1037 | memcpy(&key_v[0], key->key, 5); | 1049 | memcpy(&key_v[0], key->key, 5); |
@@ -1045,24 +1057,66 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, | |||
1045 | memcpy(&key_v[4], &key->key[12], 1); | 1057 | memcpy(&key_v[4], &key->key[12], 1); |
1046 | keytype = AR5K_KEYTABLE_TYPE_104; | 1058 | keytype = AR5K_KEYTABLE_TYPE_104; |
1047 | break; | 1059 | break; |
1048 | /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ | 1060 | /* WEP/TKIP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ |
1049 | case 128 / 8: | 1061 | case 128 / 8: |
1050 | memcpy(&key_v[0], &key->key[0], 6); | 1062 | memcpy(&key_v[0], &key->key[0], 6); |
1051 | memcpy(&key_v[2], &key->key[6], 6); | 1063 | memcpy(&key_v[2], &key->key[6], 6); |
1052 | memcpy(&key_v[4], &key->key[12], 4); | 1064 | memcpy(&key_v[4], &key->key[12], 4); |
1053 | keytype = AR5K_KEYTABLE_TYPE_128; | 1065 | keytype = is_tkip ? |
1066 | AR5K_KEYTABLE_TYPE_TKIP : | ||
1067 | AR5K_KEYTABLE_TYPE_128; | ||
1054 | break; | 1068 | break; |
1055 | 1069 | ||
1056 | default: | 1070 | default: |
1057 | return -EINVAL; /* shouldn't happen */ | 1071 | return -EINVAL; /* shouldn't happen */ |
1058 | } | 1072 | } |
1059 | 1073 | ||
1074 | /* intentionally corrupt key until mic is installed */ | ||
1075 | if (is_tkip) { | ||
1076 | key0 = key_v[0] = ~key_v[0]; | ||
1077 | key1 = key_v[1] = ~key_v[1]; | ||
1078 | } | ||
1079 | |||
1060 | for (i = 0; i < ARRAY_SIZE(key_v); i++) | 1080 | for (i = 0; i < ARRAY_SIZE(key_v); i++) |
1061 | ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), | 1081 | ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), |
1062 | AR5K_KEYTABLE_OFF(entry, i)); | 1082 | AR5K_KEYTABLE_OFF(entry, i)); |
1063 | 1083 | ||
1064 | ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); | 1084 | ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); |
1065 | 1085 | ||
1086 | if (is_tkip) { | ||
1087 | /* Install rx/tx MIC */ | ||
1088 | rxmic = (__le32 *) &key->key[16]; | ||
1089 | txmic = (__le32 *) &key->key[24]; | ||
1090 | #if 0 | ||
1091 | /* MISC_MODE register & 0x04 - for mac srev >= griffin */ | ||
1092 | key_v[0] = rxmic[0]; | ||
1093 | key_v[1] = (txmic[0] >> 16) & 0xffff; | ||
1094 | key_v[2] = rxmic[1]; | ||
1095 | key_v[3] = txmic[0] & 0xffff; | ||
1096 | key_v[4] = txmic[1]; | ||
1097 | #else | ||
1098 | key_v[0] = rxmic[0]; | ||
1099 | key_v[1] = 0; | ||
1100 | key_v[2] = rxmic[1]; | ||
1101 | key_v[3] = 0; | ||
1102 | key_v[4] = 0; | ||
1103 | #endif | ||
1104 | for (i = 0; i < ARRAY_SIZE(key_v); i++) | ||
1105 | ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), | ||
1106 | AR5K_KEYTABLE_OFF(micentry, i)); | ||
1107 | |||
1108 | ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, | ||
1109 | AR5K_KEYTABLE_TYPE(micentry)); | ||
1110 | ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry)); | ||
1111 | ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry)); | ||
1112 | |||
1113 | /* restore first 2 words of key */ | ||
1114 | ath5k_hw_reg_write(ah, le32_to_cpu(~key0), | ||
1115 | AR5K_KEYTABLE_OFF(entry, 0)); | ||
1116 | ath5k_hw_reg_write(ah, le32_to_cpu(~key1), | ||
1117 | AR5K_KEYTABLE_OFF(entry, 1)); | ||
1118 | } | ||
1119 | |||
1066 | return ath5k_hw_set_key_lladdr(ah, entry, mac); | 1120 | return ath5k_hw_set_key_lladdr(ah, entry, mac); |
1067 | } | 1121 | } |
1068 | 1122 | ||