aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-11-12 17:54:48 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-11-24 01:30:16 -0500
commitba3943b094434ac8e2074bd159c2734e8cc47511 (patch)
tree3dd228d5f7a776bd2c0bea3ca82dadf310c93f2c
parent2f6319d1cf5df2bc01637496296d755e3312c030 (diff)
iwlwifi: mvm: add WEP RX hardware offload support
In the original driver, we decided to not implement WEP RX hardware offload because of a quirk with the firmware API - it allows setting global WEP keys that then get used for all virtual interfaces, which is clearly wrong if more than one exists, and it allows setting per- station keys but then separates multicast and unicast keys. In order to implement WEP RX hardware offload, work around these limitations by uploading each WEP key twice, once as multicast and once as unicast, but point them both to the same key slot (offset) and use the same key material so the slot overwrite on the second upload doesn't actually change anything. Upon removal, also remove the key twice so the station no longer references it. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c64
2 files changed, 61 insertions, 17 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index f3379d76f3db..08976c3a4dfc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -2330,12 +2330,16 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
2330 break; 2330 break;
2331 case WLAN_CIPHER_SUITE_WEP40: 2331 case WLAN_CIPHER_SUITE_WEP40:
2332 case WLAN_CIPHER_SUITE_WEP104: 2332 case WLAN_CIPHER_SUITE_WEP104:
2333 /* 2333 /* For non-client mode, only use WEP keys for TX as we probably
2334 * Support for TX only, at least for now, so accept 2334 * don't have a station yet anyway and would then have to keep
2335 * the key and do nothing else. Then mac80211 will 2335 * track of the keys, linking them to each of the clients/peers
2336 * pass it for TX but we don't have to use it for RX. 2336 * as they appear. For now, don't do that, for performance WEP
2337 * offload doesn't really matter much, but we need it for some
2338 * other offload features in client mode.
2337 */ 2339 */
2338 return 0; 2340 if (vif->type != NL80211_IFTYPE_STATION)
2341 return 0;
2342 break;
2339 default: 2343 default:
2340 /* currently FW supports only one optional cipher scheme */ 2344 /* currently FW supports only one optional cipher scheme */
2341 if (hw->n_cipher_schemes && 2345 if (hw->n_cipher_schemes &&
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index f94be3cdeff6..0eb850542af4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -1071,7 +1071,7 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
1071 1071
1072static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, 1072static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
1073 struct iwl_mvm_sta *mvm_sta, 1073 struct iwl_mvm_sta *mvm_sta,
1074 struct ieee80211_key_conf *keyconf, 1074 struct ieee80211_key_conf *keyconf, bool mcast,
1075 u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags) 1075 u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags)
1076{ 1076{
1077 struct iwl_mvm_add_sta_key_cmd cmd = {}; 1077 struct iwl_mvm_add_sta_key_cmd cmd = {};
@@ -1099,12 +1099,18 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
1099 key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); 1099 key_flags |= cpu_to_le16(STA_KEY_FLG_CCM);
1100 memcpy(cmd.key, keyconf->key, keyconf->keylen); 1100 memcpy(cmd.key, keyconf->key, keyconf->keylen);
1101 break; 1101 break;
1102 case WLAN_CIPHER_SUITE_WEP104:
1103 key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_13BYTES);
1104 case WLAN_CIPHER_SUITE_WEP40:
1105 key_flags |= cpu_to_le16(STA_KEY_FLG_WEP);
1106 memcpy(cmd.key + 3, keyconf->key, keyconf->keylen);
1107 break;
1102 default: 1108 default:
1103 key_flags |= cpu_to_le16(STA_KEY_FLG_EXT); 1109 key_flags |= cpu_to_le16(STA_KEY_FLG_EXT);
1104 memcpy(cmd.key, keyconf->key, keyconf->keylen); 1110 memcpy(cmd.key, keyconf->key, keyconf->keylen);
1105 } 1111 }
1106 1112
1107 if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 1113 if (mcast)
1108 key_flags |= cpu_to_le16(STA_KEY_MULTICAST); 1114 key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
1109 1115
1110 cmd.key_offset = keyconf->hw_key_idx; 1116 cmd.key_offset = keyconf->hw_key_idx;
@@ -1199,7 +1205,8 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm,
1199static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, 1205static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
1200 struct ieee80211_vif *vif, 1206 struct ieee80211_vif *vif,
1201 struct ieee80211_sta *sta, 1207 struct ieee80211_sta *sta,
1202 struct ieee80211_key_conf *keyconf) 1208 struct ieee80211_key_conf *keyconf,
1209 bool mcast)
1203{ 1210{
1204 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); 1211 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
1205 int ret; 1212 int ret;
@@ -1213,15 +1220,17 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
1213 /* get phase 1 key from mac80211 */ 1220 /* get phase 1 key from mac80211 */
1214 ieee80211_get_key_rx_seq(keyconf, 0, &seq); 1221 ieee80211_get_key_rx_seq(keyconf, 0, &seq);
1215 ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); 1222 ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
1216 ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, 1223 ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
1217 seq.tkip.iv32, p1k, 0); 1224 seq.tkip.iv32, p1k, 0);
1218 break; 1225 break;
1219 case WLAN_CIPHER_SUITE_CCMP: 1226 case WLAN_CIPHER_SUITE_CCMP:
1220 ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, 1227 case WLAN_CIPHER_SUITE_WEP40:
1228 case WLAN_CIPHER_SUITE_WEP104:
1229 ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
1221 0, NULL, 0); 1230 0, NULL, 0);
1222 break; 1231 break;
1223 default: 1232 default:
1224 ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, 1233 ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
1225 0, NULL, 0); 1234 0, NULL, 0);
1226 } 1235 }
1227 1236
@@ -1229,7 +1238,8 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
1229} 1238}
1230 1239
1231static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, 1240static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,
1232 struct ieee80211_key_conf *keyconf) 1241 struct ieee80211_key_conf *keyconf,
1242 bool mcast)
1233{ 1243{
1234 struct iwl_mvm_add_sta_key_cmd cmd = {}; 1244 struct iwl_mvm_add_sta_key_cmd cmd = {};
1235 __le16 key_flags; 1245 __le16 key_flags;
@@ -1241,7 +1251,7 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,
1241 key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); 1251 key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP);
1242 key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); 1252 key_flags |= cpu_to_le16(STA_KEY_NOT_VALID);
1243 1253
1244 if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 1254 if (mcast)
1245 key_flags |= cpu_to_le16(STA_KEY_MULTICAST); 1255 key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
1246 1256
1247 cmd.key_flags = key_flags; 1257 cmd.key_flags = key_flags;
@@ -1271,6 +1281,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
1271 struct ieee80211_key_conf *keyconf, 1281 struct ieee80211_key_conf *keyconf,
1272 bool have_key_offset) 1282 bool have_key_offset)
1273{ 1283{
1284 bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
1274 u8 sta_id; 1285 u8 sta_id;
1275 int ret; 1286 int ret;
1276 1287
@@ -1315,9 +1326,26 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
1315 return -ENOSPC; 1326 return -ENOSPC;
1316 } 1327 }
1317 1328
1318 ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf); 1329 ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, mcast);
1319 if (ret) 1330 if (ret) {
1320 __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); 1331 __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
1332 goto end;
1333 }
1334
1335 /*
1336 * For WEP, the same key is used for multicast and unicast. Upload it
1337 * again, using the same key offset, and now pointing the other one
1338 * to the same key slot (offset).
1339 * If this fails, remove the original as well.
1340 */
1341 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
1342 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
1343 ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, !mcast);
1344 if (ret) {
1345 __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
1346 __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
1347 }
1348 }
1321 1349
1322end: 1350end:
1323 IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", 1351 IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
@@ -1331,7 +1359,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
1331 struct ieee80211_sta *sta, 1359 struct ieee80211_sta *sta,
1332 struct ieee80211_key_conf *keyconf) 1360 struct ieee80211_key_conf *keyconf)
1333{ 1361{
1362 bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
1334 u8 sta_id; 1363 u8 sta_id;
1364 int ret;
1335 1365
1336 lockdep_assert_held(&mvm->mutex); 1366 lockdep_assert_held(&mvm->mutex);
1337 1367
@@ -1373,7 +1403,16 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
1373 if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) 1403 if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
1374 return -EINVAL; 1404 return -EINVAL;
1375 1405
1376 return __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf); 1406 ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
1407 if (ret)
1408 return ret;
1409
1410 /* delete WEP key twice to get rid of (now useless) offset */
1411 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
1412 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
1413 ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, !mcast);
1414
1415 return ret;
1377} 1416}
1378 1417
1379void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, 1418void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
@@ -1384,6 +1423,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
1384{ 1423{
1385 struct iwl_mvm_sta *mvm_sta; 1424 struct iwl_mvm_sta *mvm_sta;
1386 u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); 1425 u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta);
1426 bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
1387 1427
1388 if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) 1428 if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
1389 return; 1429 return;
@@ -1399,7 +1439,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
1399 } 1439 }
1400 1440
1401 mvm_sta = iwl_mvm_sta_from_mac80211(sta); 1441 mvm_sta = iwl_mvm_sta_from_mac80211(sta);
1402 iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, 1442 iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
1403 iv32, phase1key, CMD_ASYNC); 1443 iv32, phase1key, CMD_ASYNC);
1404 rcu_read_unlock(); 1444 rcu_read_unlock();
1405} 1445}