3.6-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Felix Fietkau <n...@openwrt.org>

commit c3e7724b6bc2f25e46c38dbe68f09d71fafeafb8 upstream.

A few places free skbs using dev_kfree_skb even though they're called
after ieee80211_subif_start_xmit might have cloned it for tracking tx
status. Use ieee80211_free_txskb here to prevent skb leaks.

Signed-off-by: Felix Fietkau <n...@openwrt.org>
Signed-off-by: John W. Linville <linvi...@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 net/mac80211/status.c |    4 ++--
 net/mac80211/tx.c     |   22 ++++++++++++----------
 2 files changed, 14 insertions(+), 12 deletions(-)

--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -34,7 +34,7 @@ void ieee80211_tx_status_irqsafe(struct
                skb_queue_len(&local->skb_queue_unreliable);
        while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
               (skb = skb_dequeue(&local->skb_queue_unreliable))) {
-               dev_kfree_skb_irq(skb);
+               ieee80211_free_txskb(hw, skb);
                tmp--;
                I802_DEBUG_INC(local->tx_status_drop);
        }
@@ -159,7 +159,7 @@ static void ieee80211_handle_filtered_fr
                           "dropped TX filtered frame, queue_len=%d PS=%d 
@%lu\n",
                           skb_queue_len(&sta->tx_filtered[ac]),
                           !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
-       dev_kfree_skb(skb);
+       ieee80211_free_txskb(&local->hw, skb);
 }
 
 static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -354,7 +354,7 @@ static void purge_old_ps_buffers(struct
                        total += skb_queue_len(&sta->ps_tx_buf[ac]);
                        if (skb) {
                                purged++;
-                               dev_kfree_skb(skb);
+                               ieee80211_free_txskb(&local->hw, skb);
                                break;
                        }
                }
@@ -466,7 +466,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
                        ps_dbg(tx->sdata,
                               "STA %pM TX buffer for AC %d full - dropping 
oldest frame\n",
                               sta->sta.addr, ac);
-                       dev_kfree_skb(old);
+                       ieee80211_free_txskb(&local->hw, old);
                } else
                        tx->local->total_ps_buffered++;
 
@@ -1103,7 +1103,7 @@ static bool ieee80211_tx_prep_agg(struct
                spin_unlock(&tx->sta->lock);
 
                if (purge_skb)
-                       dev_kfree_skb(purge_skb);
+                       ieee80211_free_txskb(&tx->local->hw, purge_skb);
        }
 
        /* reset session timer */
@@ -1214,7 +1214,7 @@ static bool ieee80211_tx_frags(struct ie
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (WARN_ON_ONCE(q >= local->hw.queues)) {
                        __skb_unlink(skb, skbs);
-                       dev_kfree_skb(skb);
+                       ieee80211_free_txskb(&local->hw, skb);
                        continue;
                }
 #endif
@@ -1356,7 +1356,7 @@ static int invoke_tx_handlers(struct iee
        if (unlikely(res == TX_DROP)) {
                I802_DEBUG_INC(tx->local->tx_handlers_drop);
                if (tx->skb)
-                       dev_kfree_skb(tx->skb);
+                       ieee80211_free_txskb(&tx->local->hw, tx->skb);
                else
                        __skb_queue_purge(&tx->skbs);
                return -1;
@@ -1393,7 +1393,7 @@ static bool ieee80211_tx(struct ieee8021
        res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
 
        if (unlikely(res_prepare == TX_DROP)) {
-               dev_kfree_skb(skb);
+               ieee80211_free_txskb(&local->hw, skb);
                goto out;
        } else if (unlikely(res_prepare == TX_QUEUED)) {
                goto out;
@@ -1466,7 +1466,7 @@ void ieee80211_xmit(struct ieee80211_sub
        headroom = max_t(int, 0, headroom);
 
        if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
-               dev_kfree_skb(skb);
+               ieee80211_free_txskb(&local->hw, skb);
                rcu_read_unlock();
                return;
        }
@@ -2060,8 +2060,10 @@ netdev_tx_t ieee80211_subif_start_xmit(s
                head_need += IEEE80211_ENCRYPT_HEADROOM;
                head_need += local->tx_headroom;
                head_need = max_t(int, 0, head_need);
-               if (ieee80211_skb_resize(sdata, skb, head_need, true))
-                       goto fail;
+               if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
+                       ieee80211_free_txskb(&local->hw, skb);
+                       return NETDEV_TX_OK;
+               }
        }
 
        if (encaps_data) {
@@ -2196,7 +2198,7 @@ void ieee80211_tx_pending(unsigned long
                        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
                        if (WARN_ON(!info->control.vif)) {
-                               kfree_skb(skb);
+                               ieee80211_free_txskb(&local->hw, skb);
                                continue;
                        }
 


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to