From 56363ddeeed3afc5277ca227209773bc1042cc7b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 28 Aug 2010 18:21:21 +0200 Subject: [PATCH] ath9k: fix spurious MIC failure reports According to the hardware documentation, the MIC failure bit is only valid if the frame was decrypted using a valid TKIP key and is not a fragment. In some setups I've seen hardware-reported MIC failures on an AP that was configured for CCMP only, so it's clear that additional checks are necessary. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/common.c | 11 +++++++++++ drivers/net/wireless/ath/ath9k/mac.c | 3 ++- drivers/net/wireless/ath/ath9k/recv.c | 19 +++++++++++-------- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index d32f2828b098..a706202fa67c 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -119,6 +119,7 @@ struct ath_common { u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); + DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX); u8 splitmic; struct ath_regulatory regulatory; diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 31cfe468e3fc..2dab64bb23a8 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -372,9 +372,13 @@ int ath9k_cmn_key_config(struct ath_common *common, set_bit(idx, common->keymap); if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { set_bit(idx + 64, common->keymap); + set_bit(idx, common->tkip_keymap); + set_bit(idx + 64, common->tkip_keymap); if (common->splitmic) { set_bit(idx + 32, common->keymap); set_bit(idx + 64 + 32, common->keymap); + set_bit(idx + 32, common->tkip_keymap); + set_bit(idx + 64 + 32, common->tkip_keymap); } } @@ -399,10 +403,17 @@ void ath9k_cmn_key_delete(struct ath_common *common, return; clear_bit(key->hw_key_idx + 64, common->keymap); + + clear_bit(key->hw_key_idx, common->tkip_keymap); + clear_bit(key->hw_key_idx + 64, common->tkip_keymap); + if (common->splitmic) { ath9k_hw_keyreset(ah, key->hw_key_idx + 32); clear_bit(key->hw_key_idx + 32, common->keymap); clear_bit(key->hw_key_idx + 64 + 32, common->keymap); + + clear_bit(key->hw_key_idx + 32, common->tkip_keymap); + clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap); } } EXPORT_SYMBOL(ath9k_cmn_key_delete); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index e955bb9d98cb..0b7d1253f0c0 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -711,7 +711,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_phyerr = phyerr; } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) rs->rs_status |= ATH9K_RXERR_DECRYPT; - else if (ads.ds_rxstatus8 & AR_MichaelErr) + else if ((ads.ds_rxstatus8 & AR_MichaelErr) && + rs->rs_keyix != ATH9K_RXKEYIX_INVALID) rs->rs_status |= ATH9K_RXERR_MIC; } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a3fc987ebab0..534a91bcc1d9 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -870,15 +870,18 @@ static bool ath9k_rx_accept(struct ath_common *common, if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { *decrypt_error = true; } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) { - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - rx_stats->rs_status &= ~ATH9K_RXERR_MIC; - else + /* + * The MIC error bit is only valid if the frame + * is not a control frame or fragment, and it was + * decrypted using a valid TKIP key. + */ + if (!ieee80211_is_ctl(fc) && + !ieee80211_has_morefrags(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && + test_bit(rx_stats->rs_keyix, common->tkip_keymap)) rxs->flag |= RX_FLAG_MMIC_ERROR; + else + rx_stats->rs_status &= ~ATH9K_RXERR_MIC; } /* * Reject error frames with the exception of -- GitLab