diff options
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/carl9170/main.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlegacy/4965-mac.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/mac80211.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/core.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/main.c | 4 | ||||
-rw-r--r-- | include/net/mac80211.h | 22 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 40 |
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; } /* |