summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/560-mac80211_defer_bar_tx.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/560-mac80211_defer_bar_tx.patch')
-rw-r--r--package/mac80211/patches/560-mac80211_defer_bar_tx.patch90
1 files changed, 90 insertions, 0 deletions
diff --git a/package/mac80211/patches/560-mac80211_defer_bar_tx.patch b/package/mac80211/patches/560-mac80211_defer_bar_tx.patch
new file mode 100644
index 000000000..9bf89183e
--- /dev/null
+++ b/package/mac80211/patches/560-mac80211_defer_bar_tx.patch
@@ -0,0 +1,90 @@
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -84,6 +84,8 @@ enum ieee80211_sta_info_flags {
+ * @stop_initiator: initiator of a session stop
+ * @tx_stop: TX DelBA frame when stopping
+ * @buf_size: reorder buffer size at receiver
++ * @failed_bar_ssn: ssn of the last failed BAR tx attempt
++ * @bar_pending: BAR needs to be re-sent
+ *
+ * This structure's lifetime is managed by RCU, assignments to
+ * the array holding it must hold the aggregation mutex.
+@@ -104,6 +106,9 @@ struct tid_ampdu_tx {
+ u8 stop_initiator;
+ bool tx_stop;
+ u8 buf_size;
++
++ u16 failed_bar_ssn;
++ bool bar_pending;
+ };
+
+ /**
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -127,12 +127,32 @@ static void ieee80211_handle_filtered_fr
+ dev_kfree_skb(skb);
+ }
+
++static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
++{
++ struct tid_ampdu_tx *tid_tx;
++
++ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
++ if (!tid_tx || !tid_tx->bar_pending)
++ return;
++
++ tid_tx->bar_pending = false;
++ ieee80211_send_bar(sta->sdata, addr, tid, tid_tx->failed_bar_ssn);
++}
++
+ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
+ {
+ struct ieee80211_mgmt *mgmt = (void *) skb->data;
+ struct ieee80211_local *local = sta->local;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+
++ if (ieee80211_is_data_qos(mgmt->frame_control)) {
++ struct ieee80211_hdr *hdr = (void *) skb->data;
++ u8 *qc = ieee80211_get_qos_ctl(hdr);
++ u16 tid = qc[0] & 0xf;
++
++ ieee80211_check_pending_bar(sta, hdr->addr1, tid);
++ }
++
+ if (ieee80211_is_action(mgmt->frame_control) &&
+ sdata->vif.type == NL80211_IFTYPE_STATION &&
+ mgmt->u.action.category == WLAN_CATEGORY_HT &&
+@@ -161,6 +181,18 @@ static void ieee80211_frame_acked(struct
+ }
+ }
+
++static void ieee80211_set_bar_pending(struct sta_info *sta, u8 tid, u16 ssn)
++{
++ struct tid_ampdu_tx *tid_tx;
++
++ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
++ if (!tid_tx)
++ return;
++
++ tid_tx->failed_bar_ssn = ssn;
++ tid_tx->bar_pending = true;
++}
++
+ /*
+ * Use a static threshold for now, best value to be determined
+ * by testing ...
+@@ -254,10 +286,13 @@ void ieee80211_tx_status(struct ieee8021
+ */
+ bar = (struct ieee80211_bar *) skb->data;
+ if (!(bar->control & IEEE80211_BAR_CTRL_MULTI_TID)) {
++ u16 ssn = le16_to_cpu(bar->start_seq_num);
++
+ tid = (bar->control &
+ IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
+ IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
+- ieee80211_stop_tx_ba_session(&sta->sta, tid);
++
++ ieee80211_set_bar_pending(sta, tid, ssn);
+ }
+ }
+