aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Copeland <me@bobcopeland.com>2008-10-29 23:19:14 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-11-10 15:17:33 -0500
commit3f64b435ab76e79bfb3b4d36f043e6f892093b71 (patch)
tree44d68068b59f54e54288d1ccab30783b7c661ffb
parent9ad9a26e7b7b6671a9aefbb1edb2e8a9ed50ee8d (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>
-rw-r--r--drivers/net/wireless/ath5k/base.c5
-rw-r--r--drivers/net/wireless/ath5k/pcu.c64
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