summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c4
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c4
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c4
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c4
-rw-r--r--drivers/net/wireless/mwl8k.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c4
-rw-r--r--drivers/net/wireless/rtlwifi/core.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c4
-rw-r--r--include/net/mac80211.h22
-rw-r--r--net/mac80211/agg-tx.c40
13 files changed, 85 insertions, 21 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 9c07a8fa5134..a8016d70088a 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1628,7 +1628,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
if (!ret)
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index be30a9af1528..e1fa70596e61 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1610,7 +1610,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ath9k_ps_wakeup(sc);
ath_tx_aggr_stop(sc, sta, tid);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 25a1e2f4f738..9d2051aeb782 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1394,7 +1394,9 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
rcu_read_lock();
tid_info = rcu_dereference(sta_info->agg[tid]);
if (tid_info) {
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 1fbd8ecbe2ea..f0fc8cd4d5df 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -668,7 +668,9 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
spin_lock_bh(&wl->lock);
brcms_c_ampdu_flush(wl->wlc, sta, tid);
spin_unlock_bh(&wl->lock);
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index c3fbf6717564..6a86ed45835d 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -5968,7 +5968,9 @@ il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
D_HT("start Tx\n");
ret = il4965_tx_agg_start(il, vif, sta, tid, ssn);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
D_HT("stop Tx\n");
ret = il4965_tx_agg_stop(il, vif, sta, tid);
if (test_bit(S_EXIT_PENDING, &il->status))
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 3163e0f38c25..02fdcea76b21 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -679,7 +679,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
IWL_DEBUG_HT(priv, "stop Tx\n");
ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
if ((ret == 0) && (priv->agg_tids_count > 0)) {
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 145498f8411f..d248a4cc6656 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1312,7 +1312,9 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_START:
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index f221b95b90b3..19b46fdf9f0f 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -5170,7 +5170,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
if (stream) {
if (stream->state == AMPDU_STREAM_ACTIVE) {
spin_unlock(&priv->stream_lock);
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 197b4466a5d2..12f93e42e160 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -5484,7 +5484,9 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_START:
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index be33aa14c8af..d3ce9fbef00e 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -879,7 +879,9 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
"IEEE80211_AMPDU_TX_START: TID:%d\n", tid);
return rtl_tx_agg_start(hw, sta, tid, ssn);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid);
return rtl_tx_agg_stop(hw, sta, tid);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index ea9d8e011bc9..d7de06359ae1 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -4575,7 +4575,9 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
* Falling break here on purpose for all TX APDU commands.
*/
case IEEE80211_AMPDU_TX_START:
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
case IEEE80211_AMPDU_TX_OPERATIONAL:
ret = -EINVAL;
break;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 0978b0faa880..a464f4fb36a0 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2033,17 +2033,29 @@ enum ieee80211_filter_flags {
* calling ieee80211_start_tx_ba_cb_irqsafe, because the peer
* might receive the addBA frame and send a delBA right away!
*
- * @IEEE80211_AMPDU_RX_START: start Rx aggregation
- * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation
- * @IEEE80211_AMPDU_TX_START: start Tx aggregation
- * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation
+ * @IEEE80211_AMPDU_RX_START: start RX aggregation
+ * @IEEE80211_AMPDU_RX_STOP: stop RX aggregation
+ * @IEEE80211_AMPDU_TX_START: start TX aggregation
* @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational
+ * @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting
+ * queued packets, now unaggregated. After all packets are transmitted the
+ * driver has to call ieee80211_stop_tx_ba_cb_irqsafe().
+ * @IEEE80211_AMPDU_TX_STOP_FLUSH: stop TX aggregation and flush all packets,
+ * called when the station is removed. There's no need or reason to call
+ * ieee80211_stop_tx_ba_cb_irqsafe() in this case as mac80211 assumes the
+ * session is gone and removes the station.
+ * @IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: called when TX aggregation is stopped
+ * but the driver hasn't called ieee80211_stop_tx_ba_cb_irqsafe() yet and
+ * now the connection is dropped and the station will be removed. Drivers
+ * should clean up and drop remaining packets when this is called.
*/
enum ieee80211_ampdu_mlme_action {
IEEE80211_AMPDU_RX_START,
IEEE80211_AMPDU_RX_STOP,
IEEE80211_AMPDU_TX_START,
- IEEE80211_AMPDU_TX_STOP,
+ IEEE80211_AMPDU_TX_STOP_CONT,
+ IEEE80211_AMPDU_TX_STOP_FLUSH,
+ IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
IEEE80211_AMPDU_TX_OPERATIONAL,
};
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index dda8d7df4b54..2f0ccbc5f13e 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -257,10 +257,25 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
{
struct ieee80211_local *local = sta->local;
struct tid_ampdu_tx *tid_tx;
+ enum ieee80211_ampdu_mlme_action action;
int ret;
lockdep_assert_held(&sta->ampdu_mlme.mtx);
+ switch (reason) {
+ case AGG_STOP_DECLINED:
+ case AGG_STOP_LOCAL_REQUEST:
+ case AGG_STOP_PEER_REQUEST:
+ action = IEEE80211_AMPDU_TX_STOP_CONT;
+ break;
+ case AGG_STOP_DESTROY_STA:
+ action = IEEE80211_AMPDU_TX_STOP_FLUSH;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+
spin_lock_bh(&sta->lock);
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
@@ -269,10 +284,19 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
return -ENOENT;
}
- /* if we're already stopping ignore any new requests to stop */
+ /*
+ * if we're already stopping ignore any new requests to stop
+ * unless we're destroying it in which case notify the driver
+ */
if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
spin_unlock_bh(&sta->lock);
- return -EALREADY;
+ if (reason != AGG_STOP_DESTROY_STA)
+ return -EALREADY;
+ ret = drv_ampdu_action(local, sta->sdata,
+ IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
+ &sta->sta, tid, NULL, 0);
+ WARN_ON_ONCE(ret);
+ goto remove_tid_tx;
}
if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
@@ -319,8 +343,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
WLAN_BACK_INITIATOR;
tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
- ret = drv_ampdu_action(local, sta->sdata,
- IEEE80211_AMPDU_TX_STOP,
+ ret = drv_ampdu_action(local, sta->sdata, action,
&sta->sta, tid, NULL, 0);
/* HW shall not deny going back to legacy */
@@ -331,7 +354,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
*/
}
- return ret;
+ if (reason == AGG_STOP_DESTROY_STA) {
+ remove_tid_tx:
+ spin_lock_bh(&sta->lock);
+ ieee80211_remove_tid_tx(sta, tid);
+ spin_unlock_bh(&sta->lock);
+ }
+
+ return 0;
}
/*