ath9k_hw: fix a regression in key miss handling
authorFelix Fietkau <nbd@openwrt.org>
Sat, 8 Oct 2011 20:02:58 +0000 (22:02 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 11 Oct 2011 20:41:29 +0000 (16:41 -0400)
The commit "ath9k_hw: Fix incorrect key_miss handling" changed the code
to only report key miss errors if a MIC error wasn't reported.
When checking the flags in that order in the MAC code, it might miss some
real events, because the value of the MIC error flag is undefined under
some conditions.

The primary issue addressed by the previous commit is making sure that
MIC errors are properly reported on the STA side. This can be fixed in
a better way by adding a separate rx status flag for key miss and
ignoring it for multicast frames.

This fix slightly improves stability in AP mode on some older hardware,
like AR9132.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Cc: stable@kernel.org
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/recv.c

index 6cabc85bf61b3c9214b3e8ba94c6c8e6b51b646b..b363cc06cfd950cd08cf42334658d9cafced6598 100644 (file)
@@ -525,8 +525,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
                        rxs->rs_status |= ATH9K_RXERR_DECRYPT;
                else if (rxsp->status11 & AR_MichaelErr)
                        rxs->rs_status |= ATH9K_RXERR_MIC;
-               else if (rxsp->status11 & AR_KeyMiss)
-                       rxs->rs_status |= ATH9K_RXERR_DECRYPT;
+               if (rxsp->status11 & AR_KeyMiss)
+                       rxs->rs_status |= ATH9K_RXERR_KEYMISS;
        }
 
        return 0;
index 835e81d8ef0e8066286cf7c3cb30302287ed63f9..6a8fdf33a5273704a61767cf0dd4c4aecd703d5b 100644 (file)
@@ -620,8 +620,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
                else if (ads.ds_rxstatus8 & AR_MichaelErr)
                        rs->rs_status |= ATH9K_RXERR_MIC;
-               else if (ads.ds_rxstatus8 & AR_KeyMiss)
-                       rs->rs_status |= ATH9K_RXERR_DECRYPT;
+               if (ads.ds_rxstatus8 & AR_KeyMiss)
+                       rs->rs_status |= ATH9K_RXERR_KEYMISS;
        }
 
        return 0;
index 736fcbee919d8495a67c369406477d0949ff4a3e..11dbd1473a13049f659b198520cba1177c80138a 100644 (file)
@@ -182,6 +182,7 @@ struct ath_htc_rx_status {
 #define ATH9K_RXERR_FIFO          0x04
 #define ATH9K_RXERR_DECRYPT       0x08
 #define ATH9K_RXERR_MIC           0x10
+#define ATH9K_RXERR_KEYMISS       0x20
 
 #define ATH9K_RX_MORE             0x01
 #define ATH9K_RX_MORE_AGGR        0x02
index 33d30792d7d7305985ad43dc5cbf6e6f9929e792..cd2722529c146d40e877a2d73b34fc942f28e130 100644 (file)
@@ -820,7 +820,8 @@ static bool ath9k_rx_accept(struct ath_common *common,
                test_bit(rx_stats->rs_keyix, common->tkip_keymap);
        strip_mic = is_valid_tkip && ieee80211_is_data(fc) &&
                !(rx_stats->rs_status &
-               (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC));
+               (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC |
+                ATH9K_RXERR_KEYMISS));
 
        if (!rx_stats->rs_datalen)
                return false;
@@ -848,6 +849,8 @@ static bool ath9k_rx_accept(struct ath_common *common,
         * descriptors.
         */
        if (rx_stats->rs_status != 0) {
+               u8 status_mask;
+
                if (rx_stats->rs_status & ATH9K_RXERR_CRC) {
                        rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
                        mic_error = false;
@@ -855,7 +858,8 @@ static bool ath9k_rx_accept(struct ath_common *common,
                if (rx_stats->rs_status & ATH9K_RXERR_PHY)
                        return false;
 
-               if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
+               if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) ||
+                   (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) {
                        *decrypt_error = true;
                        mic_error = false;
                }
@@ -865,17 +869,14 @@ static bool ath9k_rx_accept(struct ath_common *common,
                 * decryption and MIC failures. For monitor mode,
                 * we also ignore the CRC error.
                 */
-               if (ah->is_monitoring) {
-                       if (rx_stats->rs_status &
-                           ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
-                             ATH9K_RXERR_CRC))
-                               return false;
-               } else {
-                       if (rx_stats->rs_status &
-                           ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
-                               return false;
-                       }
-               }
+               status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+                             ATH9K_RXERR_KEYMISS;
+
+               if (ah->is_monitoring)
+                       status_mask |= ATH9K_RXERR_CRC;
+
+               if (rx_stats->rs_status & ~status_mask)
+                       return false;
        }
 
        /*