Skip to content

Commit

Permalink
ath9k: fix spurious MIC failure reports
Browse files Browse the repository at this point in the history
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 <nbd@openwrt.org>
Cc: stable@kernel.org
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Felix Fietkau authored and John W. Linville committed Aug 31, 2010
1 parent 3653910 commit 56363dd
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 9 deletions.
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions drivers/net/wireless/ath/ath9k/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/wireless/ath/ath9k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
19 changes: 11 additions & 8 deletions drivers/net/wireless/ath/ath9k/recv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 56363dd

Please sign in to comment.