diff options
author | Hauke Mehrtens <hauke@openwrt.org> | 2014-04-08 19:50:17 +0000 |
---|---|---|
committer | Hauke Mehrtens <hauke@openwrt.org> | 2014-04-08 19:50:17 +0000 |
commit | f762ec24cc0539e90966a7ee6936c486e27baf25 (patch) | |
tree | 11ffccb02373e0e5ab762cb7c4b59351f84da43d /target/linux/generic | |
parent | 132cd136386c672ae7e9974689ff41792b539b15 (diff) | |
download | upstream-f762ec24cc0539e90966a7ee6936c486e27baf25.tar.gz upstream-f762ec24cc0539e90966a7ee6936c486e27baf25.tar.bz2 upstream-f762ec24cc0539e90966a7ee6936c486e27baf25.zip |
kernel: bgmac: rework patch checking packet length
This bgmac patch was an attempt to fix/workaround bug reported in
https://dev.openwrt.org/ticket/7198 noticed on WNR3500L.
Patch assumed length reported by the hardware was 0 and was trying to
read it until getting a different value. This was actually the opposite.
Lenghts were some invalid & huge values that resulted in skb_over_panic.
For example:
skbuff: skb_over_panic: text:83b21074 len:57222 (...)
skbuff: skb_over_panic: text:87af1024 len:43226 (...)
skbuff: skb_over_panic: text:87af5024 len:8739 (...)
So instead of that not-working patch checking for 0, write a new one
checking for huge values. In case something like that happens, dump
hardware state and drop the packet.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@40424 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/generic')
4 files changed, 141 insertions, 26 deletions
diff --git a/target/linux/generic/patches-3.10/775-bgmac-check-length-of-received-frame.patch b/target/linux/generic/patches-3.10/775-bgmac-check-length-of-received-frame.patch index f708e7dcec..c3d63b65fa 100644 --- a/target/linux/generic/patches-3.10/775-bgmac-check-length-of-received-frame.patch +++ b/target/linux/generic/patches-3.10/775-bgmac-check-length-of-received-frame.patch @@ -9,33 +9,31 @@ Subject: [PATCH] bgmac: check length of received frame --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c -@@ -349,6 +349,7 @@ static int bgmac_dma_rx_read(struct bgma - struct sk_buff *skb = slot->skb; - struct bgmac_rx_header *rx; - u16 len, flags; -+ int count; - - /* Unmap buffer to make it accessible to the CPU */ - dma_sync_single_for_cpu(dma_dev, slot->dma_addr, -@@ -357,6 +358,12 @@ static int bgmac_dma_rx_read(struct bgma - /* Get info from the header */ - rx = (struct bgmac_rx_header *)skb->data; - len = le16_to_cpu(rx->len); -+ for (count = 0; count < 200; count++) { -+ len = le16_to_cpu(rx->len); -+ if (len) -+ break; -+ udelay(1); -+ } - flags = le16_to_cpu(rx->flags); - - do { -@@ -364,7 +371,7 @@ static int bgmac_dma_rx_read(struct bgma +@@ -363,6 +363,27 @@ static int bgmac_dma_rx_read(struct bgma + dma_addr_t old_dma_addr = slot->dma_addr; int err; ++ if (len > BGMAC_RX_MAX_FRAME_SIZE) { ++ struct bgmac_dma_desc *dma_desc = ring->cpu_base + ring->start; ++ ++ bgmac_err(bgmac, "Hardware reported invalid packet length %d for slot %d!\n", len, ring->start); ++ bgmac_err(bgmac, "flags: 0x%04X\n", flags); ++ bgmac_err(bgmac, "ctl0: 0x%08X\tctl1: 0x%08X\n", le32_to_cpu(dma_desc->ctl0), le32_to_cpu(dma_desc->ctl1)); ++ ++ bgmac_err(bgmac, " BGMAC_DMA_RX_CTL: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL)); ++ bgmac_err(bgmac, " BGMAC_DMA_RX_INDEX: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_RINGLO: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_RINGHI: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_STATUS: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS)); ++ bgmac_err(bgmac, " BGMAC_DMA_RX_ERROR: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_ERROR)); ++ ++ dma_sync_single_for_device(dma_dev, ++ slot->dma_addr, ++ BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ break; ++ } ++ /* Check for poison and drop or pass the packet */ -- if (len == 0xdead && flags == 0xbeef) { -+ if (!len || (len == 0xdead && flags == 0xbeef)) { + if (len == 0xdead && flags == 0xbeef) { bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", - ring->start); - dma_sync_single_for_device(dma_dev, diff --git a/target/linux/generic/patches-3.12/775-bgmac-check-length-of-received-frame.patch b/target/linux/generic/patches-3.12/775-bgmac-check-length-of-received-frame.patch new file mode 100644 index 0000000000..c3d63b65fa --- /dev/null +++ b/target/linux/generic/patches-3.12/775-bgmac-check-length-of-received-frame.patch @@ -0,0 +1,39 @@ +From 2d12a9abf3f81de5b51852e3cfcba8cedac82642 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens <hauke@hauke-m.de> +Date: Fri, 6 Dec 2013 01:14:52 +0100 +Subject: [PATCH] bgmac: check length of received frame + +--- + drivers/net/ethernet/broadcom/bgmac.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -363,6 +363,27 @@ static int bgmac_dma_rx_read(struct bgma + dma_addr_t old_dma_addr = slot->dma_addr; + int err; + ++ if (len > BGMAC_RX_MAX_FRAME_SIZE) { ++ struct bgmac_dma_desc *dma_desc = ring->cpu_base + ring->start; ++ ++ bgmac_err(bgmac, "Hardware reported invalid packet length %d for slot %d!\n", len, ring->start); ++ bgmac_err(bgmac, "flags: 0x%04X\n", flags); ++ bgmac_err(bgmac, "ctl0: 0x%08X\tctl1: 0x%08X\n", le32_to_cpu(dma_desc->ctl0), le32_to_cpu(dma_desc->ctl1)); ++ ++ bgmac_err(bgmac, " BGMAC_DMA_RX_CTL: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL)); ++ bgmac_err(bgmac, " BGMAC_DMA_RX_INDEX: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_RINGLO: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_RINGHI: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_STATUS: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS)); ++ bgmac_err(bgmac, " BGMAC_DMA_RX_ERROR: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_ERROR)); ++ ++ dma_sync_single_for_device(dma_dev, ++ slot->dma_addr, ++ BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ break; ++ } ++ + /* Check for poison and drop or pass the packet */ + if (len == 0xdead && flags == 0xbeef) { + bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", diff --git a/target/linux/generic/patches-3.13/775-bgmac-check-length-of-received-frame.patch b/target/linux/generic/patches-3.13/775-bgmac-check-length-of-received-frame.patch new file mode 100644 index 0000000000..c3d63b65fa --- /dev/null +++ b/target/linux/generic/patches-3.13/775-bgmac-check-length-of-received-frame.patch @@ -0,0 +1,39 @@ +From 2d12a9abf3f81de5b51852e3cfcba8cedac82642 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens <hauke@hauke-m.de> +Date: Fri, 6 Dec 2013 01:14:52 +0100 +Subject: [PATCH] bgmac: check length of received frame + +--- + drivers/net/ethernet/broadcom/bgmac.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -363,6 +363,27 @@ static int bgmac_dma_rx_read(struct bgma + dma_addr_t old_dma_addr = slot->dma_addr; + int err; + ++ if (len > BGMAC_RX_MAX_FRAME_SIZE) { ++ struct bgmac_dma_desc *dma_desc = ring->cpu_base + ring->start; ++ ++ bgmac_err(bgmac, "Hardware reported invalid packet length %d for slot %d!\n", len, ring->start); ++ bgmac_err(bgmac, "flags: 0x%04X\n", flags); ++ bgmac_err(bgmac, "ctl0: 0x%08X\tctl1: 0x%08X\n", le32_to_cpu(dma_desc->ctl0), le32_to_cpu(dma_desc->ctl1)); ++ ++ bgmac_err(bgmac, " BGMAC_DMA_RX_CTL: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL)); ++ bgmac_err(bgmac, " BGMAC_DMA_RX_INDEX: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_RINGLO: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_RINGHI: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_STATUS: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS)); ++ bgmac_err(bgmac, " BGMAC_DMA_RX_ERROR: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_ERROR)); ++ ++ dma_sync_single_for_device(dma_dev, ++ slot->dma_addr, ++ BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ break; ++ } ++ + /* Check for poison and drop or pass the packet */ + if (len == 0xdead && flags == 0xbeef) { + bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", diff --git a/target/linux/generic/patches-3.14/775-bgmac-check-length-of-received-frame.patch b/target/linux/generic/patches-3.14/775-bgmac-check-length-of-received-frame.patch new file mode 100644 index 0000000000..c3d63b65fa --- /dev/null +++ b/target/linux/generic/patches-3.14/775-bgmac-check-length-of-received-frame.patch @@ -0,0 +1,39 @@ +From 2d12a9abf3f81de5b51852e3cfcba8cedac82642 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens <hauke@hauke-m.de> +Date: Fri, 6 Dec 2013 01:14:52 +0100 +Subject: [PATCH] bgmac: check length of received frame + +--- + drivers/net/ethernet/broadcom/bgmac.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -363,6 +363,27 @@ static int bgmac_dma_rx_read(struct bgma + dma_addr_t old_dma_addr = slot->dma_addr; + int err; + ++ if (len > BGMAC_RX_MAX_FRAME_SIZE) { ++ struct bgmac_dma_desc *dma_desc = ring->cpu_base + ring->start; ++ ++ bgmac_err(bgmac, "Hardware reported invalid packet length %d for slot %d!\n", len, ring->start); ++ bgmac_err(bgmac, "flags: 0x%04X\n", flags); ++ bgmac_err(bgmac, "ctl0: 0x%08X\tctl1: 0x%08X\n", le32_to_cpu(dma_desc->ctl0), le32_to_cpu(dma_desc->ctl1)); ++ ++ bgmac_err(bgmac, " BGMAC_DMA_RX_CTL: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL)); ++ bgmac_err(bgmac, " BGMAC_DMA_RX_INDEX: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_RINGLO: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_RINGHI: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI)); ++ bgmac_err(bgmac, "BGMAC_DMA_RX_STATUS: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS)); ++ bgmac_err(bgmac, " BGMAC_DMA_RX_ERROR: 0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_ERROR)); ++ ++ dma_sync_single_for_device(dma_dev, ++ slot->dma_addr, ++ BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ break; ++ } ++ + /* Check for poison and drop or pass the packet */ + if (len == 0xdead && flags == 0xbeef) { + bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", |