aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c53
1 files changed, 45 insertions, 8 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index e51bd2a1a073..d50358c45ab0 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,
127 dev_kfree_skb(skb); 127 dev_kfree_skb(skb);
128} 128}
129 129
130static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
131{
132 struct tid_ampdu_tx *tid_tx;
133
134 tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
135 if (!tid_tx || !tid_tx->bar_pending)
136 return;
137
138 tid_tx->bar_pending = false;
139 ieee80211_send_bar(&sta->sdata->vif, addr, tid, tid_tx->failed_bar_ssn);
140}
141
130static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) 142static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
131{ 143{
132 struct ieee80211_mgmt *mgmt = (void *) skb->data; 144 struct ieee80211_mgmt *mgmt = (void *) skb->data;
133 struct ieee80211_local *local = sta->local; 145 struct ieee80211_local *local = sta->local;
134 struct ieee80211_sub_if_data *sdata = sta->sdata; 146 struct ieee80211_sub_if_data *sdata = sta->sdata;
135 147
148 if (ieee80211_is_data_qos(mgmt->frame_control)) {
149 struct ieee80211_hdr *hdr = (void *) skb->data;
150 u8 *qc = ieee80211_get_qos_ctl(hdr);
151 u16 tid = qc[0] & 0xf;
152
153 ieee80211_check_pending_bar(sta, hdr->addr1, tid);
154 }
155
136 if (ieee80211_is_action(mgmt->frame_control) && 156 if (ieee80211_is_action(mgmt->frame_control) &&
137 sdata->vif.type == NL80211_IFTYPE_STATION && 157 sdata->vif.type == NL80211_IFTYPE_STATION &&
138 mgmt->u.action.category == WLAN_CATEGORY_HT && 158 mgmt->u.action.category == WLAN_CATEGORY_HT &&
@@ -161,6 +181,18 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
161 } 181 }
162} 182}
163 183
184static void ieee80211_set_bar_pending(struct sta_info *sta, u8 tid, u16 ssn)
185{
186 struct tid_ampdu_tx *tid_tx;
187
188 tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
189 if (!tid_tx)
190 return;
191
192 tid_tx->failed_bar_ssn = ssn;
193 tid_tx->bar_pending = true;
194}
195
164/* 196/*
165 * Use a static threshold for now, best value to be determined 197 * Use a static threshold for now, best value to be determined
166 * by testing ... 198 * by testing ...
@@ -241,23 +273,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
241 tid = qc[0] & 0xf; 273 tid = qc[0] & 0xf;
242 ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10) 274 ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
243 & IEEE80211_SCTL_SEQ); 275 & IEEE80211_SCTL_SEQ);
244 ieee80211_send_bar(sta->sdata, hdr->addr1, 276 ieee80211_send_bar(&sta->sdata->vif, hdr->addr1,
245 tid, ssn); 277 tid, ssn);
246 } 278 }
247 279
248 if (!acked && ieee80211_is_back_req(fc)) { 280 if (!acked && ieee80211_is_back_req(fc)) {
281 u16 control;
282
249 /* 283 /*
250 * BAR failed, let's tear down the BA session as a 284 * BAR failed, store the last SSN and retry sending
251 * last resort as some STAs (Intel 5100 on Windows) 285 * the BAR when the next unicast transmission on the
252 * can get stuck when the BA window isn't flushed 286 * same TID succeeds.
253 * correctly.
254 */ 287 */
255 bar = (struct ieee80211_bar *) skb->data; 288 bar = (struct ieee80211_bar *) skb->data;
256 if (!(bar->control & IEEE80211_BAR_CTRL_MULTI_TID)) { 289 control = le16_to_cpu(bar->control);
257 tid = (bar->control & 290 if (!(control & IEEE80211_BAR_CTRL_MULTI_TID)) {
291 u16 ssn = le16_to_cpu(bar->start_seq_num);
292
293 tid = (control &
258 IEEE80211_BAR_CTRL_TID_INFO_MASK) >> 294 IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
259 IEEE80211_BAR_CTRL_TID_INFO_SHIFT; 295 IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
260 ieee80211_stop_tx_ba_session(&sta->sta, tid); 296
297 ieee80211_set_bar_pending(sta, tid, ssn);
261 } 298 }
262 } 299 }
263 300