diff options
3 files changed, 186 insertions, 7 deletions
| diff --git a/package/mac80211/patches/510-b43-poison-rx-buffers.patch b/package/mac80211/patches/510-b43-poison-rx-buffers.patch new file mode 100644 index 000000000..c50df132c --- /dev/null +++ b/package/mac80211/patches/510-b43-poison-rx-buffers.patch @@ -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. diff --git a/package/mac80211/patches/511-b43-refresh-rx-poison-on-buffer-recycling.patch b/package/mac80211/patches/511-b43-refresh-rx-poison-on-buffer-recycling.patch new file mode 100644 index 000000000..e72a61ff0 --- /dev/null +++ b/package/mac80211/patches/511-b43-refresh-rx-poison-on-buffer-recycling.patch @@ -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) diff --git a/package/mac80211/patches/520-b43-autodepend-on-hwrandom.patch b/package/mac80211/patches/520-b43-autodepend-on-hwrandom.patch index 9ffdadfd2..6cc8ea921 100644 --- a/package/mac80211/patches/520-b43-autodepend-on-hwrandom.patch +++ b/package/mac80211/patches/520-b43-autodepend-on-hwrandom.patch @@ -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 | 
