summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/d3.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c501
1 files changed, 122 insertions, 379 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 507c03198c92..029c846a236f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -120,19 +120,17 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */
- struct {
- struct iwl_mvm_wep_key_cmd wep_key_cmd;
- struct iwl_mvm_wep_key wep_key;
- } __packed wkc = {
- .wep_key_cmd.mac_id_n_color =
- cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
- mvmvif->color)),
- .wep_key_cmd.num_keys = 1,
- /* firmware sets STA_KEY_FLG_WEP_13BYTES */
- .wep_key_cmd.decryption_type = STA_KEY_FLG_WEP,
- .wep_key.key_index = key->keyidx,
- .wep_key.key_size = key->keylen,
- };
+ DEFINE_RAW_FLEX(struct iwl_mvm_wep_key_cmd, wkc, wep_key, 1);
+ struct iwl_mvm_wep_key *wep_key = wkc->wep_key;
+
+ wkc->mac_id_n_color =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+ mvmvif->color));
+ wkc->num_keys = 1;
+ /* firmware sets STA_KEY_FLG_WEP_13BYTES */
+ wkc->decryption_type = STA_KEY_FLG_WEP;
+ wep_key->key_index = key->keyidx;
+ wep_key->key_size = key->keylen;
/*
* This will fail -- the key functions don't set support
@@ -142,18 +140,19 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
break;
- memcpy(&wkc.wep_key.key[3], key->key, key->keylen);
+ memcpy(&wep_key->key[3], key->key, key->keylen);
if (key->keyidx == mvmvif->tx_key_idx) {
/* TX key must be at offset 0 */
- wkc.wep_key.key_offset = 0;
+ wep_key->key_offset = 0;
} else {
/* others start at 1 */
data->wep_key_idx++;
- wkc.wep_key.key_offset = data->wep_key_idx;
+ wep_key->key_offset = data->wep_key_idx;
}
mutex_lock(&mvm->mutex);
- ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, sizeof(wkc), &wkc);
+ ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0,
+ __struct_size(wkc), wkc);
data->error = ret != 0;
mvm->ptk_ivlen = key->iv_len;
@@ -212,7 +211,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
}
struct wowlan_key_rsc_tsc_data {
- struct iwl_wowlan_rsc_tsc_params_cmd_v4 *rsc_tsc;
+ struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 *rsc_tsc;
bool have_rsc_tsc;
};
@@ -237,21 +236,21 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw,
u64 pn64;
tkip_sc =
- data->rsc_tsc->params.all_tsc_rsc.tkip.unicast_rsc;
+ data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
tkip_tx_sc =
- &data->rsc_tsc->params.all_tsc_rsc.tkip.tsc;
+ &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
pn64 = atomic64_read(&key->tx_pn);
tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));
tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64));
} else {
tkip_sc =
- data->rsc_tsc->params.all_tsc_rsc.tkip.multicast_rsc;
+ data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
}
/*
* For non-QoS this relies on the fact that both the uCode and
- * mac80211 use TID 0 (as they need to to avoid replay attacks)
+ * mac80211 use TID 0 (as they need to avoid replay attacks)
* for checking the IV in the frames.
*/
for (i = 0; i < IWL_NUM_RSC; i++) {
@@ -270,15 +269,15 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw,
u64 pn64;
aes_sc =
- data->rsc_tsc->params.all_tsc_rsc.aes.unicast_rsc;
+ data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
aes_tx_sc =
- &data->rsc_tsc->params.all_tsc_rsc.aes.tsc;
+ &data->rsc_tsc->all_tsc_rsc.aes.tsc;
pn64 = atomic64_read(&key->tx_pn);
aes_tx_sc->pn = cpu_to_le64(pn64);
} else {
aes_sc =
- data->rsc_tsc->params.all_tsc_rsc.aes.multicast_rsc;
+ data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
}
/*
@@ -387,7 +386,7 @@ static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw,
/*
* For non-QoS this relies on the fact that both the uCode and
- * mac80211 use TID 0 (as they need to to avoid replay attacks)
+ * mac80211 use TID 0 (as they need to avoid replay attacks)
* for checking the IV in the frames.
*/
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
@@ -481,30 +480,21 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm,
else
ret = 0;
kfree(data.rsc);
- } else if (ver == 4 || ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) {
+ } else if (ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) {
struct wowlan_key_rsc_tsc_data data = {};
- int size;
data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL);
if (!data.rsc_tsc)
return -ENOMEM;
- if (ver == 4) {
- size = sizeof(*data.rsc_tsc);
- data.rsc_tsc->sta_id =
- cpu_to_le32(mvm_link->ap_sta_id);
- } else {
- /* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */
- size = sizeof(data.rsc_tsc->params);
- }
-
ieee80211_iter_keys(mvm->hw, vif,
iwl_mvm_wowlan_get_rsc_tsc_data,
&data);
if (data.have_rsc_tsc)
ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM,
- CMD_ASYNC, size,
+ CMD_ASYNC,
+ sizeof(*data.rsc_tsc),
data.rsc_tsc);
else
ret = 0;
@@ -1475,9 +1465,6 @@ struct iwl_wowlan_status_data {
struct iwl_multicast_key_data igtk;
struct iwl_multicast_key_data bigtk[WOWLAN_BIGTK_KEYS_NUM];
- int num_mlo_keys;
- struct iwl_wowlan_mlo_gtk mlo_keys[WOWLAN_MAX_MLO_KEYS];
-
u8 *wake_packet;
};
@@ -1693,7 +1680,7 @@ static void iwl_mvm_set_aes_ptk_rx_seq(struct iwl_mvm *mvm,
}
static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status,
- union iwl_all_tsc_rsc *sc)
+ union iwl_all_tsc_rsc *sc, u8 key_idx)
{
int i;
@@ -1708,7 +1695,7 @@ static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status,
&status->gtk_seq[0].aes.seq[i]);
}
status->gtk_seq[0].valid = true;
- status->gtk_seq[0].key_id = -1;
+ status->gtk_seq[0].key_id = key_idx;
/* PTK TX counter */
status->ptk.tkip.tx_pn = (u64)le16_to_cpu(sc->tkip.tsc.iv16) |
@@ -1791,8 +1778,7 @@ static void iwl_mvm_set_key_rx_seq_idx(struct ieee80211_key_conf *key,
}
static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
- struct iwl_wowlan_status_data *status,
- bool installed)
+ struct iwl_wowlan_status_data *status)
{
int i;
@@ -1800,23 +1786,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
if (!status->gtk_seq[i].valid)
continue;
- /* Handle the case where we know the key ID */
- if (status->gtk_seq[i].key_id == key->keyidx) {
- s8 new_key_id = -1;
-
- if (status->num_of_gtk_rekeys)
- new_key_id = status->gtk[0].flags &
- IWL_WOWLAN_GTK_IDX_MASK;
-
- /* Don't install a new key's value to an old key */
- if (new_key_id != key->keyidx)
- iwl_mvm_set_key_rx_seq_idx(key, status, i);
- continue;
- }
-
- /* handle the case where we didn't, last key only */
- if (status->gtk_seq[i].key_id == -1 &&
- (!status->num_of_gtk_rekeys || installed))
+ if (status->gtk_seq[i].key_id == key->keyidx)
iwl_mvm_set_key_rx_seq_idx(key, status, i);
}
}
@@ -1906,17 +1876,10 @@ iwl_mvm_d3_update_igtk_bigtk(struct iwl_wowlan_status_data *status,
struct ieee80211_key_conf *key,
struct iwl_multicast_key_data *key_data)
{
- if (status->num_of_gtk_rekeys && key_data->len) {
- /* remove rekeyed key */
- ieee80211_remove_key(key);
- } else {
- struct ieee80211_key_seq seq;
+ struct ieee80211_key_seq seq;
- iwl_mvm_d3_set_igtk_bigtk_ipn(key_data,
- &seq,
- key->cipher);
- ieee80211_set_key_rx_seq(key, 0, &seq);
- }
+ iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, key->cipher);
+ ieee80211_set_key_rx_seq(key, 0, &seq);
}
static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
@@ -1957,18 +1920,13 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
return;
}
keyidx = key->keyidx;
- /* The current key is always sent by the FW, even if it wasn't
- * rekeyed during D3.
- * We remove an existing key if it has the same index as
- * a new key
+ /*
+ * Update the seq even if there was a rekey. If there was a
+ * rekey, we will update again after replacing the key
*/
- if (status->num_of_gtk_rekeys &&
- ((status->gtk[0].len && keyidx == status->gtk[0].id) ||
- (status->gtk[1].len && keyidx == status->gtk[1].id))) {
- ieee80211_remove_key(key);
- } else {
- iwl_mvm_set_key_rx_seq(key, data->status, false);
- }
+ if ((status->gtk[0].len && keyidx == status->gtk[0].id) ||
+ (status->gtk[1].len && keyidx == status->gtk[1].id))
+ iwl_mvm_set_key_rx_seq(key, status);
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
@@ -1987,199 +1945,35 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
}
}
-struct iwl_mvm_d3_mlo_old_keys {
- u32 cipher[IEEE80211_MLD_MAX_NUM_LINKS][WOWLAN_MLO_GTK_KEY_NUM_TYPES];
- struct ieee80211_key_conf *key[IEEE80211_MLD_MAX_NUM_LINKS][8];
-};
-
-static void iwl_mvm_mlo_key_ciphers(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key,
- void *data)
-{
- struct iwl_mvm_d3_mlo_old_keys *old_keys = data;
- enum iwl_wowlan_mlo_gtk_type key_type;
-
- if (key->link_id < 0)
- return;
-
- if (WARN_ON(key->link_id >= IEEE80211_MLD_MAX_NUM_LINKS ||
- key->keyidx >= 8))
- return;
-
- if (WARN_ON(old_keys->key[key->link_id][key->keyidx]))
- return;
-
- switch (key->cipher) {
- case WLAN_CIPHER_SUITE_CCMP:
- case WLAN_CIPHER_SUITE_GCMP:
- case WLAN_CIPHER_SUITE_GCMP_256:
- key_type = WOWLAN_MLO_GTK_KEY_TYPE_GTK;
- break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_128:
- case WLAN_CIPHER_SUITE_BIP_GMAC_256:
- case WLAN_CIPHER_SUITE_BIP_CMAC_256:
- case WLAN_CIPHER_SUITE_AES_CMAC:
- if (key->keyidx == 4 || key->keyidx == 5) {
- key_type = WOWLAN_MLO_GTK_KEY_TYPE_IGTK;
- break;
- } else if (key->keyidx == 6 || key->keyidx == 7) {
- key_type = WOWLAN_MLO_GTK_KEY_TYPE_BIGTK;
- break;
- }
- return;
- default:
- /* ignore WEP/TKIP or unknown ciphers */
- return;
- }
-
- old_keys->cipher[key->link_id][key_type] = key->cipher;
- old_keys->key[key->link_id][key->keyidx] = key;
-}
-
-static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status,
- struct ieee80211_vif *vif,
- struct iwl_mvm *mvm)
-{
- int i;
- struct iwl_mvm_d3_mlo_old_keys *old_keys;
- bool ret = true;
-
- IWL_DEBUG_WOWLAN(mvm, "Num of MLO Keys: %d\n", status->num_mlo_keys);
- if (!status->num_mlo_keys)
- return true;
-
- old_keys = kzalloc(sizeof(*old_keys), GFP_KERNEL);
- if (!old_keys)
- return false;
-
- /* find the cipher for each mlo key */
- ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mlo_key_ciphers, old_keys);
-
- for (i = 0; i < status->num_mlo_keys; i++) {
- struct iwl_wowlan_mlo_gtk *mlo_key = &status->mlo_keys[i];
- struct ieee80211_key_conf *key, *old_key;
- struct ieee80211_key_seq seq;
- struct {
- struct ieee80211_key_conf conf;
- u8 key[32];
- } conf = {};
- u16 flags = le16_to_cpu(mlo_key->flags);
- int j, link_id, key_id, key_type;
-
- link_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK);
- key_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK);
- key_type = u16_get_bits(flags,
- WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK);
-
- if (!(vif->valid_links & BIT(link_id)))
- continue;
-
- if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS ||
- key_id >= 8 ||
- key_type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES))
- continue;
-
- conf.conf.cipher = old_keys->cipher[link_id][key_type];
- /* WARN_ON? */
- if (!conf.conf.cipher)
- continue;
-
- conf.conf.keylen = 0;
- switch (conf.conf.cipher) {
- case WLAN_CIPHER_SUITE_CCMP:
- case WLAN_CIPHER_SUITE_GCMP:
- conf.conf.keylen = WLAN_KEY_LEN_CCMP;
- break;
- case WLAN_CIPHER_SUITE_GCMP_256:
- conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;
- break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_128:
- conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128;
- break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_256:
- conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256;
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC;
- break;
- case WLAN_CIPHER_SUITE_BIP_CMAC_256:
- conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256;
- break;
- }
-
- if (WARN_ON(!conf.conf.keylen ||
- conf.conf.keylen > sizeof(conf.key)))
- continue;
-
- memcpy(conf.conf.key, mlo_key->key, conf.conf.keylen);
- conf.conf.keyidx = key_id;
-
- old_key = old_keys->key[link_id][key_id];
- if (old_key) {
- IWL_DEBUG_WOWLAN(mvm,
- "Remove MLO key id %d, link id %d\n",
- key_id, link_id);
- ieee80211_remove_key(old_key);
- }
-
- IWL_DEBUG_WOWLAN(mvm, "Add MLO key id %d, link id %d\n",
- key_id, link_id);
- key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);
- if (WARN_ON(IS_ERR(key))) {
- ret = false;
- goto out;
- }
-
- /*
- * mac80211 expects the pn in big-endian
- * also note that seq is a union of all cipher types
- * (ccmp, gcmp, cmac, gmac), and they all have the same
- * pn field (of length 6) so just copy it to ccmp.pn.
- */
- for (j = 5; j >= 0; j--)
- seq.ccmp.pn[5 - j] = mlo_key->pn[j];
-
- /* group keys are non-QoS and use TID 0 */
- ieee80211_set_key_rx_seq(key, 0, &seq);
- }
-
-out:
- kfree(old_keys);
- return ret;
-}
-
static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
struct ieee80211_vif *vif,
struct iwl_mvm *mvm, u32 gtk_cipher)
{
int i, j;
struct ieee80211_key_conf *key;
- struct {
- struct ieee80211_key_conf conf;
- u8 key[32];
- } conf = {
- .conf.cipher = gtk_cipher,
- };
+ DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key,
+ WOWLAN_KEY_MAX_SIZE);
int link_id = vif->active_links ? __ffs(vif->active_links) : -1;
+ u8 key_data[WOWLAN_KEY_MAX_SIZE];
+
+ conf->cipher = gtk_cipher;
BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP);
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP);
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256);
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP);
- BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk[0].key));
+ BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_CCMP);
+ BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_GCMP_256);
+ BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_TKIP);
+ BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(status->gtk[0].key));
switch (gtk_cipher) {
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
- conf.conf.keylen = WLAN_KEY_LEN_CCMP;
+ conf->keylen = WLAN_KEY_LEN_CCMP;
break;
case WLAN_CIPHER_SUITE_GCMP_256:
- conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;
+ conf->keylen = WLAN_KEY_LEN_GCMP_256;
break;
case WLAN_CIPHER_SUITE_TKIP:
- conf.conf.keylen = WLAN_KEY_LEN_TKIP;
+ conf->keylen = WLAN_KEY_LEN_TKIP;
break;
default:
WARN_ON(1);
@@ -2189,16 +1983,22 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
if (!status->gtk[i].len)
continue;
- conf.conf.keyidx = status->gtk[i].id;
+ conf->keyidx = status->gtk[i].id;
IWL_DEBUG_WOWLAN(mvm,
"Received from FW GTK cipher %d, key index %d\n",
- conf.conf.cipher, conf.conf.keyidx);
- memcpy(conf.conf.key, status->gtk[i].key,
+ conf->cipher, conf->keyidx);
+ memcpy(conf->key, status->gtk[i].key,
sizeof(status->gtk[i].key));
+ memcpy(key_data, status->gtk[i].key, sizeof(status->gtk[i].key));
- key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);
- if (IS_ERR(key))
+ key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, key_data,
+ sizeof(key_data), link_id);
+ if (IS_ERR(key)) {
+ /* FW may send also the old keys */
+ if (PTR_ERR(key) == -EALREADY)
+ continue;
return false;
+ }
for (j = 0; j < ARRAY_SIZE(status->gtk_seq); j++) {
if (!status->gtk_seq[j].valid ||
@@ -2218,55 +2018,66 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,
struct ieee80211_vif *vif, u32 cipher,
struct iwl_multicast_key_data *key_data)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key,
+ WOWLAN_KEY_MAX_SIZE);
struct ieee80211_key_conf *key_config;
- struct {
- struct ieee80211_key_conf conf;
- u8 key[WOWLAN_KEY_MAX_SIZE];
- } conf = {
- .conf.cipher = cipher,
- .conf.keyidx = key_data->id,
- };
struct ieee80211_key_seq seq;
int link_id = vif->active_links ? __ffs(vif->active_links) : -1;
+ u8 key[WOWLAN_KEY_MAX_SIZE];
+ s8 keyidx = key_data->id;
+
+ conf->cipher = cipher;
+ conf->keyidx = keyidx;
if (!key_data->len)
return true;
- iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher);
+ iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf->cipher);
switch (cipher) {
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
- conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128;
+ conf->keylen = WLAN_KEY_LEN_BIP_GMAC_128;
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
- conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256;
+ conf->keylen = WLAN_KEY_LEN_BIP_GMAC_256;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
- conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC;
+ conf->keylen = WLAN_KEY_LEN_AES_CMAC;
break;
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
- conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256;
+ conf->keylen = WLAN_KEY_LEN_BIP_CMAC_256;
break;
default:
WARN_ON(1);
}
- BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key));
- memcpy(conf.conf.key, key_data->key, conf.conf.keylen);
+ BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(key_data->key));
+ memcpy(conf->key, key_data->key, conf->keylen);
- key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);
- if (IS_ERR(key_config))
- return false;
+ memcpy(key, key_data->key, sizeof(key_data->key));
+
+ key_config = ieee80211_gtk_rekey_add(vif, keyidx, key, sizeof(key),
+ link_id);
+ if (IS_ERR(key_config)) {
+ /* FW may send also the old keys */
+ return PTR_ERR(key_config) == -EALREADY;
+ }
ieee80211_set_key_rx_seq(key_config, 0, &seq);
- if (key_config->keyidx == 4 || key_config->keyidx == 5) {
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ if (keyidx == 4 || keyidx == 5) {
struct iwl_mvm_vif_link_info *mvm_link;
link_id = link_id < 0 ? 0 : link_id;
mvm_link = mvmvif->link[link_id];
+ if (mvm_link->igtk)
+ mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;
mvm_link->igtk = key_config;
}
+ if (vif->type == NL80211_IFTYPE_STATION && (keyidx == 6 || keyidx == 7))
+ rcu_assign_pointer(mvmvif->bcn_prot.keys[keyidx - 6],
+ key_config);
+
return true;
}
@@ -2353,9 +2164,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
return false;
}
- if (!iwl_mvm_mlo_gtk_rekey(status, vif, mvm))
- return false;
-
ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
(void *)&replay_ctr, GFP_KERNEL);
}
@@ -2385,6 +2193,7 @@ static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status,
status->gtk[0].len = data->key_len;
status->gtk[0].flags = data->key_flags;
+ status->gtk[0].id = status->gtk[0].flags & IWL_WOWLAN_GTK_IDX_MASK;
memcpy(status->gtk[0].key, data->key, sizeof(data->key));
@@ -2486,10 +2295,11 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
struct iwl_wowlan_status_data *status,
u32 len)
{
- u32 expected_len = sizeof(*data) +
- data->num_mlo_link_keys * sizeof(status->mlo_keys[0]);
+ if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys,
+ "MLO is not supported, shouldn't receive MLO keys\n"))
+ return;
- if (len < expected_len) {
+ if (len < sizeof(*data)) {
IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
status = NULL;
return;
@@ -2518,33 +2328,17 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
le32_to_cpu(data->num_of_gtk_rekeys);
status->received_beacons = le32_to_cpu(data->received_beacons);
status->tid_tear_down = data->tid_tear_down;
-
- if (data->num_mlo_link_keys) {
- status->num_mlo_keys = data->num_mlo_link_keys;
- if (IWL_FW_CHECK(mvm,
- status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS,
- "Too many mlo keys: %d, max %d\n",
- status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS))
- status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS;
- memcpy(status->mlo_keys, data->mlo_gtks,
- status->num_mlo_keys * sizeof(status->mlo_keys[0]));
- }
}
static void
-iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm,
- struct iwl_wowlan_info_notif_v4 *data,
+iwl_mvm_parse_wowlan_info_notif_v3(struct iwl_mvm *mvm,
+ struct iwl_wowlan_info_notif_v3 *data,
struct iwl_wowlan_status_data *status,
- u32 len, bool has_mlo_keys)
+ u32 len)
{
u32 i;
- u32 expected_len = sizeof(*data);
-
- if (has_mlo_keys)
- expected_len += (data->num_mlo_link_keys *
- sizeof(status->mlo_keys[0]));
- if (len < expected_len) {
+ if (len < sizeof(*data)) {
IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
status = NULL;
return;
@@ -2567,22 +2361,11 @@ iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm,
le32_to_cpu(data->num_of_gtk_rekeys);
status->received_beacons = le32_to_cpu(data->received_beacons);
status->tid_tear_down = data->tid_tear_down;
-
- if (has_mlo_keys && data->num_mlo_link_keys) {
- status->num_mlo_keys = data->num_mlo_link_keys;
- if (IWL_FW_CHECK(mvm,
- status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS,
- "Too many mlo keys: %d, max %d\n",
- status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS))
- status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS;
- memcpy(status->mlo_keys, data->mlo_gtks,
- status->num_mlo_keys * sizeof(status->mlo_keys[0]));
- }
}
static void
-iwl_mvm_parse_wowlan_info_notif_v2(struct iwl_mvm *mvm,
- struct iwl_wowlan_info_notif_v2 *data,
+iwl_mvm_parse_wowlan_info_notif_v1(struct iwl_mvm *mvm,
+ struct iwl_wowlan_info_notif_v1 *data,
struct iwl_wowlan_status_data *status,
u32 len)
{
@@ -2667,8 +2450,6 @@ iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \
iwl_mvm_parse_wowlan_status_common(v6)
iwl_mvm_parse_wowlan_status_common(v7)
-iwl_mvm_parse_wowlan_status_common(v9)
-iwl_mvm_parse_wowlan_status_common(v12)
static struct iwl_wowlan_status_data *
iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
@@ -2724,7 +2505,8 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
v6->gtk.tkip_mic_key,
sizeof(v6->gtk.tkip_mic_key));
- iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc);
+ iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc,
+ v6->gtk.key_index);
/* hardcode the key length to 16 since v6 only supports 16 */
status->gtk[0].len = 16;
@@ -2735,6 +2517,7 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
* currently used key.
*/
status->gtk[0].flags = v6->gtk.key_index | BIT(7);
+ status->gtk[0].id = v6->gtk.key_index;
} else if (notif_ver == 7) {
struct iwl_wowlan_status_v7 *v7 = (void *)cmd.resp_pkt->data;
@@ -2742,36 +2525,10 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
if (!status)
goto out_free_resp;
- iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc);
+ iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc,
+ v7->gtk[0].key_flags & IWL_WOWLAN_GTK_IDX_MASK);
iwl_mvm_convert_gtk_v2(status, &v7->gtk[0]);
iwl_mvm_convert_igtk(status, &v7->igtk[0]);
- } else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) {
- struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data;
-
- /* these three command versions have same layout and size, the
- * difference is only in a few not used (reserved) fields.
- */
- status = iwl_mvm_parse_wowlan_status_common_v9(mvm, v9, len);
- if (!status)
- goto out_free_resp;
-
- iwl_mvm_convert_key_counters(status, &v9->gtk[0].rsc.all_tsc_rsc);
- iwl_mvm_convert_gtk_v2(status, &v9->gtk[0]);
- iwl_mvm_convert_igtk(status, &v9->igtk[0]);
-
- status->tid_tear_down = v9->tid_tear_down;
- } else if (notif_ver == 12) {
- struct iwl_wowlan_status_v12 *v12 = (void *)cmd.resp_pkt->data;
-
- status = iwl_mvm_parse_wowlan_status_common_v12(mvm, v12, len);
- if (!status)
- goto out_free_resp;
-
- iwl_mvm_convert_key_counters_v5(status, &v12->gtk[0].sc);
- iwl_mvm_convert_gtk_v3(status, v12->gtk);
- iwl_mvm_convert_igtk(status, &v12->igtk[0]);
-
- status->tid_tear_down = v12->tid_tear_down;
} else {
IWL_ERR(mvm,
"Firmware advertises unknown WoWLAN status response %d!\n",
@@ -3298,44 +3055,30 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
break;
}
- if (wowlan_info_ver < 2) {
+ if (wowlan_info_ver == 1) {
struct iwl_wowlan_info_notif_v1 *notif_v1 =
(void *)pkt->data;
- struct iwl_wowlan_info_notif_v2 *notif_v2;
-
- notif_v2 = kmemdup(notif_v1, sizeof(*notif_v2), GFP_ATOMIC);
-
- if (!notif_v2)
- return false;
-
- notif_v2->tid_tear_down = notif_v1->tid_tear_down;
- notif_v2->station_id = notif_v1->station_id;
- memset_after(notif_v2, 0, station_id);
- iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2,
- d3_data->status,
- len);
- kfree(notif_v2);
-
- } else if (wowlan_info_ver == 2) {
- struct iwl_wowlan_info_notif_v2 *notif_v2 =
- (void *)pkt->data;
- iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2,
+ iwl_mvm_parse_wowlan_info_notif_v1(mvm, notif_v1,
d3_data->status,
len);
- } else if (wowlan_info_ver < 5) {
- struct iwl_wowlan_info_notif_v4 *notif =
+ } else if (wowlan_info_ver == 3) {
+ struct iwl_wowlan_info_notif_v3 *notif =
(void *)pkt->data;
- iwl_mvm_parse_wowlan_info_notif_v4(mvm, notif,
- d3_data->status, len,
- wowlan_info_ver > 3);
- } else {
+ iwl_mvm_parse_wowlan_info_notif_v3(mvm, notif,
+ d3_data->status, len);
+ } else if (wowlan_info_ver == 5) {
struct iwl_wowlan_info_notif *notif =
(void *)pkt->data;
iwl_mvm_parse_wowlan_info_notif(mvm, notif,
d3_data->status, len);
+ } else {
+ IWL_FW_CHECK(mvm, 1,
+ "Firmware advertises unknown WoWLAN info notification %d!\n",
+ wowlan_info_ver);
+ return false;
}
d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO;