aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/agg-rx.c
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-07-16 06:12:15 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-07-21 11:42:07 -0400
commit08cf42e843f9a7e253502011c81677f61f7e5c42 (patch)
tree0922a80812809c8ee2f2f64793b4754ea4b729a4 /net/mac80211/agg-rx.c
parent83eb935ec74a91468776cd86415abcb6ee23cca8 (diff)
mac80211: add support for Rx reordering offloading
Some drivers may be performing most of Tx/Rx aggregation on their own (e.g. in firmware) including AddBa/DelBa negotiations but may otherwise require Rx reordering assistance. The patch exports 2 new functions for establishing Rx aggregation sessions in assumption device driver has taken care of the necessary negotiations. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> [fix endian bug] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/agg-rx.c')
-rw-r--r--net/mac80211/agg-rx.c101
1 files changed, 78 insertions, 23 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index d38c49b644cd..f0e84bc48038 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -224,28 +224,15 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
224 ieee80211_tx_skb(sdata, skb); 224 ieee80211_tx_skb(sdata, skb);
225} 225}
226 226
227void ieee80211_process_addba_request(struct ieee80211_local *local, 227void __ieee80211_start_rx_ba_session(struct sta_info *sta,
228 struct sta_info *sta, 228 u8 dialog_token, u16 timeout,
229 struct ieee80211_mgmt *mgmt, 229 u16 start_seq_num, u16 ba_policy, u16 tid,
230 size_t len) 230 u16 buf_size, bool tx)
231{ 231{
232 struct ieee80211_local *local = sta->sdata->local;
232 struct tid_ampdu_rx *tid_agg_rx; 233 struct tid_ampdu_rx *tid_agg_rx;
233 u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
234 u8 dialog_token;
235 int i, ret = -EOPNOTSUPP; 234 int i, ret = -EOPNOTSUPP;
236 235 u16 status = WLAN_STATUS_REQUEST_DECLINED;
237 /* extract session parameters from addba request frame */
238 dialog_token = mgmt->u.action.u.addba_req.dialog_token;
239 timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
240 start_seq_num =
241 le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
242
243 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
244 ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
245 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
246 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
247
248 status = WLAN_STATUS_REQUEST_DECLINED;
249 236
250 if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { 237 if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
251 ht_dbg(sta->sdata, 238 ht_dbg(sta->sdata,
@@ -264,7 +251,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
264 status = WLAN_STATUS_INVALID_QOS_PARAM; 251 status = WLAN_STATUS_INVALID_QOS_PARAM;
265 ht_dbg_ratelimited(sta->sdata, 252 ht_dbg_ratelimited(sta->sdata,
266 "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", 253 "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
267 mgmt->sa, tid, ba_policy, buf_size); 254 sta->sta.addr, tid, ba_policy, buf_size);
268 goto end_no_lock; 255 goto end_no_lock;
269 } 256 }
270 /* determine default buffer size */ 257 /* determine default buffer size */
@@ -281,7 +268,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
281 if (sta->ampdu_mlme.tid_rx[tid]) { 268 if (sta->ampdu_mlme.tid_rx[tid]) {
282 ht_dbg_ratelimited(sta->sdata, 269 ht_dbg_ratelimited(sta->sdata,
283 "unexpected AddBA Req from %pM on tid %u\n", 270 "unexpected AddBA Req from %pM on tid %u\n",
284 mgmt->sa, tid); 271 sta->sta.addr, tid);
285 272
286 /* delete existing Rx BA session on the same tid */ 273 /* delete existing Rx BA session on the same tid */
287 ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 274 ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
@@ -353,6 +340,74 @@ end:
353 mutex_unlock(&sta->ampdu_mlme.mtx); 340 mutex_unlock(&sta->ampdu_mlme.mtx);
354 341
355end_no_lock: 342end_no_lock:
356 ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, 343 if (tx)
357 dialog_token, status, 1, buf_size, timeout); 344 ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
345 dialog_token, status, 1, buf_size,
346 timeout);
347}
348
349void ieee80211_process_addba_request(struct ieee80211_local *local,
350 struct sta_info *sta,
351 struct ieee80211_mgmt *mgmt,
352 size_t len)
353{
354 u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
355 u8 dialog_token;
356
357 /* extract session parameters from addba request frame */
358 dialog_token = mgmt->u.action.u.addba_req.dialog_token;
359 timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
360 start_seq_num =
361 le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
362
363 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
364 ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
365 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
366 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
367
368 __ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
369 start_seq_num, ba_policy, tid,
370 buf_size, true);
371}
372
373void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif,
374 const u8 *addr, u16 tid)
375{
376 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
377 struct ieee80211_local *local = sdata->local;
378 struct ieee80211_rx_agg *rx_agg;
379 struct sk_buff *skb = dev_alloc_skb(0);
380
381 if (unlikely(!skb))
382 return;
383
384 rx_agg = (struct ieee80211_rx_agg *) &skb->cb;
385 memcpy(&rx_agg->addr, addr, ETH_ALEN);
386 rx_agg->tid = tid;
387
388 skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_START;
389 skb_queue_tail(&sdata->skb_queue, skb);
390 ieee80211_queue_work(&local->hw, &sdata->work);
391}
392EXPORT_SYMBOL(ieee80211_start_rx_ba_session_offl);
393
394void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif,
395 const u8 *addr, u16 tid)
396{
397 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
398 struct ieee80211_local *local = sdata->local;
399 struct ieee80211_rx_agg *rx_agg;
400 struct sk_buff *skb = dev_alloc_skb(0);
401
402 if (unlikely(!skb))
403 return;
404
405 rx_agg = (struct ieee80211_rx_agg *) &skb->cb;
406 memcpy(&rx_agg->addr, addr, ETH_ALEN);
407 rx_agg->tid = tid;
408
409 skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_STOP;
410 skb_queue_tail(&sdata->skb_queue, skb);
411 ieee80211_queue_work(&local->hw, &sdata->work);
358} 412}
413EXPORT_SYMBOL(ieee80211_stop_rx_ba_session_offl);