Commit d6ee54a9 authored by Luca Coelho's avatar Luca Coelho Committed by Emmanuel Grumbach

iwlwifi: mvm: don't overwrite the key indices in D3 entry

When entering D3, we need to use hardcoded key indices because the
firmware requires that.  To do so, we are overwriting the HW key index
in the keyconf structure, which makes it impossible to reuse the
indices that were used before entering D3.  Additionally, we overwrite
all the non-PTK keys with index 1, because the firmware only allows
one non-PTK key to be set.  This is bad, because when we resume, we
may try to set more than one key with index 1, which will obviously
fail.

To fix this, allow the callers to set a pre-defined index to use in
iwl_mvm_set_sta_key() instead of relying on the hw_key_idx value from
the keyconf struct (which requires overwriting it).  In normal cases,
the caller can pass STA_KEY_IDX_INVALID, which will cause a new key
offset to be chosen.  During HW_RESTART, we pass the offset that is in
use.  And during D3 entry, we pass the hardcoded indices we need to
use.

Additionally, don't clear the fw_key_table in D3 entry, so that the
flags are still set with the pre-D3 values when exiting D3.

fixes=I3165c22362483f0152d9ec1d2a987fb5529727c1

Fixes: b546dcd6 ("iwlwifi: mvm: don't reset key index on HW restart")
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 5fd6705c
...@@ -309,9 +309,9 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, ...@@ -309,9 +309,9 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
* to transmit packets to the AP, i.e. the PTK. * to transmit packets to the AP, i.e. the PTK.
*/ */
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
key->hw_key_idx = 0;
mvm->ptk_ivlen = key->iv_len; mvm->ptk_ivlen = key->iv_len;
mvm->ptk_icvlen = key->icv_len; mvm->ptk_icvlen = key->icv_len;
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0);
} else { } else {
/* /*
* firmware only supports TSC/RSC for a single key, * firmware only supports TSC/RSC for a single key,
...@@ -319,12 +319,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, ...@@ -319,12 +319,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
* with new ones -- this relies on mac80211 doing * with new ones -- this relies on mac80211 doing
* list_add_tail(). * list_add_tail().
*/ */
key->hw_key_idx = 1;
mvm->gtk_ivlen = key->iv_len; mvm->gtk_ivlen = key->iv_len;
mvm->gtk_icvlen = key->icv_len; mvm->gtk_icvlen = key->icv_len;
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1);
} }
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
data->error = ret != 0; data->error = ret != 0;
out_unlock: out_unlock:
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
...@@ -772,9 +771,6 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm) ...@@ -772,9 +771,6 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
*/ */
set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
/* We reprogram keys and shouldn't allocate new key indices */
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
mvm->ptk_ivlen = 0; mvm->ptk_ivlen = 0;
mvm->ptk_icvlen = 0; mvm->ptk_icvlen = 0;
mvm->ptk_ivlen = 0; mvm->ptk_ivlen = 0;
......
...@@ -2941,6 +2941,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2941,6 +2941,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
{ {
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret; int ret;
u8 key_offset;
if (iwlwifi_mod_params.sw_crypto) { if (iwlwifi_mod_params.sw_crypto) {
IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n"); IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n");
...@@ -3006,10 +3007,14 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -3006,10 +3007,14 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break; break;
} }
/* in HW restart reuse the index, otherwise request a new one */
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
key_offset = key->hw_key_idx;
else
key_offset = STA_KEY_IDX_INVALID;
IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset);
test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
&mvm->status));
if (ret) { if (ret) {
IWL_WARN(mvm, "set key failed\n"); IWL_WARN(mvm, "set key failed\n");
/* /*
......
...@@ -1227,7 +1227,8 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, ...@@ -1227,7 +1227,8 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta, struct iwl_mvm_sta *mvm_sta,
struct ieee80211_key_conf *keyconf, bool mcast, struct ieee80211_key_conf *keyconf, bool mcast,
u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags) u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags,
u8 key_offset)
{ {
struct iwl_mvm_add_sta_key_cmd cmd = {}; struct iwl_mvm_add_sta_key_cmd cmd = {};
__le16 key_flags; __le16 key_flags;
...@@ -1269,7 +1270,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, ...@@ -1269,7 +1270,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
if (mcast) if (mcast)
key_flags |= cpu_to_le16(STA_KEY_MULTICAST); key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
cmd.key_offset = keyconf->hw_key_idx; cmd.key_offset = key_offset;
cmd.key_flags = key_flags; cmd.key_flags = key_flags;
cmd.sta_id = sta_id; cmd.sta_id = sta_id;
...@@ -1360,6 +1361,7 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ...@@ -1360,6 +1361,7 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf, struct ieee80211_key_conf *keyconf,
u8 key_offset,
bool mcast) bool mcast)
{ {
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
...@@ -1375,17 +1377,17 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ...@@ -1375,17 +1377,17 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
ieee80211_get_key_rx_seq(keyconf, 0, &seq); ieee80211_get_key_rx_seq(keyconf, 0, &seq);
ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
seq.tkip.iv32, p1k, 0); seq.tkip.iv32, p1k, 0, key_offset);
break; break;
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_WEP104:
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
0, NULL, 0); 0, NULL, 0, key_offset);
break; break;
default: default:
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
0, NULL, 0); 0, NULL, 0, key_offset);
} }
return ret; return ret;
...@@ -1433,7 +1435,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ...@@ -1433,7 +1435,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf, struct ieee80211_key_conf *keyconf,
bool have_key_offset) u8 key_offset)
{ {
bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
u8 sta_id; u8 sta_id;
...@@ -1470,18 +1472,25 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ...@@ -1470,18 +1472,25 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
return -EINVAL; return -EINVAL;
if (!have_key_offset) { /* If the key_offset is not pre-assigned, we need to find a
/* * new offset to use. In normal cases, the offset is not
* The D3 firmware hardcodes the PTK offset to 0, so we have to * pre-assigned, but during HW_RESTART we want to reuse the
* configure it there. As a result, this workaround exists to * same indices, so we pass them when this function is called.
* let the caller set the key offset (hw_key_idx), see d3.c. *
* In D3 entry, we need to hardcoded the indices (because the
* firmware hardcodes the PTK offset to 0). In this case, we
* need to make sure we don't overwrite the hw_key_idx in the
* keyconf structure, because otherwise we cannot configure
* the original ones back when resuming.
*/ */
keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm); if (key_offset == STA_KEY_IDX_INVALID) {
if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID) key_offset = iwl_mvm_set_fw_key_idx(mvm);
if (key_offset == STA_KEY_IDX_INVALID)
return -ENOSPC; return -ENOSPC;
keyconf->hw_key_idx = key_offset;
} }
ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, mcast); ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, mcast);
if (ret) { if (ret) {
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
goto end; goto end;
...@@ -1495,7 +1504,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ...@@ -1495,7 +1504,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
*/ */
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, !mcast); ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf,
key_offset, !mcast);
if (ret) { if (ret) {
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
__iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
...@@ -1602,7 +1612,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, ...@@ -1602,7 +1612,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
mvm_sta = iwl_mvm_sta_from_mac80211(sta); mvm_sta = iwl_mvm_sta_from_mac80211(sta);
iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
iv32, phase1key, CMD_ASYNC); iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx);
rcu_read_unlock(); rcu_read_unlock();
} }
......
...@@ -365,8 +365,8 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, ...@@ -365,8 +365,8 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key, struct ieee80211_key_conf *keyconf,
bool have_key_offset); u8 key_offset);
int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
......
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