diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/sta.c | 88 |
1 files changed, 47 insertions, 41 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 300a249486e4..354acbde088e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -1201,7 +1201,8 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) | |||
1201 | return max_offs; | 1201 | return max_offs; |
1202 | } | 1202 | } |
1203 | 1203 | ||
1204 | static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, | 1204 | static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm, |
1205 | struct ieee80211_vif *vif, | ||
1205 | struct ieee80211_sta *sta) | 1206 | struct ieee80211_sta *sta) |
1206 | { | 1207 | { |
1207 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1208 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
@@ -1218,8 +1219,21 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, | |||
1218 | * station ID, then use AP's station ID. | 1219 | * station ID, then use AP's station ID. |
1219 | */ | 1220 | */ |
1220 | if (vif->type == NL80211_IFTYPE_STATION && | 1221 | if (vif->type == NL80211_IFTYPE_STATION && |
1221 | mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) | 1222 | mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
1222 | return mvmvif->ap_sta_id; | 1223 | u8 sta_id = mvmvif->ap_sta_id; |
1224 | |||
1225 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
1226 | lockdep_is_held(&mvm->mutex)); | ||
1227 | /* | ||
1228 | * It is possible that the 'sta' parameter is NULL, | ||
1229 | * for example when a GTK is removed - the sta_id will then | ||
1230 | * be the AP ID, and no station was passed by mac80211. | ||
1231 | */ | ||
1232 | if (IS_ERR_OR_NULL(sta)) | ||
1233 | return IWL_MVM_STATION_COUNT; | ||
1234 | |||
1235 | return sta_id; | ||
1236 | } | ||
1223 | 1237 | ||
1224 | return IWL_MVM_STATION_COUNT; | 1238 | return IWL_MVM_STATION_COUNT; |
1225 | } | 1239 | } |
@@ -1227,7 +1241,8 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, | |||
1227 | static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | 1241 | static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, |
1228 | struct iwl_mvm_sta *mvm_sta, | 1242 | struct iwl_mvm_sta *mvm_sta, |
1229 | struct ieee80211_key_conf *keyconf, bool mcast, | 1243 | struct ieee80211_key_conf *keyconf, bool mcast, |
1230 | u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags) | 1244 | u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags, |
1245 | u8 key_offset) | ||
1231 | { | 1246 | { |
1232 | struct iwl_mvm_add_sta_key_cmd cmd = {}; | 1247 | struct iwl_mvm_add_sta_key_cmd cmd = {}; |
1233 | __le16 key_flags; | 1248 | __le16 key_flags; |
@@ -1269,7 +1284,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | |||
1269 | if (mcast) | 1284 | if (mcast) |
1270 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | 1285 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); |
1271 | 1286 | ||
1272 | cmd.key_offset = keyconf->hw_key_idx; | 1287 | cmd.key_offset = key_offset; |
1273 | cmd.key_flags = key_flags; | 1288 | cmd.key_flags = key_flags; |
1274 | cmd.sta_id = sta_id; | 1289 | cmd.sta_id = sta_id; |
1275 | 1290 | ||
@@ -1360,6 +1375,7 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
1360 | struct ieee80211_vif *vif, | 1375 | struct ieee80211_vif *vif, |
1361 | struct ieee80211_sta *sta, | 1376 | struct ieee80211_sta *sta, |
1362 | struct ieee80211_key_conf *keyconf, | 1377 | struct ieee80211_key_conf *keyconf, |
1378 | u8 key_offset, | ||
1363 | bool mcast) | 1379 | bool mcast) |
1364 | { | 1380 | { |
1365 | struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); | 1381 | struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); |
@@ -1375,17 +1391,17 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
1375 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); | 1391 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); |
1376 | ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); | 1392 | ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); |
1377 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | 1393 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, |
1378 | seq.tkip.iv32, p1k, 0); | 1394 | seq.tkip.iv32, p1k, 0, key_offset); |
1379 | break; | 1395 | break; |
1380 | case WLAN_CIPHER_SUITE_CCMP: | 1396 | case WLAN_CIPHER_SUITE_CCMP: |
1381 | case WLAN_CIPHER_SUITE_WEP40: | 1397 | case WLAN_CIPHER_SUITE_WEP40: |
1382 | case WLAN_CIPHER_SUITE_WEP104: | 1398 | case WLAN_CIPHER_SUITE_WEP104: |
1383 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | 1399 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, |
1384 | 0, NULL, 0); | 1400 | 0, NULL, 0, key_offset); |
1385 | break; | 1401 | break; |
1386 | default: | 1402 | default: |
1387 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | 1403 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, |
1388 | 0, NULL, 0); | 1404 | 0, NULL, 0, key_offset); |
1389 | } | 1405 | } |
1390 | 1406 | ||
1391 | return ret; | 1407 | return ret; |
@@ -1433,7 +1449,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
1433 | struct ieee80211_vif *vif, | 1449 | struct ieee80211_vif *vif, |
1434 | struct ieee80211_sta *sta, | 1450 | struct ieee80211_sta *sta, |
1435 | struct ieee80211_key_conf *keyconf, | 1451 | struct ieee80211_key_conf *keyconf, |
1436 | bool have_key_offset) | 1452 | u8 key_offset) |
1437 | { | 1453 | { |
1438 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); | 1454 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); |
1439 | u8 sta_id; | 1455 | u8 sta_id; |
@@ -1443,7 +1459,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
1443 | lockdep_assert_held(&mvm->mutex); | 1459 | lockdep_assert_held(&mvm->mutex); |
1444 | 1460 | ||
1445 | /* Get the station id from the mvm local station table */ | 1461 | /* Get the station id from the mvm local station table */ |
1446 | sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 1462 | sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta); |
1447 | if (sta_id == IWL_MVM_STATION_COUNT) { | 1463 | if (sta_id == IWL_MVM_STATION_COUNT) { |
1448 | IWL_ERR(mvm, "Failed to find station id\n"); | 1464 | IWL_ERR(mvm, "Failed to find station id\n"); |
1449 | return -EINVAL; | 1465 | return -EINVAL; |
@@ -1470,18 +1486,25 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
1470 | if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) | 1486 | if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) |
1471 | return -EINVAL; | 1487 | return -EINVAL; |
1472 | 1488 | ||
1473 | if (!have_key_offset) { | 1489 | /* If the key_offset is not pre-assigned, we need to find a |
1474 | /* | 1490 | * new offset to use. In normal cases, the offset is not |
1475 | * The D3 firmware hardcodes the PTK offset to 0, so we have to | 1491 | * pre-assigned, but during HW_RESTART we want to reuse the |
1476 | * configure it there. As a result, this workaround exists to | 1492 | * same indices, so we pass them when this function is called. |
1477 | * let the caller set the key offset (hw_key_idx), see d3.c. | 1493 | * |
1478 | */ | 1494 | * In D3 entry, we need to hardcoded the indices (because the |
1479 | keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm); | 1495 | * firmware hardcodes the PTK offset to 0). In this case, we |
1480 | if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID) | 1496 | * need to make sure we don't overwrite the hw_key_idx in the |
1497 | * keyconf structure, because otherwise we cannot configure | ||
1498 | * the original ones back when resuming. | ||
1499 | */ | ||
1500 | if (key_offset == STA_KEY_IDX_INVALID) { | ||
1501 | key_offset = iwl_mvm_set_fw_key_idx(mvm); | ||
1502 | if (key_offset == STA_KEY_IDX_INVALID) | ||
1481 | return -ENOSPC; | 1503 | return -ENOSPC; |
1504 | keyconf->hw_key_idx = key_offset; | ||
1482 | } | 1505 | } |
1483 | 1506 | ||
1484 | ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, mcast); | 1507 | ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, mcast); |
1485 | if (ret) { | 1508 | if (ret) { |
1486 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | 1509 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); |
1487 | goto end; | 1510 | goto end; |
@@ -1495,7 +1518,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
1495 | */ | 1518 | */ |
1496 | if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || | 1519 | if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || |
1497 | keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { | 1520 | keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { |
1498 | ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, !mcast); | 1521 | ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, |
1522 | key_offset, !mcast); | ||
1499 | if (ret) { | 1523 | if (ret) { |
1500 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | 1524 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); |
1501 | __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); | 1525 | __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); |
@@ -1521,7 +1545,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1521 | lockdep_assert_held(&mvm->mutex); | 1545 | lockdep_assert_held(&mvm->mutex); |
1522 | 1546 | ||
1523 | /* Get the station id from the mvm local station table */ | 1547 | /* Get the station id from the mvm local station table */ |
1524 | sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 1548 | sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta); |
1525 | 1549 | ||
1526 | IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", | 1550 | IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", |
1527 | keyconf->keyidx, sta_id); | 1551 | keyconf->keyidx, sta_id); |
@@ -1547,24 +1571,6 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1547 | return 0; | 1571 | return 0; |
1548 | } | 1572 | } |
1549 | 1573 | ||
1550 | /* | ||
1551 | * It is possible that the 'sta' parameter is NULL, and thus | ||
1552 | * there is a need to retrieve the sta from the local station table, | ||
1553 | * for example when a GTK is removed (where the sta_id will then be | ||
1554 | * the AP ID, and no station was passed by mac80211.) | ||
1555 | */ | ||
1556 | if (!sta) { | ||
1557 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
1558 | lockdep_is_held(&mvm->mutex)); | ||
1559 | if (!sta) { | ||
1560 | IWL_ERR(mvm, "Invalid station id\n"); | ||
1561 | return -EINVAL; | ||
1562 | } | ||
1563 | } | ||
1564 | |||
1565 | if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) | ||
1566 | return -EINVAL; | ||
1567 | |||
1568 | ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); | 1574 | ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); |
1569 | if (ret) | 1575 | if (ret) |
1570 | return ret; | 1576 | return ret; |
@@ -1584,7 +1590,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
1584 | u16 *phase1key) | 1590 | u16 *phase1key) |
1585 | { | 1591 | { |
1586 | struct iwl_mvm_sta *mvm_sta; | 1592 | struct iwl_mvm_sta *mvm_sta; |
1587 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 1593 | u8 sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta); |
1588 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); | 1594 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); |
1589 | 1595 | ||
1590 | if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) | 1596 | if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) |
@@ -1602,7 +1608,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
1602 | 1608 | ||
1603 | mvm_sta = iwl_mvm_sta_from_mac80211(sta); | 1609 | mvm_sta = iwl_mvm_sta_from_mac80211(sta); |
1604 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | 1610 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, |
1605 | iv32, phase1key, CMD_ASYNC); | 1611 | iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx); |
1606 | rcu_read_unlock(); | 1612 | rcu_read_unlock(); |
1607 | } | 1613 | } |
1608 | 1614 | ||