diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 32 |
1 files changed, 31 insertions, 1 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); |