diff options
-rw-r--r-- | net/mac80211/iface.c | 32 | ||||
-rw-r--r-- | net/mac80211/rx.c | 5 |
2 files changed, 33 insertions, 4 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7a3dbde9979e..87fc012e4ab3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -707,6 +707,7 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
707 | container_of(work, struct ieee80211_sub_if_data, work); | 707 | container_of(work, struct ieee80211_sub_if_data, work); |
708 | struct ieee80211_local *local = sdata->local; | 708 | struct ieee80211_local *local = sdata->local; |
709 | struct sk_buff *skb; | 709 | struct sk_buff *skb; |
710 | struct sta_info *sta; | ||
710 | 711 | ||
711 | if (!ieee80211_sdata_running(sdata)) | 712 | if (!ieee80211_sdata_running(sdata)) |
712 | return; | 713 | return; |
@@ -729,7 +730,6 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
729 | if (ieee80211_is_action(mgmt->frame_control) && | 730 | if (ieee80211_is_action(mgmt->frame_control) && |
730 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { | 731 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { |
731 | int len = skb->len; | 732 | int len = skb->len; |
732 | struct sta_info *sta; | ||
733 | 733 | ||
734 | rcu_read_lock(); | 734 | rcu_read_lock(); |
735 | sta = sta_info_get(sdata, mgmt->sa); | 735 | sta = sta_info_get(sdata, mgmt->sa); |
@@ -753,6 +753,36 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
753 | } | 753 | } |
754 | } | 754 | } |
755 | rcu_read_unlock(); | 755 | rcu_read_unlock(); |
756 | } else if (ieee80211_is_data_qos(mgmt->frame_control)) { | ||
757 | struct ieee80211_hdr *hdr = (void *)mgmt; | ||
758 | /* | ||
759 | * So the frame isn't mgmt, but frame_control | ||
760 | * is at the right place anyway, of course, so | ||
761 | * the if statement is correct. | ||
762 | * | ||
763 | * Warn if we have other data frame types here, | ||
764 | * they must not get here. | ||
765 | */ | ||
766 | WARN_ON(hdr->frame_control & | ||
767 | cpu_to_le16(IEEE80211_STYPE_NULLFUNC)); | ||
768 | WARN_ON(!(hdr->seq_ctrl & | ||
769 | cpu_to_le16(IEEE80211_SCTL_FRAG))); | ||
770 | /* | ||
771 | * This was a fragment of a frame, received while | ||
772 | * a block-ack session was active. That cannot be | ||
773 | * right, so terminate the session. | ||
774 | */ | ||
775 | rcu_read_lock(); | ||
776 | sta = sta_info_get(sdata, mgmt->sa); | ||
777 | if (sta) { | ||
778 | u16 tid = *ieee80211_get_qos_ctl(hdr) & | ||
779 | IEEE80211_QOS_CTL_TID_MASK; | ||
780 | |||
781 | __ieee80211_stop_rx_ba_session( | ||
782 | sta, tid, WLAN_BACK_RECIPIENT, | ||
783 | WLAN_REASON_QSTA_REQUIRE_SETUP); | ||
784 | } | ||
785 | rcu_read_unlock(); | ||
756 | } else switch (sdata->vif.type) { | 786 | } else switch (sdata->vif.type) { |
757 | case NL80211_IFTYPE_STATION: | 787 | case NL80211_IFTYPE_STATION: |
758 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | 788 | ieee80211_sta_rx_queued_mgmt(sdata, skb); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 435c2166e0c5..b716fa2370b3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -741,9 +741,8 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
741 | sc = le16_to_cpu(hdr->seq_ctrl); | 741 | sc = le16_to_cpu(hdr->seq_ctrl); |
742 | if (sc & IEEE80211_SCTL_FRAG) { | 742 | if (sc & IEEE80211_SCTL_FRAG) { |
743 | spin_unlock(&sta->lock); | 743 | spin_unlock(&sta->lock); |
744 | __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, | 744 | skb_queue_tail(&rx->sdata->skb_queue, skb); |
745 | WLAN_REASON_QSTA_REQUIRE_SETUP); | 745 | ieee80211_queue_work(&local->hw, &rx->sdata->work); |
746 | dev_kfree_skb(skb); | ||
747 | return; | 746 | return; |
748 | } | 747 | } |
749 | 748 | ||