b43: Add DMA poisoning patches
authorMichael Büsch <mb@bu3sch.de>
Mon, 6 Apr 2009 17:15:19 +0000 (17:15 +0000)
committerMichael Büsch <mb@bu3sch.de>
Mon, 6 Apr 2009 17:15:19 +0000 (17:15 +0000)
SVN-Revision: 15121

package/mac80211/patches/510-b43-poison-rx-buffers.patch [new file with mode: 0644]
package/mac80211/patches/511-b43-refresh-rx-poison-on-buffer-recycling.patch [new file with mode: 0644]
package/mac80211/patches/520-b43-autodepend-on-hwrandom.patch

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 (file)
index 0000000..c50df13
--- /dev/null
@@ -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 (file)
index 0000000..e72a61f
--- /dev/null
@@ -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)
index 9ffdadfd263aeac6918baa4eaa04f437efd57282..6cc8ea92124af2b4906d8ff443353a2c4e049727 100644 (file)
@@ -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