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: Roel Kluin <roel.kluin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Roel Kluin 2009-08-18 20:21:40 -07:00 committed by David S. Miller
parent 08fdef9934
commit e7a5965a81

View file

@ -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)