diff options
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 06cc03820dd5..c12f303cf652 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -279,7 +279,6 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, { struct iwl_mvm_sta *mvmsta; struct iwl_mvm_vif *mvmvif; - u8 fwkeyid = u32_get_bits(status, IWL_RX_MPDU_STATUS_KEY); u8 keyid; struct ieee80211_key_conf *key; u32 len = le16_to_cpu(desc->mpdu_len); @@ -299,6 +298,10 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, if (!ieee80211_is_beacon(hdr->frame_control)) return 0; + /* key mismatch - will also report !MIC_OK but we shouldn't count it */ + if (!(status & IWL_RX_MPDU_STATUS_KEY_VALID)) + return -1; + /* good cases */ if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK && !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR))) @@ -309,26 +312,36 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, mvmsta = iwl_mvm_sta_from_mac80211(sta); - /* what? */ - if (fwkeyid != 6 && fwkeyid != 7) - return -1; - mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); - key = rcu_dereference(mvmvif->bcn_prot.keys[fwkeyid - 6]); - if (!key) - return -1; + /* + * both keys will have the same cipher and MIC length, use + * whichever one is available + */ + key = rcu_dereference(mvmvif->bcn_prot.keys[0]); + if (!key) { + key = rcu_dereference(mvmvif->bcn_prot.keys[1]); + if (!key) + return -1; + } if (len < key->icv_len + IEEE80211_GMAC_PN_LEN + 2) return -1; - /* - * See if the key ID matches - if not this may be due to a - * switch and the firmware may erroneously report !MIC_OK. - */ + /* get the real key ID */ keyid = frame[len - key->icv_len - IEEE80211_GMAC_PN_LEN - 2]; - if (keyid != fwkeyid) - return -1; + /* and if that's the other key, look it up */ + if (keyid != key->keyidx) { + /* + * shouldn't happen since firmware checked, but be safe + * in case the MIC length is wrong too, for example + */ + if (keyid != 6 && keyid != 7) + return -1; + key = rcu_dereference(mvmvif->bcn_prot.keys[keyid - 6]); + if (!key) + return -1; + } /* Report status to mac80211 */ if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) |