diff options
author | Christian Lamparter <chunkeey@googlemail.com> | 2010-10-09 19:15:07 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-11 15:04:23 -0400 |
commit | 8f236d1bef659ca69c912536a69b3031e5ba3269 (patch) | |
tree | 84698876160061a099bd9709f6bc660b1e1d0ffd /drivers/net/wireless/ath/carl9170/rx.c | |
parent | 9f59f3c694c184c69e0be7d0fd0829bcb61b0429 (diff) |
carl9170: A-MPDU frame type filter
In the past, carl9170 has been plagued by mysterious
ghosts.
e.g.:
wlan4: deauthenticated from 02:04:d8:3c:ac:c1 (Reason: 0)
Apparently, the AP sent us a bogus deauthentication
notification. But upon closer inspection the
"management frame" turned out to be a corrupted
scrap of an unsuccessful A-MPDU.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/carl9170/rx.c')
-rw-r--r-- | drivers/net/wireless/ath/carl9170/rx.c | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 256dd42bb4ab..939a0e96ed1f 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c | |||
@@ -576,6 +576,41 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) | |||
576 | } | 576 | } |
577 | } | 577 | } |
578 | 578 | ||
579 | static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) | ||
580 | { | ||
581 | __le16 fc; | ||
582 | |||
583 | if ((ms & AR9170_RX_STATUS_MPDU) == AR9170_RX_STATUS_MPDU_SINGLE) { | ||
584 | /* | ||
585 | * This frame is not part of an aMPDU. | ||
586 | * Therefore it is not subjected to any | ||
587 | * of the following content restrictions. | ||
588 | */ | ||
589 | return true; | ||
590 | } | ||
591 | |||
592 | /* | ||
593 | * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts | ||
594 | * certain frame types can be part of an aMPDU. | ||
595 | * | ||
596 | * In order to keep the processing cost down, I opted for a | ||
597 | * stateless filter solely based on the frame control field. | ||
598 | */ | ||
599 | |||
600 | fc = ((struct ieee80211_hdr *)buf)->frame_control; | ||
601 | if (ieee80211_is_data_qos(fc) && ieee80211_is_data_present(fc)) | ||
602 | return true; | ||
603 | |||
604 | if (ieee80211_is_ack(fc) || ieee80211_is_back(fc) || | ||
605 | ieee80211_is_back_req(fc)) | ||
606 | return true; | ||
607 | |||
608 | if (ieee80211_is_action(fc)) | ||
609 | return true; | ||
610 | |||
611 | return false; | ||
612 | } | ||
613 | |||
579 | /* | 614 | /* |
580 | * If the frame alignment is right (or the kernel has | 615 | * If the frame alignment is right (or the kernel has |
581 | * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there | 616 | * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there |
@@ -594,6 +629,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | |||
594 | struct ieee80211_rx_status status; | 629 | struct ieee80211_rx_status status; |
595 | struct sk_buff *skb; | 630 | struct sk_buff *skb; |
596 | int mpdu_len; | 631 | int mpdu_len; |
632 | u8 mac_status; | ||
597 | 633 | ||
598 | if (!IS_STARTED(ar)) | 634 | if (!IS_STARTED(ar)) |
599 | return; | 635 | return; |
@@ -604,7 +640,8 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | |||
604 | mpdu_len = len - sizeof(*mac); | 640 | mpdu_len = len - sizeof(*mac); |
605 | 641 | ||
606 | mac = (void *)(buf + mpdu_len); | 642 | mac = (void *)(buf + mpdu_len); |
607 | switch (mac->status & AR9170_RX_STATUS_MPDU) { | 643 | mac_status = mac->status; |
644 | switch (mac_status & AR9170_RX_STATUS_MPDU) { | ||
608 | case AR9170_RX_STATUS_MPDU_FIRST: | 645 | case AR9170_RX_STATUS_MPDU_FIRST: |
609 | /* Aggregated MPDUs start with an PLCP header */ | 646 | /* Aggregated MPDUs start with an PLCP header */ |
610 | if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { | 647 | if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { |
@@ -693,6 +730,9 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | |||
693 | if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) | 730 | if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) |
694 | goto drop; | 731 | goto drop; |
695 | 732 | ||
733 | if (!carl9170_ampdu_check(ar, buf, mac_status)) | ||
734 | goto drop; | ||
735 | |||
696 | if (phy) | 736 | if (phy) |
697 | carl9170_rx_phy_status(ar, phy, &status); | 737 | carl9170_rx_phy_status(ar, phy, &status); |
698 | 738 | ||