ath9k: detect more kinds of invalid descriptors
authorFelix Fietkau <nbd@openwrt.org>
Sun, 7 Apr 2013 22:04:12 +0000 (00:04 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 10 Apr 2013 18:10:33 +0000 (14:10 -0400)
If AR_CRCErr, AR_PHYErr, AR_DecryptCRCErr or AR_MichaelErr is indicated
in the rx status word, but AR_RxFrameOK is also set, the descriptor
contents are typically invalid. This can show up as a warning about
invalid MCS rates in a frame. Even with those checks in place, a
descriptor with invalid MCS rates can still sometimes make it through to
the driver (mostly on older hardware like AR91xx).

Detect such errors in the last descriptor of a frame and discard the
whole frame if present.

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

index 811007e..498fee0 100644 (file)
@@ -615,6 +615,14 @@ 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_CRCErr | AR_PHYErr | AR_DecryptCRCErr | AR_MichaelErr))
+                       rs->rs_status |= ATH9K_RXERR_CORRUPT_DESC;
+
+               /* Only up to MCS16 supported, everything above is invalid */
+               if (rs->rs_rate >= 0x90)
+                       rs->rs_status |= ATH9K_RXERR_CORRUPT_DESC;
        }
 
        if (ads.ds_rxstatus8 & AR_KeyMiss)
index 1ff8170..5865f92 100644 (file)
@@ -183,6 +183,7 @@ struct ath_htc_rx_status {
 #define ATH9K_RXERR_DECRYPT       0x08
 #define ATH9K_RXERR_MIC           0x10
 #define ATH9K_RXERR_KEYMISS       0x20
+#define ATH9K_RXERR_CORRUPT_DESC  0x40
 
 #define ATH9K_RX_MORE             0x01
 #define ATH9K_RX_MORE_AGGR        0x02
index c593a3e..ebb8d36 100644 (file)
@@ -1319,6 +1319,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                        sc->rx.frag = skb;
                        goto requeue;
                }
+               if (rs.rs_status & ATH9K_RXERR_CORRUPT_DESC)
+                       goto requeue_drop_frag;
 
                if (sc->rx.frag) {
                        int space = skb->len - skb_tailroom(hdr_skb);