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

Commit b530b164 authored by Alexander Kochetkov's avatar Alexander Kochetkov Committed by David S. Miller
Browse files

net: arc_emac: fix sk_buff leak



EMAC could be disabled, while there is some sb_buff
in use. That buffers got lost for linux.

In order to reproduce run on device during active ethernet work:
    ifconfig eth0 down

Signed-off-by: default avatarAlexander Kochetkov <al.kochet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 99f93a15
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -517,6 +517,64 @@ static void arc_emac_set_rx_mode(struct net_device *ndev)
	}
}

/**
 * arc_free_tx_queue - free skb from tx queue
 * @ndev:	Pointer to the network device.
 *
 * This function must be called while EMAC disable
 */
static void arc_free_tx_queue(struct net_device *ndev)
{
	struct arc_emac_priv *priv = netdev_priv(ndev);
	unsigned int i;

	for (i = 0; i < TX_BD_NUM; i++) {
		struct arc_emac_bd *txbd = &priv->txbd[i];
		struct buffer_state *tx_buff = &priv->tx_buff[i];

		if (tx_buff->skb) {
			dma_unmap_single(&ndev->dev, dma_unmap_addr(tx_buff, addr),
					 dma_unmap_len(tx_buff, len), DMA_TO_DEVICE);

			/* return the sk_buff to system */
			dev_kfree_skb_irq(tx_buff->skb);
		}

		txbd->info = 0;
		txbd->data = 0;
		tx_buff->skb = NULL;
	}
}

/**
 * arc_free_rx_queue - free skb from rx queue
 * @ndev:	Pointer to the network device.
 *
 * This function must be called while EMAC disable
 */
static void arc_free_rx_queue(struct net_device *ndev)
{
	struct arc_emac_priv *priv = netdev_priv(ndev);
	unsigned int i;

	for (i = 0; i < RX_BD_NUM; i++) {
		struct arc_emac_bd *rxbd = &priv->rxbd[i];
		struct buffer_state *rx_buff = &priv->rx_buff[i];

		if (rx_buff->skb) {
			dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr),
					dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE);

			/* return the sk_buff to system */
			dev_kfree_skb_irq(rx_buff->skb);
		}

		rxbd->info = 0;
		rxbd->data = 0;
		rx_buff->skb = NULL;
	}
}

/**
 * arc_emac_stop - Close the network device.
 * @ndev:	Pointer to the network device.
@@ -538,6 +596,10 @@ static int arc_emac_stop(struct net_device *ndev)
	/* Disable EMAC */
	arc_reg_clr(priv, R_CTRL, EN_MASK);

	/* Return the sk_buff to system */
	arc_free_tx_queue(ndev);
	arc_free_rx_queue(ndev);

	return 0;
}