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

Commit e7a5965a authored by Roel Kluin's avatar Roel Kluin Committed by David S. Miller
Browse files

yellowfin: Fix buffer underrun after dev_alloc_skb() failure



yellowfin_init_ring() needs to clean up if dev_alloc_skb() fails and
should pass an error status up to the caller. This also prevents an
buffer underrun if failure occurred in the first iteration.
yellowfin_open() which calls yellowfin_init_ring() should free its
requested irq upon failure.

Signed-off-by: default avatarRoel Kluin <roel.kluin@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 08fdef99
Loading
Loading
Loading
Loading
+18 −10
Original line number Original line Diff line number Diff line
@@ -346,7 +346,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int yellowfin_open(struct net_device *dev);
static int yellowfin_open(struct net_device *dev);
static void yellowfin_timer(unsigned long data);
static void yellowfin_timer(unsigned long data);
static void yellowfin_tx_timeout(struct net_device *dev);
static void yellowfin_tx_timeout(struct net_device *dev);
static void yellowfin_init_ring(struct net_device *dev);
static int yellowfin_init_ring(struct net_device *dev);
static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance);
static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance);
static int yellowfin_rx(struct net_device *dev);
static int yellowfin_rx(struct net_device *dev);
@@ -573,19 +573,24 @@ static int yellowfin_open(struct net_device *dev)
{
{
	struct yellowfin_private *yp = netdev_priv(dev);
	struct yellowfin_private *yp = netdev_priv(dev);
	void __iomem *ioaddr = yp->base;
	void __iomem *ioaddr = yp->base;
	int i;
	int i, ret;


	/* Reset the chip. */
	/* Reset the chip. */
	iowrite32(0x80000000, ioaddr + DMACtrl);
	iowrite32(0x80000000, ioaddr + DMACtrl);


	i = request_irq(dev->irq, &yellowfin_interrupt, IRQF_SHARED, dev->name, dev);
	ret = request_irq(dev->irq, &yellowfin_interrupt, IRQF_SHARED, dev->name, dev);
	if (i) return i;
	if (ret)
		return ret;


	if (yellowfin_debug > 1)
	if (yellowfin_debug > 1)
		printk(KERN_DEBUG "%s: yellowfin_open() irq %d.\n",
		printk(KERN_DEBUG "%s: yellowfin_open() irq %d.\n",
			   dev->name, dev->irq);
			   dev->name, dev->irq);


	yellowfin_init_ring(dev);
	ret = yellowfin_init_ring(dev);
	if (ret) {
		free_irq(dev->irq, dev);
		return ret;
	}


	iowrite32(yp->rx_ring_dma, ioaddr + RxPtr);
	iowrite32(yp->rx_ring_dma, ioaddr + RxPtr);
	iowrite32(yp->tx_ring_dma, ioaddr + TxPtr);
	iowrite32(yp->tx_ring_dma, ioaddr + TxPtr);
@@ -725,10 +730,10 @@ static void yellowfin_tx_timeout(struct net_device *dev)
}
}


/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void yellowfin_init_ring(struct net_device *dev)
static int yellowfin_init_ring(struct net_device *dev)
{
{
	struct yellowfin_private *yp = netdev_priv(dev);
	struct yellowfin_private *yp = netdev_priv(dev);
	int i;
	int i, j;


	yp->tx_full = 0;
	yp->tx_full = 0;
	yp->cur_rx = yp->cur_tx = 0;
	yp->cur_rx = yp->cur_tx = 0;
@@ -753,6 +758,11 @@ static void yellowfin_init_ring(struct net_device *dev)
		yp->rx_ring[i].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
		yp->rx_ring[i].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
			skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
			skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
	}
	}
	if (i != RX_RING_SIZE) {
		for (j = 0; j < i; j++)
			dev_kfree_skb(yp->rx_skbuff[j]);
		return -ENOMEM;
	}
	yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP);
	yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP);
	yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
	yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);


@@ -769,8 +779,6 @@ static void yellowfin_init_ring(struct net_device *dev)
	yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS);
	yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS);
#else
#else
{
{
	int j;

	/* Tx ring needs a pair of descriptors, the second for the status. */
	/* Tx ring needs a pair of descriptors, the second for the status. */
	for (i = 0; i < TX_RING_SIZE; i++) {
	for (i = 0; i < TX_RING_SIZE; i++) {
		j = 2*i;
		j = 2*i;
@@ -805,7 +813,7 @@ static void yellowfin_init_ring(struct net_device *dev)
}
}
#endif
#endif
	yp->tx_tail_desc = &yp->tx_status[0];
	yp->tx_tail_desc = &yp->tx_status[0];
	return;
	return 0;
}
}


static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)