aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-06-10 04:21:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-14 15:39:27 -0400
commit344eec67c7b8557234e149d254bca2ae9614d61e (patch)
treea7243e1f8c67adf535be457b4ccccb212259f41c /net/mac80211
parentbed7ee6e44cb7633a4f9821688a6c7ae977615ed (diff)
mac80211: move blockack stop due to fragmentation
There's a corner case where we receive a fragmented frame during a blockack session, in which case we will terminate that session. To simplify future work in this area that will culminate in allowing the driver callbacks for aggregation to sleep, move the processing of this case out of the RX path into the interface work. This will simplify future work because the new place for this code doesn't require that the function will always be atomic, which the RX path needs. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/iface.c32
-rw-r--r--net/mac80211/rx.c5
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