mac80211: QoS multicast frames have No Ack policy
authorThomas Pedersen <thomas@cozybit.com>
Fri, 4 Nov 2011 04:11:11 +0000 (21:11 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 9 Nov 2011 21:05:48 +0000 (16:05 -0500)
Previously QoS multicast frames had the Normal Acknowledgment QoS
control bits set. This would cause broadcast frames to be discarded by
peers with which we have a BA session, since their sequence number would
fall outside the allowed range. Set No Ack QoS control bits on multicast
QoS frames and filter these in de-aggregation code.

Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
v2: Use proper QoS Ack Policy ctl field mask (Christian)

v3: Clean up conditional (Johannes)
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/linux/ieee80211.h
net/mac80211/rx.c
net/mac80211/wme.c

index ffc073ab3ff85982885177037ba9c1cc7650e076..66cedf6eb5c2421b3fda7339df9290dbb1e3492e 100644 (file)
 #define IEEE80211_QOS_CTL_ACK_POLICY_NOACK     0x0020
 #define IEEE80211_QOS_CTL_ACK_POLICY_NO_EXPL   0x0040
 #define IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK  0x0060
+#define IEEE80211_QOS_CTL_ACK_POLICY_MASK      0x0060
 /* A-MSDU 802.11n */
 #define IEEE80211_QOS_CTL_A_MSDU_PRESENT       0x0080
 /* Mesh Control 802.11s */
index 3173dcfc2136e08a06bc0fe8821e8728a64de5a1..72c1eb4eb451e5d0eb84c8f9584f023a7c08b618 100644 (file)
@@ -747,7 +747,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        struct sta_info *sta = rx->sta;
        struct tid_ampdu_rx *tid_agg_rx;
        u16 sc;
-       int tid;
+       u8 tid, ack_policy;
 
        if (!ieee80211_is_data_qos(hdr->frame_control))
                goto dont_reorder;
@@ -760,6 +760,8 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        if (!sta)
                goto dont_reorder;
 
+       ack_policy = *ieee80211_get_qos_ctl(hdr) &
+                    IEEE80211_QOS_CTL_ACK_POLICY_MASK;
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
@@ -770,6 +772,11 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
                goto dont_reorder;
 
+       /* not part of a BA session */
+       if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+           ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
+               goto dont_reorder;
+
        /* new, potentially un-ordered, ampdu frame - process it */
 
        /* reset session timer */
index d0240bba45f355d27e4ce8fa6a480e0ef811d6a0..d4f789a4e4f18b7cd7f79f03f03a45bfaf962fba 100644 (file)
@@ -150,7 +150,8 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
                /* preserve EOSP bit */
                ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
 
-               if (unlikely(sdata->local->wifi_wme_noack_test))
+               if (unlikely(sdata->local->wifi_wme_noack_test) ||
+                   is_multicast_ether_addr(hdr->addr1))
                        ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
                /* qos header is 2 bytes */
                *p++ = ack_policy | tid;