mirror of https://gitee.com/openkylin/linux.git
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:
parent
08fdef9934
commit
e7a5965a81
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue