diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-01-18 07:51:05 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-01-19 11:36:11 -0500 |
commit | 0b01f030d38e00650e2db42da083d8647aad40a5 (patch) | |
tree | 14519750d9b6cdb046624dd87d5323a4826821e2 /net | |
parent | ac1bd8464f161ed1475ef73c431b926256c6b5bb (diff) |
mac80211: track receiver's aggregation reorder buffer size
The aggregation code currently doesn't implement the
buffer size negotiation. It will always request a max
buffer size (which is fine, if a little pointless, as
the mac80211 code doesn't know and might just use 0
instead), but if the peer requests a smaller size it
isn't possible to honour this request.
In order to fix this, look at the buffer size in the
addBA response frame, keep track of it and pass it to
the driver in the ampdu_action callback when called
with the IEEE80211_AMPDU_TX_OPERATIONAL action. That
way the driver can limit the number of subframes in
aggregates appropriately.
Note that this doesn't fix any drivers apart from the
addition of the new argument -- they all need to be
updated separately to use this variable!
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/agg-rx.c | 4 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 20 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 6 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 11 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 2 |
5 files changed, 31 insertions, 12 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 002db5e86eb6..1f51f4162426 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -76,7 +76,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
76 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 76 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
77 | 77 | ||
78 | if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, | 78 | if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, |
79 | &sta->sta, tid, NULL)) | 79 | &sta->sta, tid, NULL, 0)) |
80 | printk(KERN_DEBUG "HW problem - can not stop rx " | 80 | printk(KERN_DEBUG "HW problem - can not stop rx " |
81 | "aggregation for tid %d\n", tid); | 81 | "aggregation for tid %d\n", tid); |
82 | 82 | ||
@@ -297,7 +297,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
297 | } | 297 | } |
298 | 298 | ||
299 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, | 299 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, |
300 | &sta->sta, tid, &start_seq_num); | 300 | &sta->sta, tid, &start_seq_num, 0); |
301 | #ifdef CONFIG_MAC80211_HT_DEBUG | 301 | #ifdef CONFIG_MAC80211_HT_DEBUG |
302 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); | 302 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); |
303 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 303 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 9cc472c6a6a5..42f7c9007331 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -190,7 +190,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
190 | 190 | ||
191 | ret = drv_ampdu_action(local, sta->sdata, | 191 | ret = drv_ampdu_action(local, sta->sdata, |
192 | IEEE80211_AMPDU_TX_STOP, | 192 | IEEE80211_AMPDU_TX_STOP, |
193 | &sta->sta, tid, NULL); | 193 | &sta->sta, tid, NULL, 0); |
194 | 194 | ||
195 | /* HW shall not deny going back to legacy */ | 195 | /* HW shall not deny going back to legacy */ |
196 | if (WARN_ON(ret)) { | 196 | if (WARN_ON(ret)) { |
@@ -311,7 +311,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
311 | start_seq_num = sta->tid_seq[tid] >> 4; | 311 | start_seq_num = sta->tid_seq[tid] >> 4; |
312 | 312 | ||
313 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, | 313 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, |
314 | &sta->sta, tid, &start_seq_num); | 314 | &sta->sta, tid, &start_seq_num, 0); |
315 | if (ret) { | 315 | if (ret) { |
316 | #ifdef CONFIG_MAC80211_HT_DEBUG | 316 | #ifdef CONFIG_MAC80211_HT_DEBUG |
317 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | 317 | printk(KERN_DEBUG "BA request denied - HW unavailable for" |
@@ -487,7 +487,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
487 | 487 | ||
488 | drv_ampdu_action(local, sta->sdata, | 488 | drv_ampdu_action(local, sta->sdata, |
489 | IEEE80211_AMPDU_TX_OPERATIONAL, | 489 | IEEE80211_AMPDU_TX_OPERATIONAL, |
490 | &sta->sta, tid, NULL); | 490 | &sta->sta, tid, NULL, |
491 | sta->ampdu_mlme.tid_tx[tid]->buf_size); | ||
491 | 492 | ||
492 | /* | 493 | /* |
493 | * synchronize with TX path, while splicing the TX path | 494 | * synchronize with TX path, while splicing the TX path |
@@ -742,9 +743,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
742 | { | 743 | { |
743 | struct tid_ampdu_tx *tid_tx; | 744 | struct tid_ampdu_tx *tid_tx; |
744 | u16 capab, tid; | 745 | u16 capab, tid; |
746 | u8 buf_size; | ||
745 | 747 | ||
746 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | 748 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); |
747 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | 749 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; |
750 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||
748 | 751 | ||
749 | mutex_lock(&sta->ampdu_mlme.mtx); | 752 | mutex_lock(&sta->ampdu_mlme.mtx); |
750 | 753 | ||
@@ -767,12 +770,23 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
767 | 770 | ||
768 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) | 771 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) |
769 | == WLAN_STATUS_SUCCESS) { | 772 | == WLAN_STATUS_SUCCESS) { |
773 | /* | ||
774 | * IEEE 802.11-2007 7.3.1.14: | ||
775 | * In an ADDBA Response frame, when the Status Code field | ||
776 | * is set to 0, the Buffer Size subfield is set to a value | ||
777 | * of at least 1. | ||
778 | */ | ||
779 | if (!buf_size) | ||
780 | goto out; | ||
781 | |||
770 | if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED, | 782 | if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED, |
771 | &tid_tx->state)) { | 783 | &tid_tx->state)) { |
772 | /* ignore duplicate response */ | 784 | /* ignore duplicate response */ |
773 | goto out; | 785 | goto out; |
774 | } | 786 | } |
775 | 787 | ||
788 | tid_tx->buf_size = buf_size; | ||
789 | |||
776 | if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)) | 790 | if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)) |
777 | ieee80211_agg_tx_operational(local, sta, tid); | 791 | ieee80211_agg_tx_operational(local, sta, tid); |
778 | 792 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 98d589960a49..78af32d4bc58 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -382,17 +382,17 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, | |||
382 | struct ieee80211_sub_if_data *sdata, | 382 | struct ieee80211_sub_if_data *sdata, |
383 | enum ieee80211_ampdu_mlme_action action, | 383 | enum ieee80211_ampdu_mlme_action action, |
384 | struct ieee80211_sta *sta, u16 tid, | 384 | struct ieee80211_sta *sta, u16 tid, |
385 | u16 *ssn) | 385 | u16 *ssn, u8 buf_size) |
386 | { | 386 | { |
387 | int ret = -EOPNOTSUPP; | 387 | int ret = -EOPNOTSUPP; |
388 | 388 | ||
389 | might_sleep(); | 389 | might_sleep(); |
390 | 390 | ||
391 | trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn); | 391 | trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size); |
392 | 392 | ||
393 | if (local->ops->ampdu_action) | 393 | if (local->ops->ampdu_action) |
394 | ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, | 394 | ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, |
395 | sta, tid, ssn); | 395 | sta, tid, ssn, buf_size); |
396 | 396 | ||
397 | trace_drv_return_int(local, ret); | 397 | trace_drv_return_int(local, ret); |
398 | 398 | ||
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 49c84218b2f4..fbabbc2f181a 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -784,9 +784,9 @@ TRACE_EVENT(drv_ampdu_action, | |||
784 | struct ieee80211_sub_if_data *sdata, | 784 | struct ieee80211_sub_if_data *sdata, |
785 | enum ieee80211_ampdu_mlme_action action, | 785 | enum ieee80211_ampdu_mlme_action action, |
786 | struct ieee80211_sta *sta, u16 tid, | 786 | struct ieee80211_sta *sta, u16 tid, |
787 | u16 *ssn), | 787 | u16 *ssn, u8 buf_size), |
788 | 788 | ||
789 | TP_ARGS(local, sdata, action, sta, tid, ssn), | 789 | TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size), |
790 | 790 | ||
791 | TP_STRUCT__entry( | 791 | TP_STRUCT__entry( |
792 | LOCAL_ENTRY | 792 | LOCAL_ENTRY |
@@ -794,6 +794,7 @@ TRACE_EVENT(drv_ampdu_action, | |||
794 | __field(u32, action) | 794 | __field(u32, action) |
795 | __field(u16, tid) | 795 | __field(u16, tid) |
796 | __field(u16, ssn) | 796 | __field(u16, ssn) |
797 | __field(u8, buf_size) | ||
797 | VIF_ENTRY | 798 | VIF_ENTRY |
798 | ), | 799 | ), |
799 | 800 | ||
@@ -804,11 +805,13 @@ TRACE_EVENT(drv_ampdu_action, | |||
804 | __entry->action = action; | 805 | __entry->action = action; |
805 | __entry->tid = tid; | 806 | __entry->tid = tid; |
806 | __entry->ssn = ssn ? *ssn : 0; | 807 | __entry->ssn = ssn ? *ssn : 0; |
808 | __entry->buf_size = buf_size; | ||
807 | ), | 809 | ), |
808 | 810 | ||
809 | TP_printk( | 811 | TP_printk( |
810 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d", | 812 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d", |
811 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid | 813 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, |
814 | __entry->tid, __entry->buf_size | ||
812 | ) | 815 | ) |
813 | ); | 816 | ); |
814 | 817 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index bbdd2a86a94b..ca0b69060ef7 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -82,6 +82,7 @@ enum ieee80211_sta_info_flags { | |||
82 | * @state: session state (see above) | 82 | * @state: session state (see above) |
83 | * @stop_initiator: initiator of a session stop | 83 | * @stop_initiator: initiator of a session stop |
84 | * @tx_stop: TX DelBA frame when stopping | 84 | * @tx_stop: TX DelBA frame when stopping |
85 | * @buf_size: reorder buffer size at receiver | ||
85 | * | 86 | * |
86 | * This structure's lifetime is managed by RCU, assignments to | 87 | * This structure's lifetime is managed by RCU, assignments to |
87 | * the array holding it must hold the aggregation mutex. | 88 | * the array holding it must hold the aggregation mutex. |
@@ -101,6 +102,7 @@ struct tid_ampdu_tx { | |||
101 | u8 dialog_token; | 102 | u8 dialog_token; |
102 | u8 stop_initiator; | 103 | u8 stop_initiator; |
103 | bool tx_stop; | 104 | bool tx_stop; |
105 | u8 buf_size; | ||
104 | }; | 106 | }; |
105 | 107 | ||
106 | /** | 108 | /** |