summaryrefslogtreecommitdiff
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2011-08-28 21:11:01 +0200
committerJohn W. Linville <linville@tuxdriver.com>2011-09-13 15:42:30 -0400
commitf0425beda4d404a6e751439b562100b902ba9c98 (patch)
tree5a8966c3172557e80fa0a4903ade8a76e5d21415 /net/mac80211/status.c
parent765b07e46725287ceb1be648b6cb5988fbb585f2 (diff)
mac80211: retry sending failed BAR frames later instead of tearing down aggr
Unfortunately failed BAR tx attempts happen more frequently than I expected, and the resulting aggregation teardowns cause performance issues, as the aggregation session does not always get re-established properly. Instead of tearing down the entire aggr session, we can simply store the SSN of the last failed BAR tx attempt, wait for the first successful tx status event, and then send another BAR with the same SSN. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Cc: Helmut Schaa <helmut.schaa@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index e51bd2a1a073..ba405bc4f812 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -127,12 +127,32 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
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 sta_info *sta, struct sk_buff *skb)
}
}
+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 ieee80211_hw *hw, struct sk_buff *skb)
*/
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);
}
}