提交 126fa4b9 编写于 作者: F Francois Romieu 提交者: Jeff Garzik

[PATCH] r8169: incoming frame length check

  
  The size of the incoming frame is not correctly checked.
  
  The RxMaxSize register (0xDA) does not work as expected and incoming
  frames whose size exceeds the MTU actually end spanning multiple
  descriptors. The first Rx descriptor contains the size of the whole
  frame (or some garbage in its place). The driver does not expect
  something above the space allocated to the current skb and crashes
  loudly when it issues a skb_put.
  
  The fix contains two parts:
  - disable hardware Rx size filtering: so far it only proved to be able
    to trigger some new fancy errors;
  - drop multi-descriptors frame: as the driver allocates MTU sized Rx
    buffers, it provides an adequate filtering.
  
  As a bonus, wrong descriptors were not returned to the asic after their
  processing.
Signed-off-by: NFrancois Romieu <romieu@fr.zoreil.com>
Signed-off-by: NJeff Garzik <jgarzik@pobox.com>
上级 88d7bd8c
...@@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev) ...@@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev)
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W8(EarlyTxThres, EarlyTxThld); RTL_W8(EarlyTxThres, EarlyTxThld);
/* For gigabit rtl8169, MTU + header + CRC + VLAN */ /* Low hurts. Let's disable the filtering. */
RTL_W16(RxMaxSize, tp->rx_buf_sz); RTL_W16(RxMaxSize, 16383);
/* Set Rx Config register */ /* Set Rx Config register */
i = rtl8169_rx_config | i = rtl8169_rx_config |
...@@ -2127,6 +2127,11 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp, ...@@ -2127,6 +2127,11 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
} }
} }
static inline int rtl8169_fragmented_frame(u32 status)
{
return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
}
static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc) static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
{ {
u32 opts1 = le32_to_cpu(desc->opts1); u32 opts1 = le32_to_cpu(desc->opts1);
...@@ -2177,27 +2182,41 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, ...@@ -2177,27 +2182,41 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
while (rx_left > 0) { while (rx_left > 0) {
unsigned int entry = cur_rx % NUM_RX_DESC; unsigned int entry = cur_rx % NUM_RX_DESC;
struct RxDesc *desc = tp->RxDescArray + entry;
u32 status; u32 status;
rmb(); rmb();
status = le32_to_cpu(tp->RxDescArray[entry].opts1); status = le32_to_cpu(desc->opts1);
if (status & DescOwn) if (status & DescOwn)
break; break;
if (status & RxRES) { if (status & RxRES) {
printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); printk(KERN_INFO "%s: Rx ERROR. status = %08x\n",
dev->name, status);
tp->stats.rx_errors++; tp->stats.rx_errors++;
if (status & (RxRWT | RxRUNT)) if (status & (RxRWT | RxRUNT))
tp->stats.rx_length_errors++; tp->stats.rx_length_errors++;
if (status & RxCRC) if (status & RxCRC)
tp->stats.rx_crc_errors++; tp->stats.rx_crc_errors++;
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
} else { } else {
struct RxDesc *desc = tp->RxDescArray + entry;
struct sk_buff *skb = tp->Rx_skbuff[entry]; struct sk_buff *skb = tp->Rx_skbuff[entry];
int pkt_size = (status & 0x00001FFF) - 4; int pkt_size = (status & 0x00001FFF) - 4;
void (*pci_action)(struct pci_dev *, dma_addr_t, void (*pci_action)(struct pci_dev *, dma_addr_t,
size_t, int) = pci_dma_sync_single_for_device; size_t, int) = pci_dma_sync_single_for_device;
/*
* The driver does not support incoming fragmented
* frames. They are seen as a symptom of over-mtu
* sized frames.
*/
if (unlikely(rtl8169_fragmented_frame(status))) {
tp->stats.rx_dropped++;
tp->stats.rx_length_errors++;
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
goto move_on;
}
rtl8169_rx_csum(skb, desc); rtl8169_rx_csum(skb, desc);
pci_dma_sync_single_for_cpu(tp->pci_dev, pci_dma_sync_single_for_cpu(tp->pci_dev,
...@@ -2224,7 +2243,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, ...@@ -2224,7 +2243,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
tp->stats.rx_bytes += pkt_size; tp->stats.rx_bytes += pkt_size;
tp->stats.rx_packets++; tp->stats.rx_packets++;
} }
move_on:
cur_rx++; cur_rx++;
rx_left--; rx_left--;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册