Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

mac80211: call skb_dequeue/ieee80211_free_txskb instead of __skb_queue_purge



Fixes more wifi status skb leaks, leading to hostapd/wpa_supplicant hangs.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 20f544ee
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1314,6 +1314,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
					 struct net_device *dev);
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
				       struct net_device *dev);
void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
			      struct sk_buff_head *skbs);

/* HT */
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
+3 −3
Original line number Diff line number Diff line
@@ -117,8 +117,8 @@ static void free_sta_work(struct work_struct *wk)

	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
		local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
		__skb_queue_purge(&sta->ps_tx_buf[ac]);
		__skb_queue_purge(&sta->tx_filtered[ac]);
		ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]);
		ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
	}

#ifdef CONFIG_MAC80211_MESH
@@ -141,7 +141,7 @@ static void free_sta_work(struct work_struct *wk)
		tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
		if (!tid_tx)
			continue;
		__skb_queue_purge(&tid_tx->pending);
		ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
		kfree(tid_tx);
	}

+9 −0
Original line number Diff line number Diff line
@@ -668,3 +668,12 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
	dev_kfree_skb_any(skb);
}
EXPORT_SYMBOL(ieee80211_free_txskb);

void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
			      struct sk_buff_head *skbs)
{
	struct sk_buff *skb;

	while ((skb = __skb_dequeue(skbs)))
		ieee80211_free_txskb(hw, skb);
}
+6 −3
Original line number Diff line number Diff line
@@ -1358,7 +1358,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
		if (tx->skb)
			ieee80211_free_txskb(&tx->local->hw, tx->skb);
		else
			__skb_queue_purge(&tx->skbs);
			ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
		return -1;
	} else if (unlikely(res == TX_QUEUED)) {
		I802_DEBUG_INC(tx->local->tx_handlers_queued);
@@ -2120,10 +2120,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 */
void ieee80211_clear_tx_pending(struct ieee80211_local *local)
{
	struct sk_buff *skb;
	int i;

	for (i = 0; i < local->hw.queues; i++)
		skb_queue_purge(&local->pending[i]);
	for (i = 0; i < local->hw.queues; i++) {
		while ((skb = skb_dequeue(&local->pending[i])) != NULL)
			ieee80211_free_txskb(&local->hw, skb);
	}
}

/*