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

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
...@@ -1314,6 +1314,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, ...@@ -1314,6 +1314,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct net_device *dev); struct net_device *dev);
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev); struct net_device *dev);
void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
struct sk_buff_head *skbs);
/* HT */ /* HT */
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
......
...@@ -117,8 +117,8 @@ static void free_sta_work(struct work_struct *wk) ...@@ -117,8 +117,8 @@ static void free_sta_work(struct work_struct *wk)
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
__skb_queue_purge(&sta->ps_tx_buf[ac]); ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]);
__skb_queue_purge(&sta->tx_filtered[ac]); ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
} }
#ifdef CONFIG_MAC80211_MESH #ifdef CONFIG_MAC80211_MESH
...@@ -141,7 +141,7 @@ static void free_sta_work(struct work_struct *wk) ...@@ -141,7 +141,7 @@ static void free_sta_work(struct work_struct *wk)
tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
if (!tid_tx) if (!tid_tx)
continue; continue;
__skb_queue_purge(&tid_tx->pending); ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
kfree(tid_tx); kfree(tid_tx);
} }
......
...@@ -668,3 +668,12 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -668,3 +668,12 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
EXPORT_SYMBOL(ieee80211_free_txskb); 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);
}
...@@ -1358,7 +1358,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) ...@@ -1358,7 +1358,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
if (tx->skb) if (tx->skb)
ieee80211_free_txskb(&tx->local->hw, tx->skb); ieee80211_free_txskb(&tx->local->hw, tx->skb);
else else
__skb_queue_purge(&tx->skbs); ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
return -1; return -1;
} else if (unlikely(res == TX_QUEUED)) { } else if (unlikely(res == TX_QUEUED)) {
I802_DEBUG_INC(tx->local->tx_handlers_queued); I802_DEBUG_INC(tx->local->tx_handlers_queued);
...@@ -2120,10 +2120,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -2120,10 +2120,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
*/ */
void ieee80211_clear_tx_pending(struct ieee80211_local *local) void ieee80211_clear_tx_pending(struct ieee80211_local *local)
{ {
struct sk_buff *skb;
int i; int i;
for (i = 0; i < local->hw.queues; i++) for (i = 0; i < local->hw.queues; i++) {
skb_queue_purge(&local->pending[i]); while ((skb = skb_dequeue(&local->pending[i])) != NULL)
ieee80211_free_txskb(&local->hw, skb);
}
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment