diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-07-13 11:35:05 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-07-15 13:38:32 -0400 |
commit | 66760eac005d569393bac34136bcbb8af55d8a5a (patch) | |
tree | e1aabd62a59c42cebec3e208edd4198382c91a16 | |
parent | 933d594313a5928ffc5325d7bbb6e2383d79622e (diff) |
ath9k: improve reliability of MIC error detection
For unicast the hardware sometimes reports MIC errors even though the
frame that it received actually contains a valid MIC - on some chips this
can happen frequently enough to trigger TKIP countermeasures.
Fix this issue by not reporting MIC errors for unicast frames with a
valid key, letting mac80211 validate the MIC instead.
Additionally, strip the MIC for all frames that the hardware considers
valid to avoid wasting CPU cycles re-validating it.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 80bb04f950eb..d32e82ff9283 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -814,16 +814,19 @@ static bool ath9k_rx_accept(struct ath_common *common, | |||
814 | struct ath_rx_status *rx_stats, | 814 | struct ath_rx_status *rx_stats, |
815 | bool *decrypt_error) | 815 | bool *decrypt_error) |
816 | { | 816 | { |
817 | #define is_mc_or_valid_tkip_keyix ((is_mc || \ | 817 | bool is_mc, is_valid_tkip, strip_mic, mic_error; |
818 | (rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && \ | ||
819 | test_bit(rx_stats->rs_keyix, common->tkip_keymap)))) | ||
820 | |||
821 | struct ath_hw *ah = common->ah; | 818 | struct ath_hw *ah = common->ah; |
822 | __le16 fc; | 819 | __le16 fc; |
823 | u8 rx_status_len = ah->caps.rx_status_len; | 820 | u8 rx_status_len = ah->caps.rx_status_len; |
824 | 821 | ||
825 | fc = hdr->frame_control; | 822 | fc = hdr->frame_control; |
826 | 823 | ||
824 | is_mc = !!is_multicast_ether_addr(hdr->addr1); | ||
825 | is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && | ||
826 | test_bit(rx_stats->rs_keyix, common->tkip_keymap); | ||
827 | strip_mic = is_valid_tkip && !(rx_stats->rs_status & | ||
828 | (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC)); | ||
829 | |||
827 | if (!rx_stats->rs_datalen) | 830 | if (!rx_stats->rs_datalen) |
828 | return false; | 831 | return false; |
829 | /* | 832 | /* |
@@ -838,6 +841,11 @@ static bool ath9k_rx_accept(struct ath_common *common, | |||
838 | if (rx_stats->rs_more) | 841 | if (rx_stats->rs_more) |
839 | return true; | 842 | return true; |
840 | 843 | ||
844 | mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && | ||
845 | !ieee80211_has_morefrags(fc) && | ||
846 | !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && | ||
847 | (rx_stats->rs_status & ATH9K_RXERR_MIC); | ||
848 | |||
841 | /* | 849 | /* |
842 | * The rx_stats->rs_status will not be set until the end of the | 850 | * The rx_stats->rs_status will not be set until the end of the |
843 | * chained descriptors so it can be ignored if rs_more is set. The | 851 | * chained descriptors so it can be ignored if rs_more is set. The |
@@ -845,30 +853,18 @@ static bool ath9k_rx_accept(struct ath_common *common, | |||
845 | * descriptors. | 853 | * descriptors. |
846 | */ | 854 | */ |
847 | if (rx_stats->rs_status != 0) { | 855 | if (rx_stats->rs_status != 0) { |
848 | if (rx_stats->rs_status & ATH9K_RXERR_CRC) | 856 | if (rx_stats->rs_status & ATH9K_RXERR_CRC) { |
849 | rxs->flag |= RX_FLAG_FAILED_FCS_CRC; | 857 | rxs->flag |= RX_FLAG_FAILED_FCS_CRC; |
858 | mic_error = false; | ||
859 | } | ||
850 | if (rx_stats->rs_status & ATH9K_RXERR_PHY) | 860 | if (rx_stats->rs_status & ATH9K_RXERR_PHY) |
851 | return false; | 861 | return false; |
852 | 862 | ||
853 | if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { | 863 | if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { |
854 | *decrypt_error = true; | 864 | *decrypt_error = true; |
855 | } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) { | 865 | mic_error = false; |
856 | bool is_mc; | ||
857 | /* | ||
858 | * The MIC error bit is only valid if the frame | ||
859 | * is not a control frame or fragment, and it was | ||
860 | * decrypted using a valid TKIP key. | ||
861 | */ | ||
862 | is_mc = !!is_multicast_ether_addr(hdr->addr1); | ||
863 | |||
864 | if (!ieee80211_is_ctl(fc) && | ||
865 | !ieee80211_has_morefrags(fc) && | ||
866 | !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && | ||
867 | is_mc_or_valid_tkip_keyix) | ||
868 | rxs->flag |= RX_FLAG_MMIC_ERROR; | ||
869 | else | ||
870 | rx_stats->rs_status &= ~ATH9K_RXERR_MIC; | ||
871 | } | 866 | } |
867 | |||
872 | /* | 868 | /* |
873 | * Reject error frames with the exception of | 869 | * Reject error frames with the exception of |
874 | * decryption and MIC failures. For monitor mode, | 870 | * decryption and MIC failures. For monitor mode, |
@@ -886,6 +882,18 @@ static bool ath9k_rx_accept(struct ath_common *common, | |||
886 | } | 882 | } |
887 | } | 883 | } |
888 | } | 884 | } |
885 | |||
886 | /* | ||
887 | * For unicast frames the MIC error bit can have false positives, | ||
888 | * so all MIC error reports need to be validated in software. | ||
889 | * False negatives are not common, so skip software verification | ||
890 | * if the hardware considers the MIC valid. | ||
891 | */ | ||
892 | if (strip_mic) | ||
893 | rxs->flag |= RX_FLAG_MMIC_STRIPPED; | ||
894 | else if (is_mc && mic_error) | ||
895 | rxs->flag |= RX_FLAG_MMIC_ERROR; | ||
896 | |||
889 | return true; | 897 | return true; |
890 | } | 898 | } |
891 | 899 | ||
@@ -1938,6 +1946,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | |||
1938 | sc->rx.rxotherant = 0; | 1946 | sc->rx.rxotherant = 0; |
1939 | } | 1947 | } |
1940 | 1948 | ||
1949 | if (rxs->flag & RX_FLAG_MMIC_STRIPPED) | ||
1950 | skb_trim(skb, skb->len - 8); | ||
1951 | |||
1941 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | 1952 | spin_lock_irqsave(&sc->sc_pm_lock, flags); |
1942 | 1953 | ||
1943 | if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | | 1954 | if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | |