mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-19 13:48:06 +00:00
b43: Add DMA poisoning patches
SVN-Revision: 15121
This commit is contained in:
parent
3072d928f8
commit
cb70a62be3
105
package/mac80211/patches/510-b43-poison-rx-buffers.patch
Normal file
105
package/mac80211/patches/510-b43-poison-rx-buffers.patch
Normal file
@ -0,0 +1,105 @@
|
||||
This patch adds poisoning and sanity checking to the RX DMA buffers.
|
||||
This is used for protection against buggy hardware/firmware that raises
|
||||
RX interrupts without doing an actual DMA transfer.
|
||||
|
||||
This mechanism protects against rare "bad packets" (due to uninitialized skb data)
|
||||
and rare kernel crashes due to uninitialized RX headers.
|
||||
|
||||
The poison is selected to not match on valid frames and to be cheap for checking.
|
||||
|
||||
The poison check mechanism _might_ trigger incorrectly, if we are voluntarily
|
||||
receiving frames with bad PLCP headers. However, this is nonfatal, because the
|
||||
chance of such a match is basically zero and in case it happens it just results
|
||||
in dropping the packet.
|
||||
Bad-PLCP RX defaults to off, and you should leave it off unless you want to listen
|
||||
to the latest news broadcasted by your microwave oven.
|
||||
|
||||
This patch also moves the initialization of the RX-header "length" field in front of
|
||||
the mapping of the DMA buffer. The CPU should not touch the buffer after we mapped it.
|
||||
|
||||
Cc: stable@kernel.org
|
||||
Reported-by: Francesco Gringoli <francesco.gringoli@ing.unibs.it>
|
||||
Signed-off-by: Michael Buesch <mb@bu3sch.de>
|
||||
|
||||
---
|
||||
|
||||
Index: compat-wireless-2009-03-31/drivers/net/wireless/b43/dma.c
|
||||
===================================================================
|
||||
--- compat-wireless-2009-03-31.orig/drivers/net/wireless/b43/dma.c 2009-04-06 18:52:25.000000000 +0200
|
||||
+++ compat-wireless-2009-03-31/drivers/net/wireless/b43/dma.c 2009-04-06 18:52:30.000000000 +0200
|
||||
@@ -555,11 +555,32 @@ address_error:
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb)
|
||||
+{
|
||||
+ unsigned char *f = skb->data + ring->frameoffset;
|
||||
+
|
||||
+ return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7]) == 0xFF);
|
||||
+}
|
||||
+
|
||||
+static void b43_poison_rx_buffer(struct b43_dmaring *ring, struct sk_buff *skb)
|
||||
+{
|
||||
+ struct b43_rxhdr_fw4 *rxhdr;
|
||||
+ unsigned char *frame;
|
||||
+
|
||||
+ /* This poisons the RX buffer to detect DMA failures. */
|
||||
+
|
||||
+ rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
|
||||
+ rxhdr->frame_len = 0;
|
||||
+
|
||||
+ B43_WARN_ON(ring->rx_buffersize < ring->frameoffset + sizeof(struct b43_plcp_hdr6) + 2);
|
||||
+ frame = skb->data + ring->frameoffset;
|
||||
+ memset(frame, 0xFF, sizeof(struct b43_plcp_hdr6) + 2 /* padding */);
|
||||
+}
|
||||
+
|
||||
static int setup_rx_descbuffer(struct b43_dmaring *ring,
|
||||
struct b43_dmadesc_generic *desc,
|
||||
struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
|
||||
{
|
||||
- struct b43_rxhdr_fw4 *rxhdr;
|
||||
dma_addr_t dmaaddr;
|
||||
struct sk_buff *skb;
|
||||
|
||||
@@ -568,6 +589,7 @@ static int setup_rx_descbuffer(struct b4
|
||||
skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
|
||||
if (unlikely(!skb))
|
||||
return -ENOMEM;
|
||||
+ b43_poison_rx_buffer(ring, skb);
|
||||
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
|
||||
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
|
||||
/* ugh. try to realloc in zone_dma */
|
||||
@@ -578,6 +600,7 @@ static int setup_rx_descbuffer(struct b4
|
||||
skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
|
||||
if (unlikely(!skb))
|
||||
return -ENOMEM;
|
||||
+ b43_poison_rx_buffer(ring, skb);
|
||||
dmaaddr = map_descbuffer(ring, skb->data,
|
||||
ring->rx_buffersize, 0);
|
||||
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
|
||||
@@ -592,9 +615,6 @@ static int setup_rx_descbuffer(struct b4
|
||||
ring->ops->fill_descriptor(ring, desc, dmaaddr,
|
||||
ring->rx_buffersize, 0, 0, 0);
|
||||
|
||||
- rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
|
||||
- rxhdr->frame_len = 0;
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1489,6 +1509,15 @@ static void dma_rx(struct b43_dmaring *r
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
+ if (unlikely(b43_rx_buffer_is_poisoned(ring, skb))) {
|
||||
+ /* Something went wrong with the DMA.
|
||||
+ * The device did not touch the buffer and did not overwrite the poison. */
|
||||
+ b43dbg(ring->dev->wl, "DMA RX: Dropping poisoned buffer.\n");
|
||||
+ /* recycle the descriptor buffer. */
|
||||
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
|
||||
+ ring->rx_buffersize);
|
||||
+ goto drop;
|
||||
+ }
|
||||
if (unlikely(len > ring->rx_buffersize)) {
|
||||
/* The data did not fit into one descriptor buffer
|
||||
* and is split over multiple buffers.
|
@ -0,0 +1,68 @@
|
||||
The RX buffer poison needs to be refreshed, if we recycle an RX buffer,
|
||||
because it might be (partially) overwritten by some DMA operations.
|
||||
|
||||
Cc: stable@kernel.org
|
||||
Cc: Francesco Gringoli <francesco.gringoli@ing.unibs.it>
|
||||
Signed-off-by: Michael Buesch <mb@bu3sch.de>
|
||||
|
||||
---
|
||||
|
||||
Index: compat-wireless-2009-03-31/drivers/net/wireless/b43/dma.c
|
||||
===================================================================
|
||||
--- compat-wireless-2009-03-31.orig/drivers/net/wireless/b43/dma.c 2009-04-06 18:52:30.000000000 +0200
|
||||
+++ compat-wireless-2009-03-31/drivers/net/wireless/b43/dma.c 2009-04-06 18:53:04.000000000 +0200
|
||||
@@ -1503,20 +1503,16 @@ static void dma_rx(struct b43_dmaring *r
|
||||
len = le16_to_cpu(rxhdr->frame_len);
|
||||
} while (len == 0 && i++ < 5);
|
||||
if (unlikely(len == 0)) {
|
||||
- /* recycle the descriptor buffer. */
|
||||
- sync_descbuffer_for_device(ring, meta->dmaaddr,
|
||||
- ring->rx_buffersize);
|
||||
- goto drop;
|
||||
+ dmaaddr = meta->dmaaddr;
|
||||
+ goto drop_recycle_buffer;
|
||||
}
|
||||
}
|
||||
if (unlikely(b43_rx_buffer_is_poisoned(ring, skb))) {
|
||||
/* Something went wrong with the DMA.
|
||||
* The device did not touch the buffer and did not overwrite the poison. */
|
||||
b43dbg(ring->dev->wl, "DMA RX: Dropping poisoned buffer.\n");
|
||||
- /* recycle the descriptor buffer. */
|
||||
- sync_descbuffer_for_device(ring, meta->dmaaddr,
|
||||
- ring->rx_buffersize);
|
||||
- goto drop;
|
||||
+ dmaaddr = meta->dmaaddr;
|
||||
+ goto drop_recycle_buffer;
|
||||
}
|
||||
if (unlikely(len > ring->rx_buffersize)) {
|
||||
/* The data did not fit into one descriptor buffer
|
||||
@@ -1530,6 +1526,7 @@ static void dma_rx(struct b43_dmaring *r
|
||||
while (1) {
|
||||
desc = ops->idx2desc(ring, *slot, &meta);
|
||||
/* recycle the descriptor buffer. */
|
||||
+ b43_poison_rx_buffer(ring, meta->skb);
|
||||
sync_descbuffer_for_device(ring, meta->dmaaddr,
|
||||
ring->rx_buffersize);
|
||||
*slot = next_slot(ring, *slot);
|
||||
@@ -1548,8 +1545,7 @@ static void dma_rx(struct b43_dmaring *r
|
||||
err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
|
||||
if (unlikely(err)) {
|
||||
b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n");
|
||||
- sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
|
||||
- goto drop;
|
||||
+ goto drop_recycle_buffer;
|
||||
}
|
||||
|
||||
unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
|
||||
@@ -1559,6 +1555,11 @@ static void dma_rx(struct b43_dmaring *r
|
||||
b43_rx(ring->dev, skb, rxhdr);
|
||||
drop:
|
||||
return;
|
||||
+
|
||||
+drop_recycle_buffer:
|
||||
+ /* Poison and recycle the RX buffer. */
|
||||
+ b43_poison_rx_buffer(ring, skb);
|
||||
+ sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
|
||||
}
|
||||
|
||||
void b43_dma_rx(struct b43_dmaring *ring)
|
@ -4,9 +4,11 @@ This patch is submitted upstream and can be removed when it hits compat-wireless
|
||||
|
||||
|
||||
|
||||
--- a/drivers/net/wireless/b43/b43.h
|
||||
+++ b/drivers/net/wireless/b43/b43.h
|
||||
@@ -624,9 +624,11 @@ struct b43_wl {
|
||||
Index: compat-wireless-2009-03-31/drivers/net/wireless/b43/b43.h
|
||||
===================================================================
|
||||
--- compat-wireless-2009-03-31.orig/drivers/net/wireless/b43/b43.h 2009-04-06 18:52:21.000000000 +0200
|
||||
+++ compat-wireless-2009-03-31/drivers/net/wireless/b43/b43.h 2009-04-06 18:53:19.000000000 +0200
|
||||
@@ -625,9 +625,11 @@ struct b43_wl {
|
||||
/* Stats about the wireless interface */
|
||||
struct ieee80211_low_level_stats ieee_stats;
|
||||
|
||||
@ -19,8 +21,10 @@ This patch is submitted upstream and can be removed when it hits compat-wireless
|
||||
|
||||
/* The RF-kill button */
|
||||
struct b43_rfkill rfkill;
|
||||
--- a/drivers/net/wireless/b43/main.c
|
||||
+++ b/drivers/net/wireless/b43/main.c
|
||||
Index: compat-wireless-2009-03-31/drivers/net/wireless/b43/main.c
|
||||
===================================================================
|
||||
--- compat-wireless-2009-03-31.orig/drivers/net/wireless/b43/main.c 2009-04-06 18:52:28.000000000 +0200
|
||||
+++ compat-wireless-2009-03-31/drivers/net/wireless/b43/main.c 2009-04-06 18:53:19.000000000 +0200
|
||||
@@ -2982,6 +2982,7 @@ static void b43_security_init(struct b43
|
||||
b43_clear_keys(dev);
|
||||
}
|
||||
@ -60,8 +64,10 @@ This patch is submitted upstream and can be removed when it hits compat-wireless
|
||||
|
||||
return err;
|
||||
}
|
||||
--- a/config.mk
|
||||
+++ b/config.mk
|
||||
Index: compat-wireless-2009-03-31/config.mk
|
||||
===================================================================
|
||||
--- compat-wireless-2009-03-31.orig/config.mk 2009-04-06 18:52:21.000000000 +0200
|
||||
+++ compat-wireless-2009-03-31/config.mk 2009-04-06 18:53:19.000000000 +0200
|
||||
@@ -148,6 +148,7 @@ CONFIG_ATH9K_DEBUG=y
|
||||
# CONFIG_B43_PIO=y
|
||||
# CONFIG_B43_LEDS=y
|
||||
|
Loading…
Reference in New Issue
Block a user