From ba84525bd9015e7dd20f7c97a2a96b0a238b0223 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 15:38:15 +0000
Subject: [PATCH] NET: sa11x0-ir: fix leak of tx skb

Ensure that we unmap and free a pending transmit skb when the interface
is stopped.  We rearrange the code a little bit to give all places a
similar layout when freeing the skb in both the completion and interface
stop paths - this gives some consistency to the code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index adb7fea78c2d63..9dc564830c9dda 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -602,9 +602,7 @@ static void sa1100_irda_txdma_irq(void *id)
 {
 	struct net_device *dev = id;
 	struct sa1100_irda *si = netdev_priv(dev);
-	struct sk_buff *skb = si->dma_tx.skb;
-
-	si->dma_tx.skb = NULL;
+	struct sk_buff *skb;
 
 	/*
 	 * Wait for the transmission to complete.  Unfortunately,
@@ -636,14 +634,15 @@ static void sa1100_irda_txdma_irq(void *id)
 	 */
 	sa1100_irda_rx_dma_start(si);
 
-	/*
-	 * Account and free the packet.
-	 */
+	/* Account and free the packet. */
+	skb = si->dma_tx.skb;
 	if (skb) {
-		dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, DMA_TO_DEVICE);
+		dma_unmap_single(si->dev, si->dma_tx.dma, skb->len,
+				 DMA_TO_DEVICE);
 		dev->stats.tx_packets ++;
 		dev->stats.tx_bytes += skb->len;
 		dev_kfree_skb_irq(skb);
+		si->dma_tx.skb = NULL;
 	}
 
 	/*
@@ -841,21 +840,31 @@ err_irq:
 static int sa1100_irda_stop(struct net_device *dev)
 {
 	struct sa1100_irda *si = netdev_priv(dev);
+	struct sk_buff *skb;
 
 	disable_irq(dev->irq);
 	sa1100_irda_shutdown(si);
 
 	/*
-	 * If we have been doing DMA receive, make sure we
+	 * If we have been doing any DMA activity, make sure we
 	 * tidy that up cleanly.
 	 */
-	if (si->dma_rx.skb) {
+	skb = si->dma_rx.skb;
+	if (skb) {
 		dma_unmap_single(si->dev, si->dma_rx.dma, HPSIR_MAX_RXLEN,
 				 DMA_FROM_DEVICE);
-		dev_kfree_skb(si->dma_rx.skb);
+		dev_kfree_skb(skb);
 		si->dma_rx.skb = NULL;
 	}
 
+	skb = si->dma_tx.skb;
+	if (skb) {
+		dma_unmap_single(si->dev, si->dma_tx.dma, skb->len,
+				 DMA_TO_DEVICE);
+		dev_kfree_skb(skb);
+		si->dma_tx.skb = NULL;
+	}
+
 	/* Stop IrLAP */
 	if (si->irlap) {
 		irlap_close(si->irlap);
-- 
GitLab