Commit 8f236d1b authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

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: default avatarChristian Lamparter <chunkeey@googlemail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 9f59f3c6
...@@ -576,6 +576,41 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) ...@@ -576,6 +576,41 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
} }
} }
static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms)
{
__le16 fc;
if ((ms & AR9170_RX_STATUS_MPDU) == AR9170_RX_STATUS_MPDU_SINGLE) {
/*
* This frame is not part of an aMPDU.
* Therefore it is not subjected to any
* of the following content restrictions.
*/
return true;
}
/*
* "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts
* certain frame types can be part of an aMPDU.
*
* In order to keep the processing cost down, I opted for a
* stateless filter solely based on the frame control field.
*/
fc = ((struct ieee80211_hdr *)buf)->frame_control;
if (ieee80211_is_data_qos(fc) && ieee80211_is_data_present(fc))
return true;
if (ieee80211_is_ack(fc) || ieee80211_is_back(fc) ||
ieee80211_is_back_req(fc))
return true;
if (ieee80211_is_action(fc))
return true;
return false;
}
/* /*
* If the frame alignment is right (or the kernel has * If the frame alignment is right (or the kernel has
* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
...@@ -594,6 +629,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) ...@@ -594,6 +629,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
struct ieee80211_rx_status status; struct ieee80211_rx_status status;
struct sk_buff *skb; struct sk_buff *skb;
int mpdu_len; int mpdu_len;
u8 mac_status;
if (!IS_STARTED(ar)) if (!IS_STARTED(ar))
return; return;
...@@ -604,7 +640,8 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) ...@@ -604,7 +640,8 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
mpdu_len = len - sizeof(*mac); mpdu_len = len - sizeof(*mac);
mac = (void *)(buf + mpdu_len); mac = (void *)(buf + mpdu_len);
switch (mac->status & AR9170_RX_STATUS_MPDU) { mac_status = mac->status;
switch (mac_status & AR9170_RX_STATUS_MPDU) {
case AR9170_RX_STATUS_MPDU_FIRST: case AR9170_RX_STATUS_MPDU_FIRST:
/* Aggregated MPDUs start with an PLCP header */ /* Aggregated MPDUs start with an PLCP header */
if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { 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,6 +730,9 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status)))
goto drop; goto drop;
if (!carl9170_ampdu_check(ar, buf, mac_status))
goto drop;
if (phy) if (phy)
carl9170_rx_phy_status(ar, phy, &status); carl9170_rx_phy_status(ar, phy, &status);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment