diff options
Diffstat (limited to 'package/mac80211/patches/560-mac80211_defer_bar_tx.patch')
-rw-r--r-- | package/mac80211/patches/560-mac80211_defer_bar_tx.patch | 90 |
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 0000000..9bf8918 --- /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); + } + } + |