ath9k: fix spurious MIC failure detection, causing instability issues in AP mode
authorFelix Fietkau <nbd@openwrt.org>
Wed, 25 Aug 2010 12:30:50 +0000 (12:30 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Wed, 25 Aug 2010 12:30:50 +0000 (12:30 +0000)
SVN-Revision: 22795

package/mac80211/patches/570-ath9k_mic_failure_fix.patch [new file with mode: 0644]

diff --git a/package/mac80211/patches/570-ath9k_mic_failure_fix.patch b/package/mac80211/patches/570-ath9k_mic_failure_fix.patch
new file mode 100644 (file)
index 0000000..73c6347
--- /dev/null
@@ -0,0 +1,74 @@
+--- 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;
+--- a/drivers/net/wireless/ath/ath9k/common.c
++++ b/drivers/net/wireless/ath/ath9k/common.c
+@@ -366,9 +366,13 @@ int ath9k_cmn_key_config(struct ath_comm
+       set_bit(idx, common->keymap);
+       if (key->alg == ALG_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);
+               }
+       }
+@@ -393,10 +397,17 @@ void ath9k_cmn_key_delete(struct ath_com
+               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);
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -870,15 +870,19 @@ static bool ath9k_rx_accept(struct ath_c
+               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, and it was decrypted using
++                       * a TKIP key.
++                       */
++                      if (!ieee80211_is_ctl(fc) &&
++                          rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID &&
++                          test_bit(rx_stats->rs_keyix, common->tkip_keymap)) {
+                               rxs->flag |= RX_FLAG_MMIC_ERROR;
++                      } else {
++                              rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
++                              *decrypt_error = true;
++                      }
+               }
+               /*
+                * Reject error frames with the exception of