diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-07-16 06:12:15 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-07-21 11:42:07 -0400 |
commit | 08cf42e843f9a7e253502011c81677f61f7e5c42 (patch) | |
tree | 0922a80812809c8ee2f2f64793b4754ea4b729a4 /net/mac80211/agg-rx.c | |
parent | 83eb935ec74a91468776cd86415abcb6ee23cca8 (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.c | 101 |
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 | ||
227 | void ieee80211_process_addba_request(struct ieee80211_local *local, | 227 | void __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 | ||
355 | end_no_lock: | 342 | end_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 | |||
349 | void 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 | |||
373 | void 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 | } | ||
392 | EXPORT_SYMBOL(ieee80211_start_rx_ba_session_offl); | ||
393 | |||
394 | void 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 | } |
413 | EXPORT_SYMBOL(ieee80211_stop_rx_ba_session_offl); | ||