Commit d5ad6ab6 authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg
Browse files

wifi: mac80211: always free skb on ieee80211_tx_prepare_skb() failure



ieee80211_tx_prepare_skb() has three error paths, but only two of them
free the skb. The first error path (ieee80211_tx_prepare() returning
TX_DROP) does not free it, while invoke_tx_handlers() failure and the
fragmentation check both do.

Add kfree_skb() to the first error path so all three are consistent,
and remove the now-redundant frees in callers (ath9k, mt76,
mac80211_hwsim) to avoid double-free.

Document the skb ownership guarantee in the function's kdoc.

Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
Link: https://patch.msgid.link/20260314065455.2462900-1-nbd@nbd.name


Fixes: 06be6b14 ("mac80211: add ieee80211_tx_prepare_skb() helper function")
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent deb353d9
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -1006,7 +1006,7 @@ static void ath_scan_send_probe(struct ath_softc *sc,
	skb_set_queue_mapping(skb, IEEE80211_AC_VO);

	if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
		goto error;
		return;

	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
	if (ath_tx_start(sc->hw, skb, &txctl))
@@ -1119,10 +1119,8 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,

		skb->priority = 7;
		skb_set_queue_mapping(skb, IEEE80211_AC_VO);
		if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
			dev_kfree_skb_any(skb);
		if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta))
			return false;
		}
		break;
	default:
		return false;
+1 −3
Original line number Diff line number Diff line
@@ -63,10 +63,8 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)

	rcu_read_lock();

	if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL)) {
		ieee80211_free_txskb(phy->hw, skb);
	if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
		goto out;
	}

	info = IEEE80211_SKB_CB(skb);
	if (req->no_cck)
+0 −1
Original line number Diff line number Diff line
@@ -3021,7 +3021,6 @@ static void hw_scan_work(struct work_struct *work)
						      hwsim->tmp_chan->band,
						      NULL)) {
				rcu_read_unlock();
				kfree_skb(probe);
				continue;
			}

+3 −1
Original line number Diff line number Diff line
@@ -7407,7 +7407,9 @@ void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
 * @band: the band to transmit on
 * @sta: optional pointer to get the station to send the frame to
 *
 * Return: %true if the skb was prepared, %false otherwise
 * Return: %true if the skb was prepared, %false otherwise.
 * On failure, the skb is freed by this function; callers must not
 * free it again.
 *
 * Note: must be called under RCU lock
 */
+3 −1
Original line number Diff line number Diff line
@@ -1899,8 +1899,10 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
	struct ieee80211_tx_data tx;
	struct sk_buff *skb2;

	if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
	if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP) {
		kfree_skb(skb);
		return false;
	}

	info->band = band;
	info->control.vif = vif;