Commit 592234e9 authored by Alexander Wetzel's avatar Alexander Wetzel Committed by Johannes Berg
Browse files

wifi: mac80211: Fix iTXQ AMPDU fragmentation handling



mac80211 must not enable aggregation wile transmitting a fragmented
MPDU. Enforce that for mac80211 internal TX queues (iTXQs).

Reported-by: default avatarkernel test robot <oliver.sang@intel.com>
Link: https://lore.kernel.org/oe-lkp/202301021738.7cd3e6ae-oliver.sang@intel.com


Signed-off-by: default avatarAlexander Wetzel <alexander@wetzel-home.de>
Link: https://lore.kernel.org/r/20230106223141.98696-1-alexander@wetzel-home.de


Cc: stable@vger.kernel.org
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 69403bad
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -511,8 +511,6 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
	 */
	clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);

	ieee80211_agg_stop_txq(sta, tid);

	/*
	 * Make sure no packets are being processed. This ensures that
	 * we have a valid starting sequence number and that in-flight
+31 −0
Original line number Diff line number Diff line
@@ -391,6 +391,37 @@ void ieee80211_ba_session_work(struct work_struct *work)

		tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
		if (!blocked && tid_tx) {
			struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
			struct ieee80211_sub_if_data *sdata =
				vif_to_sdata(txqi->txq.vif);
			struct fq *fq = &sdata->local->fq;

			spin_lock_bh(&fq->lock);

			/* Allow only frags to be dequeued */
			set_bit(IEEE80211_TXQ_STOP, &txqi->flags);

			if (!skb_queue_empty(&txqi->frags)) {
				/* Fragmented Tx is ongoing, wait for it to
				 * finish. Reschedule worker to retry later.
				 */

				spin_unlock_bh(&fq->lock);
				spin_unlock_bh(&sta->lock);

				/* Give the task working on the txq a chance
				 * to send out the queued frags
				 */
				synchronize_net();

				mutex_unlock(&sta->ampdu_mlme.mtx);

				ieee80211_queue_work(&sdata->local->hw, work);
				return;
			}

			spin_unlock_bh(&fq->lock);

			/*
			 * Assign it over to the normal tid_tx array
			 * where it "goes live".
+6 −12
Original line number Diff line number Diff line
@@ -1129,7 +1129,6 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
	struct sk_buff *purge_skb = NULL;

	if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
		info->flags |= IEEE80211_TX_CTL_AMPDU;
		reset_agg_timer = true;
	} else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
		/*
@@ -1161,7 +1160,6 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
		if (!tid_tx) {
			/* do nothing, let packet pass through */
		} else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
			info->flags |= IEEE80211_TX_CTL_AMPDU;
			reset_agg_timer = true;
		} else {
			queued = true;
@@ -3677,8 +3675,7 @@ static void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
	info->band = fast_tx->band;
	info->control.vif = &sdata->vif;
	info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
		      IEEE80211_TX_CTL_DONTFRAG |
		      (ampdu ? IEEE80211_TX_CTL_AMPDU : 0);
		      IEEE80211_TX_CTL_DONTFRAG;
	info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT |
			      u32_encode_bits(IEEE80211_LINK_UNSPECIFIED,
					      IEEE80211_TX_CTRL_MLO_LINK);
@@ -3804,9 +3801,6 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,

	spin_lock_bh(&fq->lock);

	if (unlikely(test_bit(IEEE80211_TXQ_STOP, &txqi->flags)))
		goto out;

	/* Make sure fragments stay together. */
	skb = __skb_dequeue(&txqi->frags);
	if (unlikely(skb)) {
@@ -3816,6 +3810,9 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
		IEEE80211_SKB_CB(skb)->control.flags &=
			~IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
	} else {
		if (unlikely(test_bit(IEEE80211_TXQ_STOP, &txqi->flags)))
			goto out;

		skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
	}

@@ -3866,9 +3863,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
	}

	if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
		info->flags |= IEEE80211_TX_CTL_AMPDU;
	else
		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
		info->flags |= (IEEE80211_TX_CTL_AMPDU |
				IEEE80211_TX_CTL_DONTFRAG);

	if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
		if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
@@ -4602,8 +4598,6 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,

	info = IEEE80211_SKB_CB(skb);
	memset(info, 0, sizeof(*info));
	if (tid_tx)
		info->flags |= IEEE80211_TX_CTL_AMPDU;

	info->hw_queue = sdata->vif.hw_queue[queue];