diff options
-rw-r--r-- | net/mac80211/agg-tx.c | 76 |
1 files changed, 51 insertions, 25 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 73abff956548..61bb7db04808 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -18,6 +18,31 @@ | |||
18 | #include "ieee80211_i.h" | 18 | #include "ieee80211_i.h" |
19 | #include "wme.h" | 19 | #include "wme.h" |
20 | 20 | ||
21 | /** | ||
22 | * DOC: TX aggregation | ||
23 | * | ||
24 | * Aggregation on the TX side requires setting the hardware flag | ||
25 | * %IEEE80211_HW_AMPDU_AGGREGATION as well as, if present, the @ampdu_queues | ||
26 | * hardware parameter to the number of hardware AMPDU queues. If there are no | ||
27 | * hardware queues then the driver will (currently) have to do all frame | ||
28 | * buffering. | ||
29 | * | ||
30 | * When TX aggregation is started by some subsystem (usually the rate control | ||
31 | * algorithm would be appropriate) by calling the | ||
32 | * ieee80211_start_tx_ba_session() function, the driver will be notified via | ||
33 | * its @ampdu_action function, with the %IEEE80211_AMPDU_TX_START action. | ||
34 | * | ||
35 | * In response to that, the driver is later required to call the | ||
36 | * ieee80211_start_tx_ba_cb() (or ieee80211_start_tx_ba_cb_irqsafe()) | ||
37 | * function, which will start the aggregation session. | ||
38 | * | ||
39 | * Similarly, when the aggregation session is stopped by | ||
40 | * ieee80211_stop_tx_ba_session(), the driver's @ampdu_action function will | ||
41 | * be called with the action %IEEE80211_AMPDU_TX_STOP. In this case, the | ||
42 | * call must not fail, and the driver must later call ieee80211_stop_tx_ba_cb() | ||
43 | * (or ieee80211_stop_tx_ba_cb_irqsafe()). | ||
44 | */ | ||
45 | |||
21 | static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | 46 | static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, |
22 | const u8 *da, u16 tid, | 47 | const u8 *da, u16 tid, |
23 | u8 dialog_token, u16 start_seq_num, | 48 | u8 dialog_token, u16 start_seq_num, |
@@ -363,6 +388,31 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
363 | } | 388 | } |
364 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | 389 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); |
365 | 390 | ||
391 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
392 | const u8 *ra, u16 tid) | ||
393 | { | ||
394 | struct ieee80211_local *local = hw_to_local(hw); | ||
395 | struct ieee80211_ra_tid *ra_tid; | ||
396 | struct sk_buff *skb = dev_alloc_skb(0); | ||
397 | |||
398 | if (unlikely(!skb)) { | ||
399 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
400 | if (net_ratelimit()) | ||
401 | printk(KERN_WARNING "%s: Not enough memory, " | ||
402 | "dropping start BA session", skb->dev->name); | ||
403 | #endif | ||
404 | return; | ||
405 | } | ||
406 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
407 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
408 | ra_tid->tid = tid; | ||
409 | |||
410 | skb->pkt_type = IEEE80211_ADDBA_MSG; | ||
411 | skb_queue_tail(&local->skb_queue, skb); | ||
412 | tasklet_schedule(&local->tasklet); | ||
413 | } | ||
414 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | ||
415 | |||
366 | 416 | ||
367 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | 417 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, |
368 | u8 *ra, u16 tid, | 418 | u8 *ra, u16 tid, |
@@ -492,31 +542,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
492 | } | 542 | } |
493 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | 543 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); |
494 | 544 | ||
495 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
496 | const u8 *ra, u16 tid) | ||
497 | { | ||
498 | struct ieee80211_local *local = hw_to_local(hw); | ||
499 | struct ieee80211_ra_tid *ra_tid; | ||
500 | struct sk_buff *skb = dev_alloc_skb(0); | ||
501 | |||
502 | if (unlikely(!skb)) { | ||
503 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
504 | if (net_ratelimit()) | ||
505 | printk(KERN_WARNING "%s: Not enough memory, " | ||
506 | "dropping start BA session", skb->dev->name); | ||
507 | #endif | ||
508 | return; | ||
509 | } | ||
510 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
511 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
512 | ra_tid->tid = tid; | ||
513 | |||
514 | skb->pkt_type = IEEE80211_ADDBA_MSG; | ||
515 | skb_queue_tail(&local->skb_queue, skb); | ||
516 | tasklet_schedule(&local->tasklet); | ||
517 | } | ||
518 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | ||
519 | |||
520 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | 545 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, |
521 | const u8 *ra, u16 tid) | 546 | const u8 *ra, u16 tid) |
522 | { | 547 | { |
@@ -542,6 +567,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | |||
542 | } | 567 | } |
543 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); | 568 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); |
544 | 569 | ||
570 | |||
545 | void ieee80211_process_addba_resp(struct ieee80211_local *local, | 571 | void ieee80211_process_addba_resp(struct ieee80211_local *local, |
546 | struct sta_info *sta, | 572 | struct sta_info *sta, |
547 | struct ieee80211_mgmt *mgmt, | 573 | struct ieee80211_mgmt *mgmt, |